1 #using scripts\codescripts\struct;
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;
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;
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;
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;
41 #namespace zm_spawner;
45 level._CONTEXTUAL_GRAB_LERP_TIME = .3;
47 level.zombie_spawners = GetEntArray(
"zombie_spawner",
"script_noteworthy" );
51 level.a_zombie_respawn_health = [];
54 level.a_zombie_respawn_type = [];
56 if(
IS_TRUE(level.use_multiple_spawns))
58 level.zombie_spawn = [];
59 for ( i = 0; i < level.zombie_spawners.size; i++ )
61 if(IsDefined(level.zombie_spawners[i].script_int))
63 int = level.zombie_spawners[i].script_int;
64 if ( !IsDefined( level.zombie_spawn[
int] ))
66 level.zombie_spawn[int] = [];
68 level.zombie_spawn[int][level.zombie_spawn[int].size] = level.zombie_spawners[i];
73 if ( IsDefined( level.ignore_spawner_func ) )
75 for ( i = 0; i < level.zombie_spawners.size; i++ )
77 ignore = [[ level.ignore_spawner_func ]]( level.zombie_spawners[i] );
80 ArrayRemoveValue(level.zombie_spawners, level.zombie_spawners[i]);
85 if ( !IsDefined( level.attack_player_thru_boards_range ) )
87 level.attack_player_thru_boards_range = 109.8;
90 if(isdefined(level._game_module_custom_spawn_init_func))
92 [[level._game_module_custom_spawn_init_func]]();
96 function player_attacks_enemy( player, amount, type, point, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel )
99 if(isDefined(
self._race_team))
101 team =
self._race_team;
107 [[ level.global_damage_func ]]( type,
self.damagelocation, point, player, amount, team, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel );
114 [[ level.global_damage_func ]]( type,
self.damagelocation, point, player, amount, team, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel );
119 [[ level.global_damage_func_ads ]]( type,
self.damagelocation, point, player, amount, team, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel );
127 if ( IsPlayer(attacker) )
136 self endon (
"death");
140 self waittill(
"damage", amount, attacker, direction_vec, point, type, tagName, modelName, partName, weapon, dFlags, inflictor, chargeLevel );
142 if ( !isDefined(amount) )
147 if ( !isalive(
self ) )
157 self.has_been_damaged_by_player =
true;
159 self player_attacks_enemy( attacker, amount, type, point, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel );
166 if( IsDefined( ent.targetname ) )
168 targeters = GetEntArray( ent.targetname,
"target" );
170 for( i = 0; i < targeters.size; i++ )
172 if( targeters[i].targetname ==
"zombie_door" || targeters[i].targetname ==
"zombie_debris" )
190 if(!IsDefined(level._zombie_custom_spawn_logic))
192 level._zombie_custom_spawn_logic = [];
195 level._zombie_custom_spawn_logic[level._zombie_custom_spawn_logic.size] = func;
202 if( !isDefined( animname_set ) )
204 animname_set =
false;
207 self.targetname =
"zombie";
208 self.script_noteworthy = undefined;
215 self.animname =
"zombie";
226 self.zmb_vocals_attack =
"zmb_vocals_zombie_attack";
228 self.ignoreme =
false;
229 self.allowdeath =
true;
230 self.force_gib =
true;
231 self.is_zombie =
true;
232 self allowedStances(
"stand" );
235 self.attackerCountThreatScale = 0;
237 self.currentEnemyThreatScale = 0;
239 self.recentAttackerThreatScale = 0;
241 self.coverThreatScale = 0;
244 self.fovcosinebusy = 0;
246 self.zombie_damaged_by_bar_knockdown =
false;
249 self.head_gibbed =
false;
256 self setPhysParams( 15, 0, 72 );
257 self.goalradius = 32;
259 self.disableArrivals =
true;
260 self.disableExits =
true;
261 self.grenadeawareness = 0;
262 self.badplaceawareness = 0;
264 self.ignoreSuppression =
true;
265 self.suppressionThreshold = 1;
266 self.noDodgeMove =
true;
267 self.dontShootWhileMoving =
true;
268 self.pathenemylookahead = 0;
271 self.holdfire =
true;
273 self.badplaceawareness = 0;
274 self.chatInitialized =
false;
275 self.missingLegs =
false;
277 if ( !isdefined(
self.zombie_arms_position ) )
279 if(randomint( 2 ) == 0)
280 self.zombie_arms_position =
"up";
282 self.zombie_arms_position =
"down";
287 self.canStumble =
true;
290 self.a.disablepain =
true;
293 if ( isdefined( level.zombie_health ) )
295 self.maxhealth = level.zombie_health;
297 if( IsDefined(level.a_zombie_respawn_health[
self.archetype ] ) && level.a_zombie_respawn_health[
self.archetype ].size > 0 )
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]);
304 self.health = level.zombie_health;
309 self.maxhealth = level.zombie_vars[
"zombie_health_start"];
310 self.health =
self.maxhealth;
313 self.freezegun_damage = 0;
316 self setAvoidanceMask(
"avoid none" );
319 self PathMode(
"dont move" );
333 if(IsDefined(level._zombie_custom_spawn_logic))
335 if(IsArray(level._zombie_custom_spawn_logic))
337 for(i = 0; i < level._zombie_custom_spawn_logic.size; i ++)
339 self thread [[level._zombie_custom_spawn_logic[i]]]();
344 self thread [[level._zombie_custom_spawn_logic]]();
348 if ( !isdefined(
self.no_eye_glow ) || !
self.no_eye_glow )
356 self.flame_damage_time = 0;
358 self.meleeDamage = 60;
359 self.no_powerups =
true;
361 self zombie_history(
"zombie_spawn_init -> Spawned = " +
self.origin );
363 self.thundergun_knockdown_func = level.basic_zombie_thundergun_knockdown;
366 self.team = level.zombie_team;
369 self.updateSight =
false;
374 if ( isDefined(level.achievement_monitor_func) )
376 self [[level.achievement_monitor_func]]();
385 if ( isDefined( level.zombie_init_done ) )
387 self [[ level.zombie_init_done ]]();
389 self.zombie_init_done =
true;
391 self notify(
"zombie_init_done" );
396 self endon (
"death");
398 continue_failsafe_damage =
false;
404 if ( !isdefined(
self.enemy ) || !IsPlayer(
self.enemy ) )
409 if (
self istouching(
self.enemy))
411 old_org =
self.origin;
412 if (!continue_failsafe_damage)
418 if (!isdefined(
self.enemy) || !IsPlayer(
self.enemy ) ||
self.enemy hasperk(
PERK_JUGGERNOG ) )
424 if (
self istouching(
self.enemy)
426 && isalive(
self.enemy))
430 if (distancesquared(old_org,
self.origin) < (60 * 60) )
432 self.enemy DoDamage(
self.enemy.health + 1000,
self.enemy.origin,
self,
self,
"none",
"MOD_RIFLE_BULLET" );
434 continue_failsafe_damage =
true;
440 continue_failsafe_damage =
false;
449 if( IsDefined(find_flesh_struct_string) && find_flesh_struct_string ==
"find_flesh" )
454 if( isDefined(
self.script_string ) &&
self.script_string ==
"find_flesh" )
468 self.entrance_nodes = [];
470 if ( IsDefined( level.max_barrier_search_dist_override ) )
472 max_dist = level.max_barrier_search_dist_override;
479 if( !IsDefined(
self.find_flesh_struct_string) && IsDefined(
self.target ) &&
self.target !=
"" )
483 assert( IsDefined( desired_origin ),
"Spawner @ " +
self.origin +
" has a .target but did not find a target" );
485 origin = desired_origin;
487 node = ArrayGetClosest( origin, level.exterior_goals );
488 self.entrance_nodes[
self.entrance_nodes.size] = node;
490 self zombie_history(
"zombie_think -> #1 entrance (script_forcegoal) origin = " +
self.entrance_nodes[0].origin );
498 if (isDefined(
self.target))
500 end_at_node = GetNode(
self.target,
"targetname");
501 if (isDefined(end_at_node))
503 self setgoalnode (end_at_node);
504 self waittill(
"goal");
518 else if( IsDefined(
self.find_flesh_struct_string) )
520 for( i=0; i<level.exterior_goals.size; i++ )
522 if( IsDefined(level.exterior_goals[i].script_string) && level.exterior_goals[i].script_string ==
self.find_flesh_struct_string )
524 node = level.exterior_goals[i];
528 self.entrance_nodes[
self.entrance_nodes.size] = node;
530 self zombie_history(
"zombie_think -> #1 entrance origin = " + node.origin );
536 assert( IsDefined( node ),
"Did not find a node!!! [Should not see this!]" );
540 self.first_node = node;
547 self endon(
"death" );
548 assert( !
self.isdog );
550 self.ai_state =
"zombie_think";
556 find_flesh_struct_string = undefined;
558 if ( IsDefined(level.zombie_custom_think_logic) )
560 shouldWait =
self [[ level.zombie_custom_think_logic ]]();
563 self waittill(
"zombie_custom_think_done", find_flesh_struct_string);
566 else if (
IS_TRUE(
self.start_inert ) )
568 find_flesh_struct_string =
"find_flesh";
572 if ( isdefined(
self.custom_location ) )
574 self thread [[
self.custom_location ]]();
581 self waittill(
"risen", find_flesh_struct_string );
583 self.find_flesh_struct_string = find_flesh_struct_string;
588 self SetGoal(
self.origin );
589 self PathMode(
"move allowed" );
590 self.zombie_think_done =
true;
595 self endon(
"death" );
597 if ( !IsDefined( level.playable_areas ) )
599 level.playable_areas = GetEntArray(
"player_volume",
"script_noteworthy" );
604 foreach(area
in level.playable_areas)
606 if(
self IsTouching(area))
618 assert( !
self.isdog );
620 self endon(
"death" );
621 self endon(
"stop_zombie_goto_entrance" );
622 level endon(
"intermission" );
624 self.ai_state =
"zombie_goto_entrance";
626 if( IsDefined( endon_bad_path ) && endon_bad_path )
630 self endon(
"bad_path" );
635 self zombie_history(
"zombie_goto_entrance -> start goto entrance " + node.origin );
637 self.got_to_entrance =
false;
642 self.goalradius = 128;
643 self SetGoal( node.origin );
644 self waittill(
"goal" );
645 self.got_to_entrance =
true;
647 self zombie_history(
"zombie_goto_entrance -> reached goto entrance " + node.origin );
653 if( isDefined( level.pre_aggro_pathfinding_func ) )
655 self [[ level.pre_aggro_pathfinding_func ]]();
659 barrier_pos[0] =
"m";
660 barrier_pos[1] =
"r";
661 barrier_pos[2] =
"l";
663 self.barricade_enter =
true;
667 self AnimScripted(
"barricade_enter_anim",
self.first_node.zbarrier.origin,
self.first_node.zbarrier.angles,
"ai_zombie_barricade_enter_m_v1" );
676 self.barricade_enter =
false;
683 self endon(
"death" );
684 self endon(
"goal" );
685 level endon(
"intermission" );
687 start_pos =
self.origin;
688 if(IsDefined(
self.entrance_nodes))
690 for( i = 0; i <
self.entrance_nodes.size; i++ )
694 self zombie_history(
"zombie_assure_node -> assigned assured node = " +
self.entrance_nodes[i].origin );
698 self.first_node =
self.entrance_nodes[i];
699 self SetGoal(
self.entrance_nodes[i].origin );
709 nodes = array::get_all_closest(
self.origin, level.exterior_goals, undefined, 20 );
714 self.entrance_nodes = nodes;
715 for( i = 0; i <
self.entrance_nodes.size; i++ )
719 self zombie_history(
"zombie_assure_node -> assigned assured node = " +
self.entrance_nodes[i].origin );
723 self.first_node =
self.entrance_nodes[i];
724 self SetGoal(
self.entrance_nodes[i].origin );
733 self zombie_history(
"zombie_assure_node -> failed to find a good entrance point" );
740 self DoDamage(
self.health + 10,
self.origin );
743 if(
IS_TRUE(level.put_timed_out_zombies_back_in_queue ) && !
IS_TRUE(
self.has_been_damaged_by_player))
745 level.zombie_total++;
746 level.zombie_total_subtract++;
750 level.zombies_timeout_spawn++;
756 self endon(
"death" );
757 self endon(
"goal" );
762 self.zombie_bad_path = undefined;
768 self notify(
"stop_zombie_bad_path" );
770 return self.zombie_bad_path;
775 self endon(
"death" );
776 self endon(
"stop_zombie_bad_path" );
778 self waittill(
"bad_path" );
781 self.zombie_bad_path =
true;
786 self endon(
"death" );
787 self endon(
"stop_zombie_bad_path" );
790 self.zombie_bad_path =
false;
799 self endon(
"death" );
800 self endon(
"teleporting");
809 if( IsDefined(
self.first_node.script_noteworthy ) )
811 if(
self.first_node.script_noteworthy ==
"no_blocker" )
817 if( !IsDefined(
self.first_node.target ) )
835 self zombie_history(
"tear_into_building -> Could not find an attack spot" );
847 self.at_entrance_tear_spot =
false;
848 if ( isdefined( level.tear_into_position ) )
850 self [[ level.tear_into_position ]]();
854 angles =
self.first_node.zbarrier.angles;
856 self SetGoal(
self.attacking_spot );
858 self waittill(
"goal" );
859 self.at_entrance_tear_spot =
true;
863 if ( isdefined( level.tear_into_wait ) )
865 self [[ level.tear_into_wait ]]();
872 self zombie_history(
"tear_into_building -> Reach position and orientated" );
879 for( i = 0; i <
self.first_node.attack_spots_taken.size; i++ )
881 self.first_node.attack_spots_taken[i] =
false;
890 if ( isDefined(
self.zombie_board_tear_down_callback ) )
892 self [[
self.zombie_board_tear_down_callback]]();
898 if ( !IsDefined(
self.chunk ) )
903 if(isDefined(attack) && !attack && !
self.missingLegs)
915 for( i = 0; i <
self.first_node.attack_spots_taken.size; i++ )
917 self.first_node.attack_spots_taken[i] =
false;
924 self.first_node.zbarrier SetZBarrierPieceState(
self.chunk,
"targetted_by_zombie");
928 self notify(
"bhtn_action_notify",
"teardown" );
945 self AnimScripted(
"tear_anim",
self.first_node.zbarrier.origin,
self.first_node.zbarrier.angles,
"ai_zombie_boardtear_aligned_m_1_grab" );
950 while(0 <
self.first_node.zbarrier.chunk_health[
self.chunk])
953 self AnimScripted(
"tear_anim",
self.first_node.zbarrier.origin,
self.first_node.zbarrier.angles,
"ai_zombie_boardtear_aligned_m_1_hold" );
955 self.first_node.zbarrier.chunk_health[
self.chunk]--;
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");
963 self.lastchunk_destroy_time = GetTime();
966 if ( isDefined( attack ) && !attack && !
self.missingLegs )
974 for( i = 0; i <
self.first_node.attack_spots_taken.size; i++ )
976 self.first_node.attack_spots_taken[i] =
false;
979 level notify(
"last_board_torn",
self.first_node.zbarrier.origin );
996 self endon (
"death");
997 if(
self.missingLegs )
1002 if(!
self.first_node.zbarrier ZBarrierSupportsZombieTaunts())
1007 self.old_origin =
self.origin;
1008 if(GetDvarString(
"zombie_taunt_freq") ==
"")
1010 SetDvar(
"zombie_taunt_freq",
"5");
1012 freq = GetDvarInt(
"zombie_taunt_freq");
1014 if( freq >= randomint(100) )
1016 self notify(
"bhtn_action_notify",
"taunt" );
1018 tauntState =
"zm_taunt";
1020 if(isdefined(
self.first_node.zbarrier) &&
self.first_node.zbarrier GetZBarrierTauntAnimState() !=
"")
1022 tauntState =
self.first_node.zbarrier GetZBarrierTauntAnimState();
1026 self animscripted(
"taunt_anim",
self.origin,
self.angles,
"ai_zombie_taunts_4" );
1033 self endon(
"death");
1037 self waittill( msg, notetrack );
1039 if( notetrack ==
"end" )
1041 self ForceTeleport(
self.old_origin);
1057 if(
self.missingLegs )
1062 if(isdefined(
self.first_node.zbarrier))
1064 if(!
self.first_node.zbarrier ZBarrierSupportsZombieReachThroughAttacks())
1070 if(GetDvarString(
"zombie_reachin_freq") ==
"")
1072 SetDvar(
"zombie_reachin_freq",
"50");
1074 freq = GetDvarInt(
"zombie_reachin_freq");
1076 players = GetPlayers();
1079 self.player_targets = [];
1080 for(i=0;i<players.size;i++)
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" ] ) )
1084 self.player_targets[
self.player_targets.size] = players[i];
1089 if ( !attack || freq < randomint(100) )
1094 self.old_origin =
self.origin;
1096 attackAnimState =
"zm_window_melee";
1098 if(isdefined(
self.first_node.zbarrier) &&
self.first_node.zbarrier GetZBarrierReachThroughAttackAnimState() !=
"")
1100 attackAnimState =
self.first_node.zbarrier GetZBarrierReachThroughAttackAnimState();
1104 self notify(
"bhtn_action_notify",
"attack" );
1106 self AnimScripted(
"window_melee_anim",
self.origin,
self.angles,
"ai_zombie_window_attack_arm_l_out" );
1114 self endon(
"death");
1118 self waittill( msg, notetrack );
1120 if( notetrack ==
"end" )
1127 if( notetrack ==
"fire" )
1131 self.ignoreall =
false;
1135 if ( isDefined(
self.first_node ) )
1137 _MELEE_DIST_SQ = 90*90;
1139 if ( IsDefined( level.attack_player_thru_boards_range ) )
1141 _MELEE_DIST_SQ = level.attack_player_thru_boards_range * level.attack_player_thru_boards_range;
1144 _TRIGGER_DIST_SQ = 51*51;
1146 for ( i = 0; i <
self.player_targets.size; i++ )
1148 playerDistSq = Distance2DSquared(
self.player_targets[i].origin,
self.origin );
1149 heightDiff = abs(
self.player_targets[i].origin[2] -
self.origin[2] );
1150 if ( playerDistSq < _MELEE_DIST_SQ && (heightDiff * heightDiff) < _MELEE_DIST_SQ )
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] );
1154 if ( triggerDistSq < _TRIGGER_DIST_SQ && (heightDiff * heightDiff) < _TRIGGER_DIST_SQ )
1156 self.player_targets[i] DoDamage(
self.meleeDamage,
self.origin,
self,
self,
"none",
"MOD_MELEE" );
1173 if( !IsDefined( index ) )
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];
1190 for( i = 0; i < node.attack_spots.size; i++ )
1192 if( !node.attack_spots_taken[i] )
1194 indexes[indexes.size] = i;
1198 if( indexes.size == 0 )
1203 return indexes[RandomInt( indexes.size )];
1209 self endon(
"death");
1213 self waittill( msg, notetrack );
1215 if ( notetrack ==
"end" )
1220 if ( notetrack ==
"board" || notetrack ==
"destroy_piece" || notetrack ==
"bar")
1222 if( isdefined( level.zbarrier_zombie_tear_notetrack_override ) )
1224 self thread [[ level.zbarrier_zombie_tear_notetrack_override ]]( node, chunk );
1226 node.zbarrier SetZBarrierPieceState(chunk,
"opening");
1238 if ( IsDefined( chunk.script_parameters ) && ( chunk.script_parameters ==
"repair_board" || chunk.script_parameters ==
"board") )
1240 if(IsDefined(chunk.unbroken) && chunk.unbroken ==
true)
1242 if(IsDefined(chunk.material) && chunk.material ==
"glass")
1244 PlayFX( level._effect[
"glass_break"], chunk.origin, node.angles );
1245 chunk.unbroken =
false;
1247 else if(IsDefined(chunk.material) && chunk.material ==
"metal")
1249 PlayFX( level._effect[
"fx_zombie_bar_break"], chunk.origin );
1250 chunk.unbroken =
false;
1252 else if(IsDefined(chunk.material) && chunk.material ==
"rock")
1254 if(
IS_TRUE(level.use_clientside_rock_tearin_fx))
1260 PlayFX( level._effect[
"wall_break"], chunk.origin );
1262 chunk.unbroken =
false;
1266 if ( IsDefined( chunk.script_parameters ) && ( chunk.script_parameters ==
"barricade_vents" ) )
1268 if(
IS_TRUE(level.use_clientside_board_fx))
1274 PlayFX( level._effect[
"fx_zombie_bar_break"], chunk.origin );
1277 else if(IsDefined(chunk.material) && chunk.material ==
"rock")
1279 if(
IS_TRUE(level.use_clientside_rock_tearin_fx))
1287 if(isDefined(level.use_clientside_board_fx))
1294 wait( randomfloatrange( 0.2, 0.4 ));
1303 if ( IsDefined( chunk.script_parameters ) && ( chunk.script_parameters ==
"repair_board" || chunk.script_parameters ==
"board") )
1305 if(IsDefined(chunk.unbroken) && chunk.unbroken ==
true)
1307 if(IsDefined(chunk.material) && chunk.material ==
"glass")
1309 PlayFX( level._effect[
"glass_break"], chunk.origin, node.angles );
1310 chunk.unbroken =
false;
1312 else if(IsDefined(chunk.material) && chunk.material ==
"metal")
1314 PlayFX( level._effect[
"fx_zombie_bar_break"], chunk.origin );
1315 chunk.unbroken =
false;
1317 else if(IsDefined(chunk.material) && chunk.material ==
"rock")
1319 if(
IS_TRUE(level.use_clientside_rock_tearin_fx))
1325 PlayFX( level._effect[
"wall_break"], chunk.origin );
1327 chunk.unbroken =
false;
1331 if ( IsDefined( chunk.script_parameters ) && ( chunk.script_parameters ==
"barricade_vents" ) )
1333 if(isDefined(level.use_clientside_board_fx))
1339 PlayFX( level._effect[
"fx_zombie_bar_break"], chunk.origin );
1342 else if(IsDefined(chunk.material) && chunk.material ==
"rock")
1344 if(
IS_TRUE(level.use_clientside_rock_tearin_fx))
1351 if(isDefined(level.use_clientside_board_fx))
1358 wait( randomfloatrange( 0.2, 0.4 ));
1367 if ( IsDefined ( chunk.script_parameters ) && ( chunk.script_parameters ==
"bar" ) || ( chunk.script_noteworthy ==
"board" ))
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] =
"";
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";
1383 possible_tag_array_2 = array::randomize( possible_tag_array_2 );
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"];
1391 random_fx = array::randomize( random_fx );
1393 switch( randomInt( 9 ) )
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" );
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" );
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" );
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" );
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" );
1426 PlayFXOnTag( level._effect[
"fx_zombie_bar_break_lite"], chunk,
"Tag_fx_top" );
1429 PlayFXOnTag( level._effect[
"fx_zombie_bar_break_lite"], chunk,
"Tag_fx_bottom" );
1432 PlayFXOnTag( level._effect[
"fx_zombie_bar_break"], chunk,
"Tag_fx_top" );
1435 PlayFXOnTag( level._effect[
"fx_zombie_bar_break"], chunk,
"Tag_fx_bottom" );
1444 if ( IsDefined ( chunk.script_parameters ) && ( chunk.script_parameters ==
"bar" ) || ( chunk.script_noteworthy ==
"board" ))
1446 switch( randomInt( 10 ) )
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" );
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" );
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" );
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" );
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" );
1479 PlayFXOnTag( level._effect[
"fx_zombie_bar_break_lite"], chunk,
"Tag_fx_left" );
1482 PlayFXOnTag( level._effect[
"fx_zombie_bar_break_lite"], chunk,
"Tag_fx_right" );
1485 PlayFXOnTag( level._effect[
"fx_zombie_bar_break"], chunk,
"Tag_fx_right" );
1488 PlayFXOnTag( level._effect[
"fx_zombie_bar_break"], chunk,
"Tag_fx_right" );
1496 zombie endon(
"completed_emerging_into_playable_area" );
1498 zombie waittill(
"stop_zombie_goto_entrance" );
1500 if ( zbarrier GetZBarrierPieceState(chunk_index) ==
"targetted_by_zombie" )
1502 zbarrier SetZBarrierPieceState(chunk_index,
"closed");
1510 if(zbarrier GetZBarrierPieceState(chunk_index) !=
"targetted_by_zombie")
1515 if(!isdefined(zombie) || !IsAlive(zombie))
1517 zbarrier SetZBarrierPieceState(chunk_index,
"closed");
1527 self endon(
"destroyed");
1536 if ( IsDefined(
self) &&
IS_TRUE(
self.inhibit_scoring_from_zombies) )
1552 if ( isdefined(zombie.no_powerups) && zombie.no_powerups )
1562 if (
IS_TRUE( level.use_powerup_volumes ) )
1564 volumes = GetEntArray(
"no_powerups",
"targetname" );
1565 foreach( volume
in volumes )
1567 if ( zombie IsTouching( volume ) )
1587 if( !IsDefined( attacker ) || !IsPlayer( attacker ) )
1594 zombie.marked_for_recycle = 1;
1601 if(IsDefined(zombie.in_the_ground) && zombie.in_the_ground ==
true)
1603 trace = BulletTrace(zombie.origin + (0, 0, 100), zombie.origin + (0, 0, -100),
false, undefined);
1604 origin =
trace[
"position"];
1609 trace = GroundTrace(zombie.origin + (0, 0, 5), zombie.origin + (0, 0, -300),
false, undefined);
1610 origin =
trace[
"position"];
1619 if ( zombie.damageweapon.isBallisticKnife && (mod ==
"MOD_MELEE" || mod ==
"MOD_IMPACT") )
1621 event =
"ballistic_knife_death";
1624 if(
IS_TRUE(zombie.deathpoints_already_given))
1629 zombie.deathpoints_already_given =
true;
1634 death_weapon = attacker.currentweapon;
1635 if ( IsDefined( zombie.damageweapon ) )
1637 death_weapon = zombie.damageweapon;
1640 if ( IsDefined(attacker) )
1645 if( isdefined(level.hero_power_update))
1647 level thread [[level.hero_power_update]](attacker, zombie);
1653 for(i=0; i<100; i++)
1655 if( !SoundExists( aliasPrefix +
"_" + i) )
1671 if( !IsDefined( level._effect ) || !IsDefined( level._effect[
"character_fire_death_sm"] ) )
1676 PlayFxOnTag( level._effect[
"character_fire_death_sm"],
self,
"J_SpineLower" );
1679 if( !IsDefined(
self.
a.gib_ref ) ||
self.a.gib_ref !=
"left_arm" )
1681 tagArray[tagArray.size] =
"J_Elbow_LE";
1682 tagArray[tagArray.size] =
"J_Wrist_LE";
1684 if( !IsDefined(
self.
a.gib_ref ) ||
self.a.gib_ref !=
"right_arm" )
1686 tagArray[tagArray.size] =
"J_Elbow_RI";
1687 tagArray[tagArray.size] =
"J_Wrist_RI";
1689 if( !IsDefined(
self.
a.gib_ref ) || (
self.a.gib_ref !=
"no_legs" &&
self.a.gib_ref !=
"left_leg") )
1691 tagArray[tagArray.size] =
"J_Knee_LE";
1692 tagArray[tagArray.size] =
"J_Ankle_LE";
1694 if( !IsDefined(
self.
a.gib_ref ) || (
self.a.gib_ref !=
"no_legs" &&
self.a.gib_ref !=
"right_leg") )
1696 tagArray[tagArray.size] =
"J_Knee_RI";
1697 tagArray[tagArray.size] =
"J_Ankle_RI";
1700 tagArray = array::randomize( tagArray );
1701 PlayFxOnTag( level._effect[
"character_fire_death_sm"],
self, tagArray[0] );
1706 if (!isdefined(
self))
1711 self notify(
"exploding" );
1712 self notify(
"end_melee" );
1713 self notify(
"death", attacker );
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);
1725 if (isdefined(launchvector))
1726 self LaunchRagdoll( launchvector );
1729 if (isdefined(
self))
1746 if(isDefined(
self._race_team))
1748 team =
self._race_team;
1759 if( IsDefined( level.zombie_death_animscript_override ) )
1761 self [ [ level.zombie_death_animscript_override ] ] ();
1764 self.grenadeAmmo = 0;
1767 if ( IsDefined(
self.nuked ) )
1772 if(IsDefined(
self.in_the_ground) &&
self.in_the_ground ==
true)
1774 trace = BulletTrace(
self.origin + (0, 0, 100),
self.origin + (0, 0, -100),
false, undefined);
1775 origin =
trace[
"position"];
1780 trace = GroundTrace(
self.origin + (0, 0, 5),
self.origin + (0, 0, -300),
false, undefined);
1781 origin =
trace[
"position"];
1790 level
zombie_death_points(
self.origin,
self.damagemod,
self.damagelocation,
self.attacker,
self ,team);
1794 if( isdefined(
self.attacker ) && isai(
self.attacker ) )
1796 self.attacker notify(
"killed",
self );
1800 if(
"rottweil72_upgraded" ==
self.damageweapon.name &&
"MOD_RIFLE_BULLET" ==
self.damagemod )
1804 if(
"tazer_knuckles" ==
self.damageweapon.name &&
"MOD_MELEE" ==
self.damagemod )
1806 self.is_on_fire =
false;
1807 self notify(
"stop_flame_damage");
1809 if(
self.damagemod ==
"MOD_BURNED" )
1813 if(
self.damagemod ==
"MOD_GRENADE" ||
self.damagemod ==
"MOD_GRENADE_SPLASH" )
1815 level notify(
"zombie_grenade_death",
self.origin );
1824 if ( !isdefined( level.zombie_death_animscript_callbacks ) )
1829 for ( i = 0; i < level.zombie_death_animscript_callbacks.size; i++ )
1831 if (
self [[ level.zombie_death_animscript_callbacks[i] ]]() )
1843 if ( !isdefined( level.zombie_death_animscript_callbacks ) )
1845 level.zombie_death_animscript_callbacks = [];
1848 level.zombie_death_animscript_callbacks[level.zombie_death_animscript_callbacks.size] = func;
1854 self endon (
"death");
1855 self endon (
"stop_flame_damage");
1858 while( isdefined(
self.is_on_fire) &&
self.is_on_fire )
1860 if( level.round_number < 6 )
1862 dmg = level.zombie_health * RandomFloatRange( 0.2, 0.3 );
1864 else if( level.round_number < 9 )
1866 dmg = level.zombie_health * RandomFloatRange( 0.15, 0.25 );
1868 else if( level.round_number < 11 )
1870 dmg = level.zombie_health * RandomFloatRange( 0.1, 0.2 );
1874 dmg = level.zombie_health * RandomFloatRange( 0.1, 0.15 );
1877 if ( Isdefined( player ) && Isalive( player ) )
1879 self DoDamage( dmg,
self.origin, player );
1883 self DoDamage( dmg,
self.origin, level );
1886 wait( randomfloatrange( 1.0, 3.0 ) );
1892 if( IsPlayer( player) )
1894 weapon = player GetCurrentWeapon();
1896 return (weapon == level.weaponNone || weapon.isSemiAuto);
1902 function zombie_damage( mod, hit_location, hit_origin, player, amount, team, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel )
1910 player.use_weapon_type = mod;
1911 if(isDefined(
self.marked_for_death))
1916 if( !IsDefined( player ) )
1921 if (isdefined(hit_origin))
1922 self.damagehit_origin = hit_origin;
1924 self.damagehit_origin = player GetWeaponMuzzlePoint();
1926 if (
self check_zombie_damage_callbacks( mod, hit_location, hit_origin, player, amount, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel ) )
1934 else if ( IsDefined(weapon) && weapon.isriotshield )
1948 damage_type =
"damage";
1952 damage_type =
"damage_light";
1955 if ( !
IS_TRUE(
self.no_damage_points ) )
1961 if ( IsDefined(
self.zombie_damage_fx_func ) )
1963 self [[
self.zombie_damage_fx_func ]]( mod, hit_location, hit_origin, player, direction_vec );
1968 if ( IsDefined(
self.zombie_damage_claymore_func ) )
1970 self [[
self.zombie_damage_claymore_func ]]( mod, hit_location, hit_origin, player );
1972 else if ( isdefined( player ) && isalive( player ) )
1974 self DoDamage( level.round_number * randomintrange( 100, 200 ),
self.origin, player,
self, hit_location, mod, 0, weapon );
1978 self DoDamage( level.round_number * randomintrange( 100, 200 ),
self.origin, undefined,
self, hit_location, mod, 0, weapon );
1981 else if ( mod ==
"MOD_GRENADE" || mod ==
"MOD_GRENADE_SPLASH" )
1983 if ( isdefined( player ) && isalive( player ) )
1985 player.grenade_multiattack_count++;
1986 player.grenade_multiattack_ent =
self;
1988 self DoDamage( level.round_number + randomintrange( 100, 200 ),
self.origin, player,
self, hit_location, mod, 0, weapon );
1992 self DoDamage( level.round_number + randomintrange( 100, 200 ),
self.origin, undefined,
self, hit_location, mod, 0, weapon );
1995 else if( mod ==
"MOD_PROJECTILE" || mod ==
"MOD_EXPLOSIVE" || mod ==
"MOD_PROJECTILE_SPLASH" )
1997 if ( isdefined( player ) && isalive( player ) )
1999 self DoDamage( level.round_number * randomintrange( 0, 100 ),
self.origin, player,
self, hit_location, mod, 0, weapon );
2003 self DoDamage( level.round_number * randomintrange( 0, 100 ),
self.origin, undefined,
self, hit_location, mod, 0, weapon );
2010 if(
IS_TRUE(
self.missinglegs ) && isalive(
self) )
2012 if ( isdefined( player ) )
2017 else if( IsDefined(
self.
a.gib_ref ) && ( (
self.a.gib_ref ==
"right_arm") || (
self.a.gib_ref ==
"left_arm") ) )
2019 if( !
self.missingLegs && isalive(
self ) )
2021 if ( isdefined( player ) )
2023 rand = randomintrange(0, 100);
2035 function zombie_damage_ads( mod, hit_location, hit_origin, player, amount, team, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel )
2043 player.use_weapon_type = mod;
2044 if( !IsDefined( player ) )
2049 if (isdefined(hit_origin))
2050 self.damagehit_origin = hit_origin;
2052 self.damagehit_origin = player GetWeaponMuzzlePoint();
2055 if (
self check_zombie_damage_callbacks( mod, hit_location, hit_origin, player, amount, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel ) )
2073 damage_type =
"damage";
2077 damage_type =
"damage_light";
2080 if ( !
IS_TRUE(
self.no_damage_points ) )
2086 if ( IsDefined(
self.zombie_damage_fx_func ) )
2088 self [[
self.zombie_damage_fx_func ]]( mod, hit_location, hit_origin, player, direction_vec );
2095 function check_zombie_damage_callbacks( mod, hit_location, hit_origin, player, amount, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel )
2097 if ( !isdefined( level.zombie_damage_callbacks ) )
2102 for ( i = 0; i < level.zombie_damage_callbacks.size; i++ )
2104 if (
self [[ level.zombie_damage_callbacks[i] ]]( mod, hit_location, hit_origin, player, amount, weapon, direction_vec, tagName, modelName, partName, dFlags, inflictor, chargeLevel ) )
2116 if ( !isdefined( level.zombie_damage_callbacks ) )
2118 level.zombie_damage_callbacks = [];
2121 level.zombie_damage_callbacks[level.zombie_damage_callbacks.size] = func;
2126 if( !isDefined(
self.flame_damage_time ) || GetTime() >
self.flame_damage_time )
2128 self.flame_damage_time = GetTime() + level.zombie_vars[
"zombie_flame_dmg_point_delay"];
2137 if( mod ==
"MOD_BURNED" )
2139 if( !IsDefined(
self.is_on_fire ) || ( Isdefined(
self.is_on_fire ) && !
self.is_on_fire ) )
2144 do_flame_death =
true;
2146 ai = GetAiTeamArray( level.zombie_team );
2147 for( i = 0; i < ai.size; i++ )
2149 if( IsDefined( ai[i].is_on_fire ) && ai[i].is_on_fire )
2151 if( DistanceSquared( ai[i].origin,
self.origin ) < dist )
2153 do_flame_death =
false;
2159 if( do_flame_death )
2172 return (weapon.weapClass ==
"spread");
2177 if ( isdefined(
self) && IsActor(
self) )
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 );
2197 zombie.marked_for_recycle = 0;
2202 zombie waittill(
"death", attacker);
2203 time_of_death = gettime();
2205 if(isDefined(zombie))
2207 zombie StopSounds();
2211 if( IsDefined(zombie) && IsDefined(zombie.marked_for_insta_upgraded_death) )
2216 if ( IsDefined(zombie) && !isdefined( zombie.damagehit_origin ) && isdefined( attacker ) && IsAlive( attacker ) && !IsVehicle( attacker ) )
2218 zombie.damagehit_origin = attacker GetWeaponMuzzlePoint();
2225 if( isdefined(zombie.script_parameters) )
2227 attacker notify(
"zombie_death_params", zombie.script_parameters,
IS_TRUE(zombie.completed_emerging_into_playable_area) );
2231 if( isdefined(zombie.b_widows_wine_cocoon) && isdefined(zombie.e_widows_wine_player) )
2233 attacker notify(
"widows_wine_kill", zombie.e_widows_wine_player );
2237 if(
IS_TRUE(level.pers_upgrade_carpenter) )
2243 if(
IS_TRUE(level.pers_upgrade_sniper) )
2248 if(isDefined(zombie) && isDefined(zombie.damagelocation) )
2252 attacker.headshots++;
2254 attacker AddWeaponStat(zombie.damageWeapon,
"headshots", 1);
2267 attacker notify(
"zombie_death_no_headshot");
2271 if(isDefined(zombie) && isDefined(zombie.damagemod) && zombie.damagemod ==
"MOD_MELEE")
2275 attacker notify(
"melee_kill" );
2291 if (
IS_TRUE(level.pers_upgrade_pistol_points) )
2296 if ( isDefined( zombie ) && isDefined( zombie.damageweapon ) )
2298 attacker AddWeaponStat(zombie.damageWeapon,
"kills", 1);
2307 if ( isDefined( zombie ) &&
IS_TRUE( zombie.missingLegs ) )
2320 if(
IS_TRUE(level.pers_upgrade_nube) )
2322 attacker notify(
"pers_player_zombie_kill" );
2330 if ( !IsDefined( zombie ) )
2336 level.global_zombies_killed++;
2339 if(isDefined(zombie.marked_for_death) && !isDefined(zombie.nuked))
2341 level.zombie_trap_killed_count++;
2348 if ( !IsDefined( zombie ) )
2353 name = zombie.animname;
2354 if( isdefined( zombie.sndname ) )
2356 name = zombie.sndname;
2359 self notify(
"bhtn_action_notify",
"death" );
2362 if( IsActor( zombie ) )
2364 if(
IS_TRUE(zombie.damageweapon.doannihilate) )
2372 ( (zombie.damagemod ===
"MOD_GRENADE") || (zombie.damagemod ===
"MOD_GRENADE_SPLASH") || (zombie.damagemod ===
"MOD_EXPLOSIVE") || (force_explode == 1) ) )
2374 splode_dist = 12 * 15;
2375 if ( isdefined(zombie.damagehit_origin) && distancesquared(zombie.origin,zombie.damagehit_origin) < splode_dist * splode_dist )
2377 tag =
"J_SpineLower";
2397 if ( isdefined(attacker) && IsPlayer( attacker ) && !
is_weapon_shotgun( zombie.damageweapon ) )
2404 if ( zombie.damagemod ===
"MOD_GRENADE" || zombie.damagemod ===
"MOD_GRENADE_SPLASH" )
2406 if ( isdefined( attacker ) && isalive( attacker ) &&isPlayer( attacker ) )
2408 attacker.grenade_multiattack_count++;
2409 attacker.grenade_multiattack_ent = zombie;
2410 attacker.grenade_multikill_count++;
2416 if ( !
IS_TRUE(zombie.has_been_damaged_by_player) &&
IS_TRUE(zombie.marked_for_recycle))
2418 level.zombie_total++;
2419 level.zombie_total_subtract++;
2421 else if(isdefined (zombie.attacker) && isplayer(zombie.attacker) )
2425 level.zombie_player_killed_count++;
2427 if ( IsDefined( zombie.sound_damage_player ) && zombie.sound_damage_player == zombie.attacker )
2432 zombie.attacker notify(
"zom_kill", zombie );
2436 if(zombie.ignoreall && !
IS_TRUE(zombie.marked_for_death) )
2438 level.zombies_timeout_spawn++;
2442 level notify(
"zom_kill" );
2443 level.total_zombies_killed++;
2451 if ( !isdefined( level.zombie_death_event_callbacks ) )
2456 for ( i = 0; i < level.zombie_death_event_callbacks.size; i++ )
2458 self [[ level.zombie_death_event_callbacks[i] ]]( attacker );
2465 if ( !isdefined( level.zombie_death_event_callbacks ) )
2467 level.zombie_death_event_callbacks = [];
2470 level.zombie_death_event_callbacks[level.zombie_death_event_callbacks.size] = func;
2475 if (isdefined( level.zombie_death_event_callbacks ) )
2477 ArrayRemoveValue(level.zombie_death_event_callbacks,func);
2488 self.ignoreall =
false;
2494 self.meleeAttackDist = 64;
2497 self.maxsightdistsqrd = 128 * 128;
2500 self.disableArrivals =
true;
2501 self.disableExits =
true;
2508 self endon(
"death" );
2509 level endon(
"intermission" );
2510 self endon(
"stop_find_flesh" );
2511 self endon(
"path_timer_done" );
2513 level waittill(
"attractor_positions_generated" );
2514 self.zombie_path_timer = 0;
2520 self endon(
"death" );
2521 self endon(
"zombie_acquire_enemy" );
2522 level endon(
"intermission" );
2524 assert( IsDefined(
self.favoriteenemy ) || IsDefined(
self.enemyoverride ) );
2526 self._skip_pathing_first_delay =
true;
2528 self waittill(
"bad_path" );
2530 level.zombie_pathing_failed ++;
2535 if( isDefined(
self.enemyoverride ) )
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] ) )
2541 self.zombie_path_timer = 0;
2547 if(isDefined(
self.favoriteenemy))
2549 zm_utility::debug_print(
"Zombie couldn't path to player at origin: " +
self.favoriteenemy.origin +
" Falling back to breadcrumb system" );
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" );
2557 if( !isDefined(
self.favoriteenemy ) )
2559 self.zombie_path_timer = 0;
2564 self.favoriteenemy endon(
"disconnect" );
2568 players = GetPlayers();
2569 valid_player_num = 0;
2570 for( i = 0; i < players.size; i++ )
2574 valid_player_num += 1;
2578 if( players.size > 1 )
2580 if(isDefined(level._should_skip_ignore_player_logic) && [[level._should_skip_ignore_player_logic]]() )
2582 self.zombie_path_timer = 0;
2585 if( !IsInArray(
self.ignore_player,
self.favoriteenemy) )
2587 self.ignore_player[
self.ignore_player.size] =
self.favoriteenemy;
2590 if(
self.ignore_player.size < valid_player_num )
2592 self.zombie_path_timer = 0;
2598 crumb_list =
self.favoriteenemy.zombie_breadcrumbs;
2605 self.zombie_path_timer = 0;
2611 if ( !IsDefined( goal ) )
2616 level.zombie_breadcrumb_failed ++;
2618 goal =
self.favoriteenemy.spectator_respawn.origin;
2623 self.zombie_path_timer += 100;
2624 self SetGoal( goal );
2625 self waittill(
"bad_path" );
2628 for( i = 0; i < crumb_list.size; i++ )
2630 if( goal == crumb_list[i] )
2632 bad_crumbs[bad_crumbs.size] = i;
2641 assert( IsDefined( origin ) );
2642 assert( IsDefined( breadcrumbs ) );
2643 assert( IsArray( breadcrumbs ) );
2645 for( i = 0; i < breadcrumbs.size; i++ )
2649 crumb_index = RandomInt( breadcrumbs.size );
2661 return breadcrumbs[crumb_index];
2669 for ( i = 0; i < bad_crumbs.size; i++ )
2671 if ( bad_crumbs[i] == crumb )
2682 trace_distance = 35;
2683 jitter_distance = 2;
2685 index = start_crumb;
2687 while (isdefined(
self.favoriteenemy.zombie_breadcrumbs[ index + 1 ]))
2689 current_crumb =
self.favoriteenemy.zombie_breadcrumbs[ index ];
2690 next_crumb =
self.favoriteenemy.zombie_breadcrumbs[ index + 1 ];
2692 angles = vectortoangles(current_crumb - next_crumb);
2694 right = anglestoright(angles);
2695 left = anglestoright(angles + (0,180,0));
2697 dist_pos = current_crumb + VectorScale( right, trace_distance );
2699 trace = bulletTrace( current_crumb, dist_pos,
true, undefined );
2700 vector =
trace[
"position"];
2702 if (distance(vector, current_crumb) < 17 )
2704 self.favoriteenemy.zombie_breadcrumbs[ index ] = current_crumb + VectorScale( left, jitter_distance );
2710 dist_pos = current_crumb + VectorScale( left, trace_distance );
2712 trace = bulletTrace( current_crumb, dist_pos,
true, undefined );
2713 vector =
trace[
"position"];
2715 if (distance(vector, current_crumb) < 17 )
2717 self.favoriteenemy.zombie_breadcrumbs[ index ] = current_crumb + VectorScale( right, jitter_distance );
2732 for(i = 0; i < 4; i ++)
2734 notes[notes.size] =
"zombie_repath_notify_"+i;
2739 level notify(notes[note]);
2741 note = (note + 1) % 4;
2748 self endon(
"death" );
2749 self endon(
"zombie_acquire_enemy" );
2750 self endon(
"bad_path" );
2752 level endon(
"intermission" );
2754 if(!isdefined(level.repathNotifierStarted))
2756 level.repathNotifierStarted =
true;
2761 if(!isdefined(
self.zombie_repath_notify))
2763 self.zombie_repath_notify =
"zombie_repath_notify_" + (
self getentitynumber() % 4);
2768 if(!isdefined(
self._skip_pathing_first_delay))
2770 level waittill(
self.zombie_repath_notify);
2774 self._skip_pathing_first_delay = undefined;
2777 if( !
IS_TRUE(
self.ignore_enemyoverride ) && isDefined(
self.enemyoverride ) && isDefined(
self.enemyoverride[1] ) )
2779 if( distanceSquared(
self.origin,
self.enemyoverride[0] ) > 1*1 )
2781 self OrientMode(
"face motion" );
2785 self OrientMode(
"face point",
self.enemyoverride[1].origin );
2787 self.ignoreall =
true;
2789 goalPos =
self.enemyoverride[0];
2790 if ( IsDefined( level.adjust_enemyoverride_func ) )
2792 goalPos =
self [[ level.adjust_enemyoverride_func ]]();
2794 self SetGoal( goalPos );
2796 else if( IsDefined(
self.favoriteenemy ) )
2798 self.ignoreall =
false;
2801 if ( IsDefined( level.enemy_location_override_func ) )
2803 goalPos = [[ level.enemy_location_override_func ]](
self,
self.favoriteenemy );
2805 if ( IsDefined( goalPos ) )
2807 self SetGoal( goalPos );
2814 else if(
IS_TRUE(
self.is_rat_test) )
2822 else if ( IsDefined(
self.favoriteenemy.last_valid_position ) )
2824 self SetGoal(
self.favoriteenemy.last_valid_position );
2831 if ( !IsDefined( level.ignore_path_delays ) )
2833 distSq = distanceSquared(
self.origin,
self.favoriteenemy.origin );
2835 if( distSq > 3200 * 3200 )
2837 wait(2.0 + randomFloat( 1.0 ));
2839 else if( distSq > 2200 * 2200 )
2841 wait(1.0 + randomFloat( 0.5 ));
2843 else if( distSq > 1200 * 1200 )
2845 wait(0.5 + randomFloat( 0.5 ));
2852 if( isDefined( level.inaccesible_player_func ) )
2854 self [[ level.inaccessible_player_func ]]();
2869 self endon(
"death");
2874 if(isDefined(
self._rise_spot))
2876 spot =
self._rise_spot;
2882 if (
IS_TRUE( level.use_multiple_spawns ) && isdefined(
self.script_int ) )
2884 foreach( loc
in level.zm_loc_types[
"zombie_location" ] )
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 )) )
2892 if ( IsDefined( loc.script_int ) && ( loc.script_int !=
self.script_int ) )
2896 else if ( IsDefined( level.zones[ loc.zone_name ].script_int ) && ( level.zones[ loc.zone_name ].script_int !=
self.script_int ) )
2901 spots[spots.size] = loc;
2906 spots = level.zm_loc_types[
"zombie_location" ];
2909 if ( GetDvarInt(
"scr_zombie_spawn_in_view") )
2911 player = GetPlayers()[0];
2914 look_loc = undefined;
2915 foreach ( loc
in level.zm_loc_types[
"zombie_location" ] )
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" ) )
2925 if ( dot > max_dot )
2935 if ( isdefined( look_loc ) )
2937 spots[ spots.size ] = look_loc;
2941 if ( spots.size <= 0 )
2943 spots[spots.size] = level.zm_loc_types[
"zombie_location" ][0];
2944 iprintln(
"no spawner in view" );
2948 assert( spots.size > 0,
"No spawn locations found" );
2950 if( isdefined(level.zm_custom_spawn_location_selection) )
2952 spot = [[level.zm_custom_spawn_location_selection]](spots);
2956 spot = array::random(spots);
2958 self.spawn_point = spot;
2961 self thread [[level.move_spawn_func]](spot);
2971 self endon(
"death");
2973 self.in_the_ground =
true;
2975 if ( IsDefined(
self.anchor ) )
2977 self.anchor Delete();
2980 self.anchor =
spawn(
"script_origin",
self.origin);
2981 self.anchor.angles =
self.angles;
2982 self linkto(
self.anchor);
2984 if( !isDefined( spot.angles ) )
2986 spot.angles = (0, 0, 0);
2989 anim_org = spot.origin;
2990 anim_ang = spot.angles;
2992 anim_org = anim_org + (0, 0, 0);
2997 self.anchor moveto(anim_org, .05);
2998 self.anchor waittill(
"movedone");
3002 if (IsDefined(target_org))
3004 anim_ang = VectorToAngles(target_org -
self.origin);
3005 self.anchor RotateTo((0, anim_ang[1], 0), .05);
3006 self.anchor waittill(
"rotatedone");
3011 if(isDefined(
self.anchor))
3013 self.anchor
delete();
3022 if (
self.zombie_move_speed ==
"walk" )
3024 substate = RandomInt( 2 );
3026 else if (
self.zombie_move_speed ==
"run" )
3030 else if (
self.zombie_move_speed ==
"sprint" )
3035 self OrientMode(
"face default" );
3037 if( isdefined( level.custom_riseanim ) )
3039 self AnimScripted(
"rise_anim",
self.origin, spot.angles, level.custom_riseanim );
3041 else if( isdefined( level.custom_rise_func ) )
3043 self [[ level.custom_rise_func ]]( spot );
3047 self AnimScripted(
"rise_anim",
self.origin, spot.angles,
"ai_zombie_traverse_ground_climbout_fast" );
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 );
3066 if(!
IS_TRUE(level.riser_fx_on_client))
3075 zombie endon(
"death");
3076 self endon(
"stop_zombie_rise_fx");
3078 if (zombie.zombie_move_speed !=
"sprint")
3087 self endon(
"stop_zombie_rise_fx");
3088 self endon(
"rise_anim_finished");
3090 if(IsDefined(
self.script_parameters) &&
self.script_parameters ==
"in_water" && (!
IS_TRUE(level._no_water_risers)) )
3094 else if(IsDefined(
self.script_parameters) &&
self.script_parameters ==
"in_foliage" && (
IS_TRUE(level._foliage_risers)) )
3098 else if(IsDefined(
self.script_parameters) &&
self.script_parameters ==
"in_snow")
3106 if(isDefined(zombie.zone_name ) && isDefined(level.zones[zombie.zone_name]) )
3108 low_g_zones = getentarray(zombie.zone_name,
"targetname");
3110 if(isDefined(low_g_zones[0].script_string) && low_g_zones[0].script_string ==
"lowgravity")
3132 dust_tag =
"J_SpineUpper";
3134 self endon(
"stop_zombie_rise_dust_fx");
3141 if(IsDefined(
self.script_parameters) &&
self.script_parameters ==
"in_water")
3144 for (t = 0; t < dust_time; t += dust_interval)
3146 PlayfxOnTag(level._effect[
"rise_dust_water"], zombie, dust_tag);
3151 else if(IsDefined(
self.script_parameters) &&
self.script_parameters ==
"in_snow")
3154 for (t = 0; t < dust_time; t += dust_interval)
3156 PlayfxOnTag(level._effect[
"rise_dust_snow"], zombie, dust_tag);
3161 else if(IsDefined(
self.script_parameters) &&
self.script_parameters ==
"in_foliage")
3164 for (t = 0; t < dust_time; t += dust_interval)
3166 PlayfxOnTag(level._effect[
"rise_dust_foliage"], zombie, dust_tag);
3173 for (t = 0; t < dust_time; t += dust_interval)
3175 PlayfxOnTag(level._effect[
"rise_dust"], zombie, dust_tag);
3183 zombie waittill(
"death");
3184 self notify(
"stop_zombie_rise_dust_fx");
3190 self endon(
"death");
3192 if(
self.animname ==
"quad_zombie")
3197 if( RandomInt( 100 ) < level.zombie_vars[
"tesla_head_gib_chance"] )
3199 wait( randomfloatrange( 0.53, 1.0 ) );
3210 self endon(
"death" );
3217 if( isdefined(
self.zombie_move_speed ) )
3219 switch(
self.zombie_move_speed)
3221 case "walk": type=
"ambient";
float=4;
break;
3222 case "run": type=
"sprint";
float=4;
break;
3223 case "sprint": type=
"sprint";
float=4;
break;
3227 if(
self.animname ==
"zombie" &&
self.missingLegs )
3231 else if(
self.animname ==
"thief_zombie" ||
self.animname ==
"leaper_zombie" )
3235 else if(
self.voicePrefix ==
"keeper" )
3240 name =
self.animname;
3241 if( isdefined(
self.sndname ) )
3243 name =
self.sndname;
3247 self notify(
"bhtn_action_notify", type );
3249 wait(RandomFloatRange(1,
float));
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 ) )
3261 self SetGoal(
self.backedUpGoal );
3262 self.backedUpGoal = undefined;
3271 self endon(
"death" );
3274 if ( !IsDefined(
self ) )
3278 self SetFreeCameraLockOnAllowed(
true );
3283 self endon(
"death" );
3286 if ( !IsDefined(
self ) )
3290 self PushActors(
true );