1 #using scripts\codescripts\struct;
3 #using scripts\shared\ai_shared;
4 #using scripts\shared\array_shared;
5 #using scripts\shared\animation_shared;
6 #using scripts\shared\clientfield_shared;
7 #using scripts\shared\flag_shared;
8 #using scripts\shared\laststand_shared;
9 #using scripts\shared\math_shared;
10 #using scripts\shared\scene_shared;
11 #using scripts\shared\system_shared;
12 #using scripts\shared\util_shared;
14 #using scripts\shared\ai\systems\debug;
15 #using scripts\shared\ai\systems\gib;
16 #using scripts\shared\ai\zombie_utility;
17 #using scripts\shared\vehicle_ai_shared;
19 #insert scripts\shared\archetype_shared\archetype_shared.gsh;
20 #insert scripts\shared\shared.gsh;
21 #insert scripts\shared\version.gsh;
22 #insert scripts\zm\_zm_weap_octobomb.gsh;
24 #using scripts\zm\_zm_clone;
25 #using scripts\zm\_zm_laststand;
26 #using scripts\zm\_zm_utility;
27 #using scripts\zm\_zm_weapons;
28 #using scripts\zm\_zm_zonemgr;
30 #precache( "fx", "zombie/fx_monkey_lightning_zmb" );
52 level.mdl_octobomb =
"p7_fxanim_zm_zod_octobomb_mod";
59 level._effect[
"grenade_samantha_steal" ] =
"zombie/fx_monkey_lightning_zmb";
81 if ( isdefined( w_tactical ) )
83 self TakeWeapon( w_tactical );
86 w_weapon = GetWeapon( str_weapon );
87 self GiveWeapon( w_weapon );
95 self notify(
"starting_octobomb_watch" );
96 self endon(
"death" );
97 self endon(
"starting_octobomb_watch" );
100 attract_dist_custom = level.octobomb_attract_dist_custom;
101 if( !isdefined( attract_dist_custom ) )
103 attract_dist_custom = 10;
106 num_attractors = level.num_octobomb_attractors;
107 if( !isdefined( num_attractors ) )
112 max_attract_dist = level.octobomb_attract_dist;
113 if( !isdefined( max_attract_dist ) )
115 max_attract_dist = 1024;
121 if ( isdefined( e_grenade ) )
130 self endon(
"show_owner");
131 if (isdefined(
self.show_for_time))
133 self.show_for_time = showtime;
136 self.show_for_time = showtime;
137 self SetVisibleToAll();
138 while (
self.show_for_time > 0 )
140 self.show_for_time -= 0.05;
143 self SetVisibleToAllExceptTeam( level.zombie_team );
144 self.show_for_time = undefined;
150 owner endon(
"hide_owner");
151 owner endon(
"show_owner");
152 self endon(
"explode" );
153 self endon(
"death" );
154 self endon(
"grenade_dud" );
156 owner.show_for_time = undefined;
160 owner waittill(
"weapon_fired" );
168 owner notify(
"hide_owner");
169 owner endon(
"hide_owner");
171 owner SetPerk(
"specialty_immunemms");
172 owner.no_burning_sfx =
true;
173 owner notify(
"stop_flame_sounds" );
174 owner SetVisibleToAllExceptTeam( level.zombie_team );
176 owner.hide_owner =
true;
178 if (isdefined(level._effect[
"human_disappears" ]))
179 PlayFX( level._effect[
"human_disappears" ], owner.origin );
184 /# println(
"ZMCLONE: Player visible again because of "+evt ); #/
186 owner notify(
"show_owner");
188 owner UnsetPerk(
"specialty_immunemms");
189 if (isdefined(level._effect[
"human_disappears" ]))
190 PlayFX( level._effect[
"human_disappears" ], owner.origin );
191 owner.no_burning_sfx = undefined;
192 owner SetVisibleToAll();
194 owner.hide_owner = undefined;
202 self notify(
"fakelinkto");
203 self endon(
"fakelinkto");
205 while (isdefined(
self) && isdefined(linkee))
207 self.origin = linkee.origin;
208 self.angles = linkee.angles;
216 ride_vehicle = undefined;
217 grenade.ground_ent = grenade GetGroundEnt();
218 if ( isdefined( grenade.ground_ent ) )
220 if ( IsVehicle( grenade.ground_ent ) && !
IS_EQUAL(level.zombie_team,grenade.ground_ent) )
222 ride_vehicle = grenade.ground_ent;
226 if ( IsDefined(ride_vehicle) )
228 if (isdefined(grenade))
232 grenade SetMovingPlatformEnabled(
true );
233 grenade.equipment_can_move =
true;
234 grenade.isOnVehicle =
true;
235 grenade.move_parent = ride_vehicle;
236 if (isdefined(model))
238 model SetMovingPlatformEnabled(
true );
239 model LinkTo( ride_vehicle );
240 model.isOnVehicle =
true;
251 self endon(
"death" );
255 while( !level.o_zod_train
flag::get(
"moving" ) )
267 self endon(
"starting_octobomb_watch" );
269 e_grenade endon(
"death" );
273 if ( isdefined( e_grenade.damagearea ) )
275 e_grenade.damagearea Delete();
283 v_angles_clone_model =
self.angles + ( 90, 0, 90 );
284 v_angles_anim_model =
self.angles - ( 0, 90, 0 );
286 is_upgraded = ( e_grenade.weapon == level.w_octobomb_upgraded );
297 e_grenade.angles = v_angles_clone_model;
298 e_grenade.clone_model =
util::spawn_model( e_grenade.model, e_grenade.origin, e_grenade.angles );
299 e_grenade.clone_model LinkTo( e_grenade );
303 e_grenade waittill(
"stationary", v_position, v_normal );
309 e_grenade ResetMissileDetonationTime();
314 if ( isdefined( level.check_b_valid_poi) )
316 b_valid_poi= e_grenade [[ level.check_b_valid_poi]]( b_valid_poi);
319 if ( b_valid_poi && e_grenade.navmesh_check )
321 if ( isdefined( level.octobomb_attack_callback ) && IsFunctionPtr( level.octobomb_attack_callback ) )
323 [[ level.octobomb_attack_callback ]]( e_grenade );
336 if ( !
IS_TRUE( e_grenade.b_special_octobomb ) )
340 e_grenade.angles = v_angles_anim_model;
341 e_grenade.anim_model =
util::spawn_model( level.mdl_octobomb, e_grenade.origin, e_grenade.angles );
342 if (
IS_TRUE(e_grenade.isOnVehicle) )
344 e_grenade.anim_model SetMovingPlatformEnabled(
true );
345 e_grenade.anim_model LinkTo( e_grenade.ground_ent );
346 e_grenade.anim_model.isOnVehicle =
true;
347 e_grenade thread
FakeLinkto(e_grenade.anim_model);
364 level.octobombs[ level.octobombs.size ] = e_grenade;
368 e_grenade.script_noteworthy = undefined;
376 self endon(
"death" );
378 if ( IsPointOnNavMesh(
self.origin, 60 ) ==
true )
380 self.navmesh_check =
true;
384 v_valid_point = GetClosestPointOnNavMesh(
self.origin, 100 );
386 if ( isdefined( v_valid_point ) )
390 if (
self.origin[2] > v_valid_point[2] )
392 n_z_correct =
self.origin[2] - v_valid_point[2];
395 self.origin = v_valid_point + ( 0, 0, n_z_correct );
396 self.navmesh_check =
true;
399 self.navmesh_check =
false;
404 self endon(
"death" );
406 self playsound(
"wpn_octobomb_explode" );
407 self scene::play(
"p7_fxanim_zm_zod_octobomb_start_bundle",
self.anim_model );
408 self thread
scene::play(
"p7_fxanim_zm_zod_octobomb_loop_bundle",
self.anim_model );
410 n_start_anim_length = GetAnimLength(
"p7_fxanim_zm_zod_octobomb_start_anim" );
411 n_end_anim_length = GetAnimLength(
"p7_fxanim_zm_zod_octobomb_end_anim" );
412 n_life_time = ( (
self.weapon.fusetime - ( n_end_anim_length * 1000 ) - ( n_start_anim_length * 1000 ) ) / 1000 );
414 wait n_life_time * .75;
426 wait n_life_time * .25;
428 self scene::play(
"p7_fxanim_zm_zod_octobomb_end_bundle",
self.anim_model );
430 self playsound(
"wpn_octobomb_end" );
436 v_orig =
self.origin;
437 n_angles =
self.angles;
439 queryResult = PositionQuery_Source_Navigation(
448 if ( queryResult.data.size )
450 foreach ( point
in queryResult.data )
452 if ( BulletTracePassed( point.origin + ( 0, 0, 20 ), v_orig + ( 0, 0, 20 ),
false,
self, undefined,
false,
false ) )
454 if (
self.origin[2] > queryResult.origin[2] )
456 n_z_correct =
self.origin[2] - queryResult.origin[2];
458 self.origin = point.origin + (0, 0, n_z_correct);
459 self.angles = n_angles;
470 if( !isdefined( e_grenade ) )
477 direction = e_grenade.origin;
478 direction = ( direction[ 1 ], direction[ 0 ], 0 );
480 if ( direction[ 1 ] < 0 || ( direction[ 0 ] > 0 && direction[ 1 ] > 0 ) )
482 direction = ( direction[ 0 ], direction[ 1 ] * -1, 0 );
484 else if ( direction[ 0 ] < 0 )
486 direction = ( direction[ 0 ] * -1, direction[ 1 ], 0 );
490 if( !
IS_TRUE(e_grenade.sndNoSamLaugh) )
492 players = GetPlayers();
493 for ( i = 0; i < players.size; i++ )
495 if ( IsAlive( players[ i ] ) )
497 players[ i ] PlayLocalSound( level.zmb_laugh_alias );
503 PlayFXOnTag( level._effect[
"grenade_samantha_steal" ], e_grenade,
"tag_origin" );
505 e_grenade.clone_model Unlink();
508 e_grenade.clone_model MoveZ( 60, 1.0, 0.25, 0.25 );
511 e_grenade.clone_model Vibrate( direction, 1.5, 2.5, 1.0 );
512 e_grenade.clone_model waittill(
"movedone" );
514 if ( isdefined(
self.damagearea ) )
516 self.damagearea Delete();
519 e_grenade.clone_model Delete();
521 if ( isdefined( e_grenade ) )
523 if ( isdefined( e_grenade.damagearea ) )
525 e_grenade.damagearea Delete();
536 if ( !isdefined(
self ) )
538 if ( isdefined(
self.clone_model ) )
540 self.clone_model Delete();
543 if ( isdefined(
self.anim_model ) )
545 self.anim_model Delete();
548 if ( isdefined(
self ) &&
IS_TRUE(
self.dud ) )
553 if ( isdefined(
self.simulacrum ) )
555 self.simulacrum
delete();
568 self waittill(
"explode", position );
569 level notify(
"grenade_exploded", position, 100, 5000, 450 );
572 for ( i = 0; i < level.octobombs.size; i++ )
574 if ( !isdefined( level.octobombs[ i ] ) )
581 if ( octobomb_index >= 0 )
583 ArrayRemoveIndex( level.octobombs, octobomb_index );
590 self endon(
"explode" );
592 n_time_started = GetTime() / 1000;
596 n_time_current = GetTime() / 1000;
597 n_time_elapsed = n_time_current - n_time_started;
610 if ( isdefined( level.octobomb_targets ) )
612 a_ai_potential_targets = [[ level.octobomb_targets ]]( a_ai_potential_targets );
615 a_ai_targets = ArraySortClosest( a_ai_potential_targets,
self.origin, a_ai_potential_targets.size, 0,
OCTOBOMB_DAMAGE_RADIUS );
617 foreach ( ai_target
in a_ai_targets )
619 if ( IsAlive( ai_target ) )
623 if ( ai_target.b_octobomb_infected !==
true )
625 self notify(
"sndKillVox" );
627 ai_target playsound(
"wpn_octobomb_zombie_imp" );
645 self endon(
"death" );
647 self.octobomb_infected =
true;
648 n_infection_time = 0;
670 self DoDamage( n_damage * n_burst_damage,
self.origin, e_player, e_grenade );
673 self.octobomb_infected =
false;
680 self waittill(
"death" );
681 if ( isdefined(
self) )
683 if (
self.octobomb_infected ==
true )
694 self endon(
"death" );
714 if ( b_fast_grab ==
false )
716 n_wait_grab = RandomFloatRange( n_time_min, n_time_max );
727 if ( isdefined( level.octobomb_targets ) )
729 a_ai_potential_targets = [[ level.octobomb_targets ]]( a_ai_potential_targets );
732 a_ai_targets = ArraySort( a_ai_potential_targets,
self.origin,
true, a_ai_potential_targets.size,
OCTOBOMB_GRAB_RADIUS );
734 n_random_x = RandomFloatRange( -5, 5 );
735 n_random_y = RandomFloatRange( -5, 5 );
737 if ( a_ai_targets.size > 0 )
739 ai_target = array::random( a_ai_targets );
741 if ( IsAlive( ai_target ) )
744 self.octobomb_infected =
true;
746 self notify(
"sndKillVox" );
748 ai_target playsound(
"wpn_octobomb_zombie_imp" );
750 ai_target DoDamage( ai_target.health, ai_target.origin, e_player,
self );
751 ai_target StartRagdoll();
752 ai_target LaunchRagdoll( 105 * VectorNormalize( ai_target.origin -
self.origin + ( n_random_x, n_random_y, 200) ) );
756 if ( RandomInt( 6 ) > ( n_grabs + 3 ) )
776 gibserverutils::gibhead(
self );
780 gibserverutils::gibleftarm(
self );
784 gibserverutils::gibrightarm(
self );
787 gibserverutils::giblegs(
self );
793 self endon (
"death" );
795 self SetMaxHealth ( 1000 ) ;
796 self SetNormalHealth( 1 );
802 a_ai_zombies = array::get_all_closest(
self.origin, getAITeamArray( level.zombie_team ), undefined, undefined, max_attract_dist * 1.5 );
804 foreach ( ai_zombie
in a_ai_zombies )
806 if ( IsVehicle( ai_zombie ) )
811 if ( !isdefined(
self.v_parasite_attractor_center ) )
821 if ( ai_zombie.archetype ==
ARCHETYPE_RAPS && ai_zombie.b_attracted_to_octobomb !==
true )
846 self endon(
"death" );
848 self.favoriteenemy = e_grenade;
849 self.b_attracted_to_octobomb =
true;
850 self.ignoreme =
true;
852 e_grenade waittill(
"death" );
854 self.b_attracted_to_octobomb =
false;
855 self.ignoreme =
false;
861 self endon(
"death" );
863 self.octobomb_infected =
true;
864 n_infection_time = 0;
871 self.octobomb_infected =
false;
880 self.a_v_parasite_attractors = [];
890 self endon(
"death" );
892 self.favoriteenemy = e_grenade;
894 self.b_parasite_attracted =
true;
895 self.ignoreme =
true;
896 self.parasiteEnemy = e_grenade;
899 e_grenade waittill(
"death" );
903 self.b_parasite_attracted =
false;
904 self.ignoreme =
false;
911 self endon(
"death" );
912 e_grenade endon(
"death" );
919 self SetVehGoalPos( e_grenade.v_parasite_attractor_center,
false,
true );
924 self ClearVehGoalPos();
928 while(
self.b_parasite_attracted )
937 self SetVehGoalPos( e_grenade.a_v_parasite_attractors[i],
false,
true );
938 while ( Distance( e_grenade.a_v_parasite_attractors[i],
self.origin ) > 10 )
940 if ( !
self.b_parasite_attracted )
946 self ClearVehGoalPos();
957 e_grenade endon(
"death" );
958 self endon(
"death" );
965 if ( b_fast_grab ==
false )
975 a_ai_parasites = array::get_all_closest(
self.origin, getAITeamArray( level.zombie_team ), undefined, undefined, 150 );
977 while (i < a_ai_parasites.size)
979 if ( isdefined( a_ai_parasites[i] ) && (a_ai_parasites[i].archetype !=
ARCHETYPE_PARASITE) )
981 ArrayRemoveValue( a_ai_parasites, a_ai_parasites[i] );
988 if ( a_ai_parasites.size > 0 )
990 ai_parasite = array::random( a_ai_parasites );
992 v_fling = VectorNormalize( ai_parasite.origin - e_grenade.origin );
994 ai_parasite DoDamage( ai_parasite.maxhealth,
self.origin );
996 if ( RandomInt( 6 ) > ( n_grabs + 3 ) )
1003 b_fast_grab =
false;
1016 self endon(
"explode" );
1020 self waittill(
"sndKillVox" );
1022 self playsound(
"wpn_octobomb_attack_vox" );
1029 self endon(
"death" );
1030 self endon(
"starting_octobomb_watch" );
1034 self waittill(
"grenade_fire", e_grenade, w_weapon );
1035 if ( w_weapon == level.w_octobomb || w_weapon == level.w_octobomb_upgraded )
1037 e_grenade.use_grenade_special_long_bookmark =
true;
1038 e_grenade.grenade_multiattack_bookmark_count = 1;
1039 e_grenade.weapon = w_weapon;
1056 for( i = 0; i < 4; i++ )
1067 if( !isdefined( n_base_value ) )
1072 SetDvar( str_dvar, n_base_value );
1074 AddDebugCommand(
"devgui_cmd \"" + str_devgui_path +
"\" \"" + str_dvar +
" " + n_value +
"\"\n" );
1079 n_dvar = GetDvarInt( str_dvar );
1080 if ( n_dvar > n_base_value )
1083 [[ func ]]( n_dvar );
1084 SetDvar( str_dvar, n_base_value );
1093 players = GetPlayers();
1095 player = players[ n_player_index ];
1096 if( isdefined( player ) )
1100 else if( n_player_index === 4 )
1102 foreach( player
in players )
1114 player TakeWeapon( weapon );