1 #using scripts\codescripts\struct;
3 #using scripts\shared\array_shared;
4 #using scripts\shared\callbacks_shared;
5 #using scripts\shared\clientfield_shared;
6 #using scripts\shared\flag_shared;
7 #using scripts\shared\hud_util_shared;
8 #using scripts\shared\laststand_shared;
9 #using scripts\shared\math_shared;
10 #using scripts\shared\system_shared;
11 #using scripts\shared\throttle_shared;
12 #using scripts\shared\util_shared;
13 #using scripts\shared\scene_shared;
15 #using scripts\zm\_zm;
16 #using scripts\zm\_zm_audio;
17 #using scripts\zm\_zm_bgb;
18 #using scripts\zm\_zm_equipment;
19 #using scripts\zm\_zm_laststand;
20 #using scripts\zm\_zm_net;
21 #using scripts\zm\_zm_powerups;
22 #using scripts\zm\_zm_spawner;
23 #using scripts\zm\_zm_unitrigger;
24 #using scripts\zm\_zm_utility;
25 #using scripts\zm\_zm_weapons;
26 #using scripts\zm\_zm_hero_weapon;
28 #using scripts\shared\ai\systems\gib;
29 #using scripts\shared\ai\zombie_death;
30 #using scripts\shared\ai\zombie_shared;
31 #using scripts\shared\ai\zombie_utility;
32 #using scripts\shared\ai\zombie_vortex;
34 #using scripts\shared\abilities\_ability_player;
36 #insert scripts\shared\ai\systems\blackboard.gsh;
37 #insert scripts\shared\shared.gsh;
38 #insert scripts\shared\version.gsh;
39 #insert scripts\shared\abilities\_ability_util.gsh;
40 #insert scripts\zm\_zm_utility.gsh;
41 #insert scripts\zm\_zm_weap_gravityspikes.gsh;
42 #insert scripts\shared\archetype_shared\archetype_shared.gsh;
43 #insert scripts\shared\ai\zombie_vortex.gsh;
45 #precache( "string", "ZOMBIE_GRAVITYSPIKE_RECHARGED" );
46 #precache( "model", "wpn_zmb_dlc1_talon_spike_single_world" );
48 #namespace zm_weap_gravityspikes;
52 #define V_GROUND_OFFSET_FUDGE ( 0, 0, 32 )
54 #define N_GRAVITYSPIKES_ACTIVE_TIME 20
55 #define V_PHYSICSTRACE_CAPSULE_MIN ( -16, -16, -16 )
56 #define V_PHYSICSTRACE_CAPSULE_MAX ( 16, 16, 16 )
58 #define N_MAX_ZOMBIES_LIFTED_FOR_RAGDOLL 12
59 #define N_GRAVITYSPIKES_LOS_HEIGHT_OFFSET 50
61 #define N_GRAVITYSPIKES_MELEE_KILL_RADIUS 200
62 #define N_GRAVITYSPIKES_KNOCKDOWN_RADIUS 400
64 #define N_GRAVITYSPIKES_MELEE_HEIGHT 96
65 #define N_GRAVITYSPIKES_MELEE_PUSH_AWAY 128
66 #define N_GRAVITY_MELEE_LIFT_HEIGHT_MIN 128
67 #define N_GRAVITY_MELEE_LIFT_HEIGHT_MAX 200
68 #define N_GRAVITY_MELEE_MIN_LIFT_SPEED 150
69 #define N_GRAVITY_MELEE_MAX_LIFT_SPEED 200
71 #define N_GRAVITY_TRAP_SEPERATION 24
72 #define N_GRAVITY_TRAP_HEIGHT 96
73 #define N_GRAVITY_TRAP_PUSH_AWAY 0
74 #define N_GRAVITY_TRAP_LIFT_HEIGHT_MIN 184
75 #define N_GRAVITY_TRAP_LIFT_HEIGHT_MAX 284
76 #define N_GRAVITY_TRAP_MIN_LIFT_SPEED 64
77 #define N_GRAVITY_TRAP_MAX_LIFT_SPEED 128
78 #define N_GRAVITY_TRAP_MAX_LIFT_TIME 10
79 #define V_GRAVITY_TRAP_LIFT_AMOUNT_OFFSET ( 0, 0, -24 )
81 #define N_GRAVITYSPIKE_HINT_TIMER 3
83 #define B_DISABLE_GIBBING 0
84 #define SPIKES_CHOP_CONE_RANGE 120
88 level.n_zombies_lifted_for_ragdoll = 0;
91 level.spikes_chop_cone_range_sq = level.spikes_chop_cone_range * level.spikes_chop_cone_range;
94 level.ai_gravity_throttle =
new Throttle();
95 [[ level.ai_gravity_throttle ]]->Initialize( 2, 0.1 );
98 level.ai_spikes_chop_throttle =
new Throttle();
99 [[ level.ai_spikes_chop_throttle ]]->Initialize( 6, 0.1 );
132 self endon(
"disconnect" );
133 self endon(
"bled_out" );
134 self endon(
"death" );
135 self endon(
"gravity_spike_expired" );
139 self.b_gravity_trap_spikes_in_ground =
false;
140 self.disable_hero_power_charging =
false;
141 self.b_gravity_trap_fx_on =
false;
149 self waittill(
"new_hero_weapon", weapon );
151 while( weapon != w_gravityspike );
153 if( isdefined(
self.a_gravityspikes_prev_ammo_clip ) && isdefined(
self.a_gravityspikes_prev_ammo_clip[
STR_GRAVITYSPIKES_NAME ] ) )
156 self.a_gravityspikes_prev_ammo_clip = undefined;
160 self SetWeaponAmmoClip( w_gravityspike, w_gravityspike.clipSize );
163 if( isdefined(
self.saved_spike_power ) )
165 self GadgetPowerSet(
self GadgetGetSlot( w_gravityspike ),
self.saved_spike_power );
166 self.saved_spike_power = undefined;
170 self GadgetPowerSet(
self GadgetGetSlot( w_gravityspike ), 100 );
173 self.gravity_trap_unitrigger_stub = undefined;
183 self endon(
"disconnect" );
188 if(
IS_TRUE(
self.b_has_gravityspikes ) )
196 self waittill(
"bled_out" );
199 if (
self HasWeapon( w_gravityspike ) )
201 self.b_has_gravityspikes =
true;
203 self.saved_spike_power =
self GadgetPowerGet(
self GadgetGetSlot( w_gravityspike ) );
206 if(
self.saved_spike_power >= 100 )
208 self.saved_spike_power = undefined;
214 if( isdefined(
self.gravity_trap_unitrigger_stub ) )
217 self.gravity_trap_unitrigger_stub = undefined;
220 self waittill(
"spawned_player");
228 const N_HERO_MINPOWER = 0;
229 const N_HERO_MAXPOWER = 100;
244 if(
IS_TRUE( e_player.disable_hero_power_charging ) )
249 if( isdefined( e_player ) && isdefined(e_player.hero_power) )
252 if( isdefined( ai_enemy.heroweapon_kill_power ) )
255 if ( e_player hasperk(
"specialty_overcharge" ) )
257 n_perk_factor = GetDvarFloat(
"gadgetPowerOverchargePerkScoreFactor" );
261 if ( IsDefined(ai_enemy.damageweapon) &&
262 (IsSubStr( ai_enemy.damageweapon.name,
"elemental_bow_demongate" ) || IsSubStr( ai_enemy.damageweapon.name,
"elemental_bow_run_prison" ) ||
263 IsSubStr( ai_enemy.damageweapon.name,
"elemental_bow_storm" ) || IsSubStr( ai_enemy.damageweapon.name,
"elemental_bow_wolf_howl" )) )
265 n_perk_factor = 0.25;
268 e_player.hero_power = e_player.hero_power + n_perk_factor * ( ai_enemy.heroweapon_kill_power );
270 e_player.hero_power =
math::clamp( e_player.hero_power, N_HERO_MINPOWER, N_HERO_MAXPOWER );
271 if ( e_player.hero_power >= e_player.hero_power_prev )
273 e_player GadgetPowerSet( e_player GadgetGetSlot( w_gravityspike ), e_player.hero_power );
278 if( e_player.hero_power >= 100 )
291 if( !
IS_TRUE(
self.b_used_spikes ) )
293 if ( isdefined(
self.hintelem) )
295 self.hintelem settext(
"");
300 self.b_used_spikes =
true;
315 self notify(
"gravityspikes_attack_watchers_end" );
317 if(
IS_TRUE(
self.b_gravity_trap_spikes_in_ground ) )
319 self.disable_hero_power_charging =
true;
328 self endon(
"disconnect" );
332 self waittill(
"weapon_switch_started", w_current );
335 self SetWeaponAmmoClip( w_current, 0 );
342 self endon(
"disconnect" );
346 self waittill(
"weapon_change", w_current, w_previous );
349 self.w_gravityspikes_wpn_prev = w_previous;
356 self endon(
"gravityspikes_attack_watchers_end" );
357 self endon(
"disconnect" );
358 self endon(
"bled_out" );
359 self endon(
"death" );
360 self endon(
"gravity_spike_expired" );
364 self waittill(
"weapon_melee_power", weapon );
366 if ( weapon == wpn_gravityspikes )
368 self PlayRumbleOnEntity(
"talon_spike" );
377 self endon(
"gravityspikes_attack_watchers_end" );
378 self endon(
"disconnect" );
379 self endon(
"bled_out" );
380 self endon(
"death" );
381 self endon(
"gravity_spike_expired" );
383 first_half_traces =
true;
387 if( !(
self IsSlamming()) )
393 while ( (
self IsSlamming()) && (
self GetCurrentWeapon()) == wpn_gravityspikes )
396 player_angles =
self GetPlayerAngles();
398 forward_vec = AnglesToForward( (0, player_angles[1], 0) );
400 if(forward_vec[0] == 0 && forward_vec[1] == 0 && forward_vec[2] == 0)
406 forward_right_45_vec = RotatePoint(forward_vec, (0, 45, 0));
407 forward_left_45_vec = RotatePoint(forward_vec, (0, -45, 0));
409 right_vec = AnglesToRight(player_angles);
414 start_point =
self.origin + ( 0, 0, 50 );
415 end_point =
self.origin + ( 0, 0, end_height );
420 trace_end_points = [];
422 if(first_half_traces)
424 trace_end_points[0] = end_point + VectorScale(forward_vec, end_radius);
425 trace_end_points[1] = end_point + VectorScale(right_vec, end_radius);
426 trace_end_points[2] = end_point - VectorScale(right_vec, end_radius);
428 first_half_traces =
false;
432 trace_end_points[0] = end_point + VectorScale(forward_right_45_vec, end_radius);
433 trace_end_points[1] = end_point + VectorScale(forward_left_45_vec, end_radius);
434 trace_end_points[2] = end_point - VectorScale(forward_vec, end_radius);
437 first_half_traces =
true;
440 for( i = 0; i < 3; i++ )
442 trace = BulletTrace(start_point, trace_end_points[i],
true,
self);
444 if(
trace[
"fraction"] < 1 )
466 self endon(
"gravityspikes_attack_watchers_end" );
467 self endon(
"disconnect" );
468 self endon(
"bled_out" );
469 self endon(
"death" );
470 self endon(
"gravity_spike_expired" );
474 self waittill(
"weapon_melee_power_left", weapon );
486 if( isdefined( level.gravityspike_position_check ) )
488 return (
self [[level.gravityspike_position_check]]() );
490 else if( IsPointOnNavMesh(
self.origin,
self ) )
498 self endon(
"disconnect" );
500 const N_SPIKES_AUTOKILL_DAMAGE = 3594;
502 if( !isdefined( ai ) || !IsAlive( ai ) )
508 if ( N_SPIKES_AUTOKILL_DAMAGE >= ai.health )
510 ai.ignoreMelee =
true;
513 [[ level.ai_spikes_chop_throttle ]]->WaitInQueue( ai );
515 ai DoDamage( N_SPIKES_AUTOKILL_DAMAGE,
self.origin,
self,
self,
"none",
"MOD_UNKNOWN", 0, weapon );
522 view_pos =
self GetWeaponMuzzlePoint();
523 forward_view_angles =
self GetWeaponForwardDir();
526 zombie_list = GetAITeamArray( level.zombie_team );
527 foreach( ai
in zombie_list )
529 if ( !IsDefined( ai ) || !IsAlive( ai ) )
543 test_origin = ai getcentroid();
544 dist_sq = DistanceSquared( view_pos, test_origin );
546 dist_to_check = level.spikes_chop_cone_range_sq;
547 if ( dist_sq > dist_to_check )
552 normal = VectorNormalize( test_origin - view_pos );
553 dot = VectorDot( forward_view_angles, normal );
559 if ( 0 == ai DamageConeTrace( view_pos,
self ) )
567 if ( isdefined( ai.chop_actor_cb ) )
569 self thread [[ ai.chop_actor_cb ]]( ai,
self, weapon );
589 self endon(
"gravityspikes_attack_watchers_end" );
590 self endon(
"disconnect" );
591 self endon(
"bled_out" );
592 self endon(
"death" );
593 self endon(
"gravity_spike_expired" );
597 self waittill(
"weapon_melee", weapon );
610 if( !
IS_TRUE( player.disable_hero_power_charging ) )
612 player GadgetPowerSet( 0, 100 );
621 self notify(
"stop_draining_hero_weapon" );
622 self notify(
"gravityspikes_timer_end" );
630 function player_invulnerable_during_gravityspike_slam( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, boneIndex )
644 self.gravityspikes_slam =
true;
646 self.gravityspikes_slam =
false;
654 self endon(
"disconnect" );
655 self endon(
"bled_out" );
656 self endon(
"death" );
660 foreach( e_player
in level.activeplayers )
662 if( isdefined(e_player) && !
IS_TRUE( e_player.idgun_vision_on ) )
668 if( !
IS_TRUE( e_player.vortex_rumble ) )
681 e_player endon(
"disconnect" );
682 e_player endon(
"bled_out" );
683 e_player endon(
"death" );
685 e_player.vortex_rumble =
true;
695 e_player.vortex_rumble = undefined;
703 self endon(
"disconnect" );
704 self endon(
"bled_out" );
705 self endon(
"death" );
707 v_forward = AnglesToForward(
self.angles );
708 v_right = AnglesToRight(
self.angles );
711 v_spawn_pos_left = v_spawn_pos_right;
721 a_v_spawn_pos =
array( v_spawn_pos_right, v_spawn_pos_left );
724 if(
self IsOnGround() )
738 self SetWeaponAmmoClip( wpn_gravityspikes, 0 );
740 self.b_gravity_trap_spikes_in_ground =
true;
741 self.v_gravity_trap_pos = v_gravity_trap_pos;
742 self notify(
"gravity_trap_planted" );
752 if( isdefined(
self ) )
754 self.b_gravity_trap_spikes_in_ground =
false;
755 self.disable_hero_power_charging =
false;
756 self notify(
"destroy_ground_spikes" );
763 self endon(
"gravity_trap_spikes_retrieved" );
764 self endon(
"disconnect" );
765 self endon(
"bled_out" );
766 self endon(
"death" );
768 is_gravity_trap_fx_on =
true;
775 a_zombies = GetAITeamArray( level.zombie_team );
779 else if( is_gravity_trap_fx_on )
782 is_gravity_trap_fx_on =
false;
806 player endon(
"gravity_trap_spikes_retrieved" );
807 player endon(
"disconnect" );
808 player endon(
"bled_out" );
809 player endon(
"death" );
811 assert( IsDefined( level.ai_gravity_throttle ) );
812 assert( IsDefined( player ) );
815 v_gravity_trap_origin = player.mdl_gravity_trap_fx_source.origin;
818 if( !isdefined(
self ) || !IsAlive(
self ) )
825 if(
self.in_gravity_trap ===
true )
829 self.in_gravity_trap =
true;
833 [[level.ai_gravity_throttle]]->WaitInQueue(
self);
835 if( IsDefined(
self) && IsAlive(
self) )
838 v_gravity_trap_origin,
855 if( !isdefined(
self.mdl_gravity_trap_spikes ) )
857 self.mdl_gravity_trap_spikes = [];
860 for( i = 0; i < a_v_spawn_pos.size; i++ )
862 if( !isdefined(
self.mdl_gravity_trap_spikes[ i ] ) )
864 self.mdl_gravity_trap_spikes[ i ] =
util::spawn_model(
"wpn_zmb_dlc1_talon_spike_single_world", a_v_spawn_pos[ i ] );
867 self.mdl_gravity_trap_spikes[ i ].origin = a_v_spawn_pos[ i ];
870 self.mdl_gravity_trap_spikes[ i ].angles =
self.angles;
871 self.mdl_gravity_trap_spikes[ i ] Show();
876 self.mdl_gravity_trap_spikes[ i ]
clientfield::set(
"gravity_trap_spike_spark", 1 );
879 if( isdefined( level.gravity_trap_spike_watcher ) )
881 [[ level.gravity_trap_spike_watcher ]](
self.mdl_gravity_trap_spikes[ i ] );
888 const N_TIME_INIT = 2;
892 self thread
scene::play(
"cin_zm_dlc1_spike_plant_loop",
self );
898 mdl_spike_source =
self.mdl_gravity_trap_fx_source;
899 mdl_gravity_trap_spikes =
self.mdl_gravity_trap_spikes;
903 if( isdefined( mdl_spike_source ) )
906 mdl_spike_source Ghost();
908 if(!isdefined(
self ) )
910 mdl_spike_source Delete();
914 if( !isdefined( mdl_gravity_trap_spikes ) )
919 for( i = 0; i < mdl_gravity_trap_spikes.size; i++ )
923 mdl_gravity_trap_spikes[ i ] thread
scene::stop(
"cin_zm_dlc1_spike_plant_loop" );
926 mdl_gravity_trap_spikes[ i ] Ghost();
928 if(!isdefined(
self ) )
930 mdl_gravity_trap_spikes[ i ] Delete();
937 if( !isdefined(
self.mdl_gravity_trap_fx_source ) )
941 self.mdl_gravity_trap_fx_source.origin = v_spawn_pos;
942 self.mdl_gravity_trap_fx_source Show();
951 if( !isdefined(
self.mdl_gravity_trap_fx_source ) )
968 if( isdefined(
self.gravity_trap_unitrigger_stub ) )
973 unitrigger_stub = spawnstruct();
974 unitrigger_stub.origin = v_origin;
975 unitrigger_stub.script_unitrigger_type =
"unitrigger_radius_use";
976 unitrigger_stub.cursor_hint =
"HINT_NOICON";
978 unitrigger_stub.require_look_at =
false;
979 unitrigger_stub.gravityspike_owner =
self;
980 unitrigger_stub.wpn_gravityspikes = wpn_gravityspikes;
982 self.gravity_trap_unitrigger_stub = unitrigger_stub;
993 if( player ==
self.stub.gravityspike_owner )
995 self SetHintString( &
"ZOMBIE_GRAVITYSPIKE_PICKUP" );
1000 self setInvisibleToPlayer( player );
1010 self waittill(
"trigger", player );
1035 if( player == trig_stub.gravityspike_owner )
1037 player notify(
"gravity_trap_spikes_retrieved" );
1039 player playsound (
"fly_talon_pickup");
1043 player.w_gravityspikes_wpn_prev = player GetCurrentWeapon();
1044 player GiveWeapon( trig_stub.wpn_gravityspikes );
1045 player GiveMaxAmmo( trig_stub.wpn_gravityspikes );
1046 player SetWeaponAmmoClip( trig_stub.wpn_gravityspikes, trig_stub.wpn_gravityspikes.clipSize );
1047 player SwitchToWeapon( trig_stub.wpn_gravityspikes );
1052 player.gravity_trap_unitrigger_stub = undefined;
1062 self.gravityspikes_state = n_gravityspikes_state;
1067 self.n_gravityspikes_power = n_gravityspikes_power;
1073 if( IsAlive(
self ) )
1075 n_z_diff =
self.origin[ 2 ] - v_attack_source[ 2 ];
1076 if( abs( n_z_diff ) < n_allowed_z_diff )
1078 if( Distance2DSquared(
self.origin, v_attack_source ) < n_radius_sq )
1081 if( BulletTracePassed(
self.origin + v_offset, v_attack_source + v_offset,
false,
self ) )
1093 b_callback_result =
true;
1094 if( isdefined( level.gravityspikes_target_filter_callback ) )
1096 b_callback_result = [[ level.gravityspikes_target_filter_callback ]]( ai_enemy );
1098 return b_callback_result;
1101 function zombie_lift( player, v_attack_source, n_push_away, n_lift_height, v_lift_offset, n_lift_speed )
1105 if( IsDefined(
self.zombie_lift_override ) )
1107 self thread [[
self.zombie_lift_override ]]( player, v_attack_source, n_push_away, n_lift_height, v_lift_offset, n_lift_speed );
1113 self.no_powerups =
true;
1114 self DoDamage(
self.health + 100,
self.origin, player, player, undefined,
"MOD_UNKNOWN", 0, wpn_gravityspikes );
1115 self playsound (
"zmb_talon_electrocute_swt");
1124 v_away_from_source = VectorNormalize(
self.origin - v_attack_source );
1125 v_away_from_source = v_away_from_source * n_push_away;
1126 v_away_from_source = ( v_away_from_source[ 0 ], v_away_from_source[ 1 ], n_lift_height );
1129 self.origin + v_away_from_source,
1134 v_lift = a_trace[
"fraction" ] * v_away_from_source;
1135 v_lift = ( v_lift + v_lift_offset );
1136 n_lift_time = Length( v_lift ) / n_lift_speed;
1140 if( isdefined(
self ) &&
IS_TRUE(
self.b_melee_kill ) )
1142 self SetPlayerCollision(
false );
1144 const N_FLING_FORCE = 150;
1146 if ( !
IS_TRUE( level.ignore_gravityspikes_ragdoll ) )
1148 self StartRagdoll();
1149 self LaunchRagdoll( N_FLING_FORCE * AnglesToUp(
self.angles ) + ( v_away_from_source[ 0 ], v_away_from_source[ 1 ], 0 ) );
1159 else if( isdefined(
self ) && v_lift[ 2 ] > 0 && Length( v_lift ) > Length( v_lift_offset ) )
1162 self SetPlayerCollision(
false );
1167 self playsound (
"zmb_talon_electrocute");
1171 self thread
scene::play(
"cin_zm_dlc1_zombie_crawler_talonspike_a_loop",
self );
1175 self thread
scene::play(
"cin_zm_dlc1_zombie_talonspike_loop",
self );
1180 self LinkTo(
self.mdl_trap_mover,
"tag_origin" );
1182 self.mdl_trap_mover MoveTo(
self.origin + v_lift, n_lift_time, 0, n_lift_time * 0.4 );
1187 self waittill(
"gravity_trap_complete" );
1190 if ( isdefined(
self) )
1195 self StartRagdoll(
true );
1206 n_fall_dist = abs(
self.origin[ 2 ] - v_land_pos[ 2 ] );
1208 if( n_slam_wait > 0 )
1215 if( IsAlive(
self ) )
1218 self playsound (
"zmb_talon_ai_slam");
1225 self playsound (
"zmb_talon_ai_slam");
1232 self endon(
"gravity_trap_complete" );
1237 player,
"gravity_trap_spikes_retrieved",
1238 player,
"gravityspikes_timer_end",
1239 player,
"disconnect",
1240 player,
"bled_out" );
1242 self notify(
"gravity_trap_complete" );
1247 self endon(
"gravity_trap_complete" );
1252 if( IsAlive(
self ) && !
IS_TRUE(
self.b_melee_kill ) )
1254 wait RandomFloatRange( 0.2, 1.0 );
1257 self notify(
"gravity_trap_complete" );
1262 player endon(
"gravityspikes_timer_end" );
1263 self endon(
"death" );
1268 negative_x = ( RandomIntRange( 0, 10 ) < 5 ? 1 : -1 );
1269 negative_z = ( RandomIntRange( 0, 10 ) < 5 ? 1 : -1 );
1271 self.mdl_trap_mover RotateTo( ( RandomIntRange( 90, 180 ) * negative_x,
1272 RandomIntRange( -90, 90 ),
1273 RandomIntRange( 90, 180 ) * negative_z ),
1276 self.mdl_trap_mover waittill(
"rotatedone" );
1284 self.no_powerups =
true;
1286 self DoDamage(
self.health + 100,
self.origin, player, player, undefined,
"MOD_UNKNOWN", 0, wpn_gravityspikes );
1289 n_random = RandomInt( 100 );
1302 if( n_random >= 20 )
1313 level.n_zombies_lifted_for_ragdoll++;
1314 self waittill(
"death" );
1315 level.n_zombies_lifted_for_ragdoll--;
1321 self waittill(
"actor_corpse", e_corpse );
1323 v_pos = GetClosestPointOnNavMesh( e_corpse.origin, 256 );
1325 if( !isdefined( v_pos ) || ( e_corpse.origin[2] > ( v_pos[2] + 64 ) ) )
1335 if( isDefined(
self ))
1351 self.b_melee_kill =
true;
1371 const N_DISTANCE_OFFSET = 24;
1374 v_forward = AnglesToForward(
self GetPlayerAngles());
1375 v_pos =
self.origin + VectorScale( v_forward, N_DISTANCE_OFFSET );
1377 a_ai = GetAITeamArray( level.zombie_team );
1399 mdl_fx_pos Delete();
1404 self endon(
"death" );
1411 self.knockdown =
true;
1413 v_zombie_to_player = v_position -
self.origin;
1414 v_zombie_to_player_2d = VectorNormalize( ( v_zombie_to_player[0], v_zombie_to_player[1], 0 ) );
1416 v_zombie_forward = AnglesToForward(
self.angles );
1417 v_zombie_forward_2d = VectorNormalize( ( v_zombie_forward[0], v_zombie_forward[1], 0 ) );
1419 v_zombie_right = AnglesToRight(
self.angles );
1420 v_zombie_right_2d = VectorNormalize( ( v_zombie_right[0], v_zombie_right[1], 0 ) );
1422 v_dot = VectorDot( v_zombie_to_player_2d, v_zombie_forward_2d );
1426 self.knockdown_direction =
"front";
1429 else if ( v_dot < 0.5 && v_dot > -0.5 )
1431 v_dot = VectorDot( v_zombie_to_player_2d, v_zombie_right_2d );
1434 self.knockdown_direction =
"right";
1447 self.knockdown_direction =
"left";
1453 self.knockdown_direction =
"back";
1459 self.knockdown =
false;