1 #using scripts\codescripts\struct;
3 #using scripts\shared\laststand_shared;
4 #using scripts\shared\math_shared;
5 #using scripts\shared\util_shared;
7 #insert scripts\shared\shared.gsh;
9 #using scripts\zm\_zm_clone;
10 #using scripts\zm\_zm_laststand;
11 #using scripts\zm\_zm_utility;
12 #using scripts\zm\_zm_weapons;
14 #precache( "fx", "zombie/fx_cymbal_monkey_light_zmb" );
15 #precache( "fx", "zombie/fx_monkey_lightning_zmb" );
16 #precache( "fx", "dlc3/stalingrad/fx_cymbal_monkey_radial_pulse" );
18 #using_animtree( "zombie_cymbal_monkey" );
20 #define VALID_POI_MAX_RADIUS 200
21 #define VALID_POI_HALF_HEIGHT 100
22 #define VALID_POI_INNER_SPACING 2
23 #define VALID_POI_RADIUS_FROM_EDGES 15
24 #define VALID_POI_HEIGHT 36
26 #define N_MONKEY_PULSE_RADIUS 128
27 #define N_MONKEY_PULSE_DAMAGE_MAX 1000
28 #define N_MONKEY_PULSE_DAMAGE_MIN 500
33 level.weaponZMCymbalMonkey = GetWeapon(
"cymbal_monkey" );
41 level.w_cymbal_monkey_upgraded = GetWeapon(
"cymbal_monkey_upgraded" );
45 level._effect[
"monkey_bass"] =
"dlc3/stalingrad/fx_cymbal_monkey_radial_pulse";
48 if (
IS_TRUE(level.legacy_cymbal_monkey))
50 level.cymbal_monkey_model =
"weapon_zombie_monkey_bomb";
54 level.cymbal_monkey_model =
"wpn_t7_zmb_monkey_bomb_world";
57 level._effect[
"monkey_glow"] =
"zombie/fx_cymbal_monkey_light_zmb";
58 level._effect[
"grenade_samantha_steal"] =
"zombie/fx_monkey_lightning_zmb";
60 level.cymbal_monkeys = [];
62 if ( !IsDefined( level.valid_poi_max_radius ) )
67 if ( !IsDefined( level.valid_poi_half_height ) )
72 if ( !IsDefined( level.valid_poi_inner_spacing ) )
77 if ( !IsDefined( level.valid_poi_radius_from_edges ) )
82 if ( !IsDefined( level.valid_poi_height ) )
90 self giveweapon( level.weaponZMCymbalMonkey );
104 self giveweapon( level.w_cymbal_monkey_upgraded );
112 self notify(
"starting_monkey_watch" );
113 self endon(
"disconnect" );
114 self endon(
"starting_monkey_watch" );
117 attract_dist_diff = level.monkey_attract_dist_diff;
118 if( !isDefined( attract_dist_diff ) )
120 attract_dist_diff = 45;
123 num_attractors = level.num_monkey_attractors;
124 if( !isDefined( num_attractors ) )
129 max_attract_dist = level.monkey_attract_dist;
130 if( !isDefined( max_attract_dist ) )
132 max_attract_dist = 1536;
146 self waittill(
"grenade_dud");
148 self playsound(
"zmb_vox_monkey_scream" );
149 self.monk_scream_vox =
true;
155 if (isdefined(
self.damagearea))
156 self.damagearea
delete();
168 level waittill(
"emp_detonate",origin,radius);
169 if ( DistanceSquared( origin,
self.origin) < radius * radius )
175 if (isdefined(level._equipment_emp_destroy_fx))
177 PlayFX( level._equipment_emp_destroy_fx,
self.origin + ( 0, 0, 5 ) , ( 0, RandomFloat( 360 ), 0 ) );
180 self.attract_to_origin =
false;
182 model ClearAnim( %o_monkey_bomb, 0 );
190 if (isdefined(
self.damagearea))
191 self.damagearea
delete();
199 self endon(
"death" );
200 owner endon(
"death" );
201 while (isdefined(
self))
203 self.angles = owner.angles;
211 self endon(
"show_owner");
212 if (isdefined(
self.show_for_time))
214 self.show_for_time = showtime;
217 self.show_for_time = showtime;
218 self SetVisibleToAll();
219 while (
self.show_for_time > 0 )
221 self.show_for_time -= 0.05;
224 self SetVisibleToAllExceptTeam( level.zombie_team );
225 self.show_for_time = undefined;
231 owner endon(
"hide_owner");
232 owner endon(
"show_owner");
233 self endon(
"explode" );
234 self endon(
"death" );
235 self endon(
"grenade_dud" );
237 owner.show_for_time = undefined;
241 owner waittill(
"weapon_fired" );
249 owner notify(
"hide_owner");
250 owner endon(
"hide_owner");
252 owner SetPerk(
"specialty_immunemms");
253 owner.no_burning_sfx =
true;
254 owner notify(
"stop_flame_sounds" );
255 owner SetVisibleToAllExceptTeam( level.zombie_team );
257 owner.hide_owner =
true;
259 if (isdefined(level._effect[
"human_disappears" ]))
260 PlayFX( level._effect[
"human_disappears" ], owner.origin );
267 owner notify(
"show_owner");
269 owner UnsetPerk(
"specialty_immunemms");
270 if (isdefined(level._effect[
"human_disappears" ]))
271 PlayFX( level._effect[
"human_disappears" ], owner.origin );
272 owner.no_burning_sfx = undefined;
273 owner SetVisibleToAll();
275 owner.hide_owner = undefined;
280 #define PLAYER_RADIUS 15.0
286 if ( !isdefined(
self) )
290 explosionRadius = detonateRadius * 2;
294 damagearea SetExcludeTeamForTrigger( owner.team );
296 damagearea enablelinkto();
297 damagearea linkto(
self );
299 self.damagearea = damagearea;
301 while ( isdefined(
self) )
303 damagearea waittill(
"trigger", ent );
305 if ( isdefined( owner ) && ent == owner )
308 if( isDefined( ent.team ) && ent.team == owner.team )
311 self playsound (
"wpn_claymore_alert");
313 dist = Distance(
self.origin, ent.origin );
315 RadiusDamage(
self.origin + (0,0,12),explosionRadius,1,1,owner,
"MOD_GRENADE_SPLASH",level.weaponZMCymbalMonkey);
317 if ( isdefined( owner ) )
325 if (isdefined(damagearea))
332 self notify(
"fakelinkto");
333 self endon(
"fakelinkto");
335 while (isdefined(
self) && isdefined(linkee))
337 self.origin = linkee.origin;
338 self.angles = linkee.angles;
346 self endon(
"disconnect" );
347 self endon(
"starting_monkey_watch" );
349 if( IsDefined( grenade ) )
351 grenade endon(
"death" );
355 if (isdefined(grenade.damagearea))
356 grenade.damagearea
delete();
361 model =
spawn(
"script_model", grenade.origin );
362 model SetModel( level.cymbal_monkey_model );
363 model UseAnimTree( #animtree );
364 model linkTo( grenade );
365 model.angles = grenade.angles;
370 if (
IS_TRUE(level.cymbal_monkey_dual_view))
372 model SetVisibleToAllExceptTeam( level.zombie_team );
376 model.simulacrum = clone;
386 info = spawnStruct();
387 info.sound_attractors = [];
390 grenade waittill(
"stationary");
392 if ( IsDefined(level.grenade_planted) )
394 self thread [[level.grenade_planted]](grenade,model);
397 if( isDefined( grenade ) )
399 grenade.ground_ent = grenade GetGroundEnt();
401 if (isdefined(model))
403 if ( isdefined(grenade.ground_ent) && !( grenade.ground_ent.classname ===
"worldspawn" ) )
405 model SetMovingPlatformEnabled(
true );
406 model LinkTo( grenade.ground_ent );
409 else if (!
IS_TRUE(grenade.backlinked))
412 model.origin = grenade.origin;
413 model.angles = grenade.angles;
417 model AnimScripted(
"cymbal_monkey_anim", grenade.origin, grenade.angles, %o_monkey_bomb );
419 if (isdefined(clone))
421 clone ForceTeleport( grenade.origin, grenade.angles );
425 clone SetInvisibleToAll();
426 clone SetVisibleToTeam(level.zombie_team);
429 grenade resetmissiledetonationtime();
430 PlayFxOnTag( level._effect[
"monkey_glow"], model,
"tag_origin_animate" );
434 if (
IS_TRUE( level.move_valid_poi_to_navmesh ) )
439 if ( isdefined( level.check_valid_poi ) )
441 valid_poi = grenade [[ level.check_valid_poi ]]( valid_poi );
447 grenade.attract_to_origin =
true;
452 if ( grenade.weapon == level.w_cymbal_monkey_upgraded )
458 level.cymbal_monkeys[ level.cymbal_monkeys.size ] = grenade;
462 grenade.script_noteworthy = undefined;
468 grenade.script_noteworthy = undefined;
481 if ( IsPointOnNavMesh(
self.origin ) )
486 v_orig =
self.origin;
487 queryResult = PositionQuery_Source_Navigation(
490 level.valid_poi_max_radius,
491 level.valid_poi_half_height,
492 level.valid_poi_inner_spacing,
493 level.valid_poi_radius_from_edges
496 if ( queryResult.data.size )
498 foreach ( point
in queryResult.data )
500 height_offset = abs(
self.origin[2] - point.origin[2] );
501 if ( height_offset > level.valid_poi_height )
506 if ( BulletTracePassed( point.origin + ( 0, 0, 20 ), v_orig + ( 0, 0, 20 ),
false,
self, undefined,
false,
false ) )
508 self.origin = point.origin;
520 if( !IsDefined( ent_model ) )
527 direction = ent_model.origin;
528 direction = (direction[1], direction[0], 0);
530 if(direction[1] < 0 || (direction[0] > 0 && direction[1] > 0))
532 direction = (direction[0], direction[1] * -1, 0);
534 else if(direction[0] < 0)
536 direction = (direction[0] * -1, direction[1], 0);
540 players = GetPlayers();
541 for( i = 0; i < players.size; i++ )
543 if( IsAlive( players[i] ) )
545 players[i] playlocalsound( level.zmb_laugh_alias );
550 PlayFXOnTag( level._effect[
"grenade_samantha_steal" ], ent_model,
"tag_origin" );
552 ent_model StopAnimScripted();
555 ent_model MoveZ( 60, 1.0, 0.25, 0.25 );
558 ent_model Vibrate( direction, 1.5, 2.5, 1.0 );
559 ent_model waittill(
"movedone" );
561 if (isdefined(
self.damagearea))
562 self.damagearea
delete();
567 if(isDefined(ent_actor))
572 if ( isdefined( ent_grenade ) )
574 if (isdefined(ent_grenade.damagearea))
575 ent_grenade.damagearea
delete();
576 ent_grenade Delete();
584 if( !isDefined( parent ) )
586 if (isdefined(
self) &&
IS_TRUE(
self.dud))
588 if (isdefined(
self.simulacrum))
589 self.simulacrum
delete();
600 self endon(
"explode" );
603 PlayFxOnTag( level._effect[
"monkey_bass"], model,
"tag_origin_animate" );
605 n_damage_origin =
self.origin + ( 0, 0, 12 );
609 a_ai_targets = GetAITeamArray(
"axis" );
611 foreach( ai_target
in a_ai_targets )
613 if ( isdefined( ai_target ) )
615 n_distance_to_target = Distance( ai_target.origin, n_damage_origin );
624 ai_target DoDamage( n_damage, ai_target.origin, e_owner,
self,
"none",
"MOD_GRENADE_SPLASH", 0, level.w_cymbal_monkey_upgraded );
635 self.monk_scream_vox =
false;
637 if (isdefined(level.grenade_safe_to_bounce))
639 if (![[level.grenade_safe_to_bounce]](
self.owner,level.weaponZMCymbalMonkey))
641 self playsound(
"zmb_vox_monkey_scream" );
642 self.monk_scream_vox =
true;
646 if (isdefined(level.monkey_song_override))
648 if ([[level.monkey_song_override]](
self.owner,level.weaponZMCymbalMonkey))
650 self playsound(
"zmb_vox_monkey_scream" );
651 self.monk_scream_vox =
true;
670 if( !
self.monk_scream_vox && level.musicSystem.currentPlaytype < 4 )
672 if (
IS_TRUE(level.cymbal_monkey_dual_view))
673 self playsoundtoteam(
"zmb_monkey_song",
"allies" );
674 else if(
self.weapon.name ==
"cymbal_monkey_upgraded" )
675 self playsound(
"zmb_monkey_song_upgraded" );
677 self playsound(
"zmb_monkey_song" );
680 if( !
self.monk_scream_vox )
683 self waittill(
"explode", position );
684 level notify(
"grenade_exploded",position,100,5000,450);
687 for ( i = 0; i < level.cymbal_monkeys.size; i++ )
689 if ( !isdefined( level.cymbal_monkeys[i] ) )
695 if ( monkey_index >= 0 )
697 ArrayRemoveIndex( level.cymbal_monkeys, monkey_index );
700 if( isDefined( model ) )
702 model ClearAnim( %o_monkey_bomb, 0.2 );
705 for( i = 0; i < info.sound_attractors.size; i++ )
707 if( isDefined( info.sound_attractors[i] ) )
709 info.sound_attractors[i] notify(
"monkey_blown_up" );
717 if(isdefined(
self ) )
719 if(
self.weapon.name ==
"cymbal_monkey_upgraded" )
721 self playsound(
"zmb_vox_monkey_explode_upgraded" );
725 self playsound(
"zmb_vox_monkey_explode" );
732 self endon(
"disconnect" );
733 self endon(
"starting_monkey_watch" );
737 self waittill(
"grenade_fire", grenade, weapon );
738 if( weapon == level.weaponZMCymbalMonkey || weapon == level.w_cymbal_monkey_upgraded )
740 grenade.use_grenade_special_long_bookmark =
true;
741 grenade.grenade_multiattack_bookmark_count = 1;
742 grenade.weapon = weapon;
752 self endon(
"explode" );
756 if( !isDefined(
self ) )
761 if( !isDefined(
self.attractor_array ) )
767 for( i = 0; i <
self.attractor_array.size; i++ )
769 if( !IsInArray( info.sound_attractors,
self.attractor_array[i] ) )
771 if ( isDefined(
self.origin ) && isDefined(
self.attractor_array[i].origin ) )
773 if( distanceSquared(
self.origin,
self.attractor_array[i].origin ) < 500 * 500 )
775 ARRAY_ADD( info.sound_attractors,
self.attractor_array[i] );
787 self endon(
"death" );
788 self endon(
"monkey_blown_up" );
792 if( isdefined (
self ) )
794 self playsound(
"zmb_vox_zombie_groan" );
795 wait randomfloatrange( 2, 3 );