‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
_zm_weap_octobomb.gsc
Go to the documentation of this file.
1 #using scripts\codescripts\struct;
2 
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;
13 
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;
18 
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;
23 
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;
29 
30 #precache( "fx", "zombie/fx_monkey_lightning_zmb" );
31 
32 ‪REGISTER_SYSTEM_EX( "zm_weap_octobomb", &‪__init__, &‪__main__, undefined )
33 
34 function ‪__init__()
35 {
36  ‪clientfield::register( "scriptmover", "octobomb_fx", ‪VERSION_SHIP, 2, "int" );
37  ‪clientfield::register( "actor", "octobomb_spores_fx", ‪VERSION_SHIP, 2, "int" );
38  ‪clientfield::register( "actor", "octobomb_tentacle_hit_fx", ‪VERSION_SHIP, 1, "int" );
39  ‪clientfield::register( "actor", "octobomb_zombie_explode_fx", ‪VERSION_TU8, 1, "counter" );
40  ‪clientfield::register( "toplayer", "octobomb_state", ‪VERSION_SHIP, 3, "int" );
41  ‪clientfield::register( "missile", "octobomb_spit_fx", ‪VERSION_SHIP, 2, "int" );
42 
43  /#
44  level thread ‪octobomb_devgui();
45  #/
46 }
47 
48 function ‪__main__()
49 {
50  level.w_octobomb = GetWeapon( ‪STR_WEAP_OCTOBOMB );
51  level.w_octobomb_upgraded = GetWeapon( ‪STR_WEAP_OCTOBOMB_UPGRADED );
52  level.mdl_octobomb = "p7_fxanim_zm_zod_octobomb_mod";
53 
54  if( !‪octobomb_exists() )
55  {
56  return;
57  }
58 
59  level._effect[ "grenade_samantha_steal" ] = "zombie/fx_monkey_lightning_zmb";
60 
63 
64  level.octobombs = [];
65 }
66 
67 
68 // Need a parameter-less function for the weapon callback
69 // self is a player
71 {
73 }
74 
75 
76 // self is a player
78 {
79  // Must remove the old weapon first
81  if ( isdefined( w_tactical ) )
82  {
83  self TakeWeapon( w_tactical );
84  }
85 
86  w_weapon = GetWeapon( str_weapon );
87  self GiveWeapon( w_weapon );
89  self thread ‪player_handle_octobomb();
90 }
91 
92 
94 {
95  self notify( "starting_octobomb_watch" );
96  self endon( "death" );
97  self endon( "starting_octobomb_watch" );
98 
99  // Min distance to attract positions
100  attract_dist_custom = level.octobomb_attract_dist_custom;
101  if( !isdefined( attract_dist_custom ) ) // Attraction point radius
102  {
103  attract_dist_custom = 10;
104  }
105 
106  num_attractors = level.num_octobomb_attractors;
107  if( !isdefined( num_attractors ) )
108  {
109  num_attractors = 64;
110  }
111 
112  max_attract_dist = level.octobomb_attract_dist;
113  if( !isdefined( max_attract_dist ) )
114  {
115  max_attract_dist = 1024;
116  }
117 
118  while ( true )
119  {
120  e_grenade = ‪get_thrown_octobomb();
121  if ( isdefined( e_grenade ) )
122  {
123  self thread ‪player_throw_octobomb( e_grenade, num_attractors, max_attract_dist, attract_dist_custom );
124  }
125  }
126 }
127 
128 function ‪show_briefly( showtime )
129 {
130  self endon("show_owner");
131  if (isdefined(self.show_for_time))
132  {
133  self.show_for_time = showtime;
134  return;
135  }
136  self.show_for_time = showtime;
137  self SetVisibleToAll();
138  while ( self.show_for_time > 0 )
139  {
140  self.show_for_time -= 0.05;
142  }
143  self SetVisibleToAllExceptTeam( level.zombie_team );
144  self.show_for_time = undefined;
145 }
146 
147 
148 function ‪show_owner_on_attack( owner )
149 {
150  owner endon("hide_owner");
151  owner endon("show_owner");
152  self endon( "explode" );
153  self endon( "death" );
154  self endon( "grenade_dud" );
155 
156  owner.show_for_time = undefined;
157 
158  for( ;; )
159  {
160  owner waittill( "weapon_fired" );
161  owner thread ‪show_briefly(0.5);
162  }
163 }
164 
165 
166 function ‪hide_owner( owner )
167 {
168  owner notify("hide_owner");
169  owner endon("hide_owner");
170 
171  owner SetPerk("specialty_immunemms");
172  owner.no_burning_sfx = true;
173  owner notify( "stop_flame_sounds" );
174  owner SetVisibleToAllExceptTeam( level.zombie_team );
175 
176  owner.hide_owner = true;
177 
178  if (isdefined(level._effect[ "human_disappears" ]))
179  PlayFX( level._effect[ "human_disappears" ], owner.origin );
180 
181  self thread ‪show_owner_on_attack( owner );
182 
183  evt = self ‪util::waittill_any_ex( "explode", "death", "grenade_dud", owner, "hide_owner" );
184  /# println( "ZMCLONE: Player visible again because of "+evt ); #/
185 
186  owner notify("show_owner");
187 
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();
193 
194  owner.hide_owner = undefined;
195 
196  owner Show();
197 }
198 
199 // hack because grenades can't linkto
200 function ‪FakeLinkto(linkee)
201 {
202  self notify("fakelinkto");
203  self endon("fakelinkto");
204  self.backlinked = 1;
205  while (isdefined(self) && isdefined(linkee))
206  {
207  self.origin = linkee.origin;
208  self.angles = linkee.angles;
209  wait 0.05;
210  }
211 }
212 
213 
214 function ‪grenade_planted( grenade, model )
215 {
216  ride_vehicle = undefined;
217  grenade.ground_ent = grenade GetGroundEnt();
218  if ( isdefined( grenade.ground_ent ) )
219  {
220  if ( IsVehicle( grenade.ground_ent ) && !‪IS_EQUAL(level.zombie_team,grenade.ground_ent) )
221  {
222  ride_vehicle = grenade.ground_ent;
223  }
224  }
225 
226  if ( IsDefined(ride_vehicle) )
227  {
228  if (isdefined(grenade))
229  {
230  //grenade enableLinkTo();
231  //grenade LinkTo( ride_vehicle );
232  grenade SetMovingPlatformEnabled( true );
233  grenade.equipment_can_move = true;
234  grenade.isOnVehicle = true;
235  grenade.move_parent = ride_vehicle;
236  if (isdefined(model))
237  {
238  model SetMovingPlatformEnabled( true );
239  model LinkTo( ride_vehicle );
240  model.isOnVehicle = true;
241  grenade ‪FakeLinkto(model);
242  }
243  }
244  }
245 }
246 
247 // If octobomb lands on train, detonates when train starts moving (or if already moving)
248 // Self == octobomb
250 {
251  self endon( "death" );
252 
253  if ( self ‪zm_zonemgr::entity_in_zone( "zone_train_rail" ) )
254  {
255  while( !level.o_zod_train ‪flag::get( "moving" ) )
256  {
257  wait ‪SERVER_FRAME;
258  continue;
259  }
260 
261  self ‪detonate();
262  }
263 }
264 
265 function ‪player_throw_octobomb( e_grenade, num_attractors, max_attract_dist, attract_dist_custom )
266 {
267  self endon( "starting_octobomb_watch" );
268 
269  e_grenade endon( "death" );
270 
272  {
273  if ( isdefined( e_grenade.damagearea ) )
274  {
275  e_grenade.damagearea Delete();
276  }
277 
278  e_grenade Delete();
279  return;
280  }
281 
282  // Angle fixes for spawned models
283  v_angles_clone_model = self.angles + ( 90, 0, 90 );
284  v_angles_anim_model = self.angles - ( 0, 90, 0 );
285 
286  is_upgraded = ( e_grenade.weapon == level.w_octobomb_upgraded );
287  if ( is_upgraded )
288  {
289  n_cf_val = ‪CF_OCTOBOMB_UG_FX;
290  }
291  else
292  {
293  n_cf_val = ‪CF_OCTOBOMB_FX;
294  }
295 
296  e_grenade Ghost();
297  e_grenade.angles = v_angles_clone_model; // clockwise turn so that Li'l Arnie points at the throwing player
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 );
300 
301  e_grenade thread ‪octobomb_cleanup();
302 
303  e_grenade waittill( "stationary", v_position, v_normal );
304 
305  e_grenade thread ‪check_octobomb_on_train();
306 
307  self thread ‪grenade_planted(e_grenade,e_grenade.clone_model);
308 
309  e_grenade ResetMissileDetonationTime();
310 
311  e_grenade ‪is_on_navmesh(); // Checks if octobomb is on navmesh
312  b_valid_poi = ‪zm_utility::check_point_in_enabled_zone( e_grenade.origin, undefined, undefined );
313 
314  if ( isdefined( level.check_b_valid_poi) )
315  {
316  b_valid_poi= e_grenade [[ level.check_b_valid_poi]]( b_valid_poi);
317  }
318 
319  if ( b_valid_poi && e_grenade.navmesh_check )
320  {
321  if ( isdefined( level.octobomb_attack_callback ) && IsFunctionPtr( level.octobomb_attack_callback ) )
322  {
323  [[ level.octobomb_attack_callback ]]( e_grenade );
324  }
325 
326  e_grenade ‪move_away_from_edges(); // Moves the grenade origin away from walls and collision
327 
328  e_grenade ‪zm_utility::create_zombie_point_of_interest( max_attract_dist, num_attractors, 10000 );
329  e_grenade thread ‪zm_utility::create_zombie_point_of_interest_attractor_positions( 4, attract_dist_custom );
331 
332  // e_grenade thread zm_utility::debug_draw_claimed_attractor_positions(); // DEBUG Draws lines from the octobomb origin to each of the claimed attractors
333  // e_grenade thread zm_utility::debug_draw_attractor_positions(); // DEBUG Draws lines from the octobomb origin to each of the attractors
334 
335  // If b_special_octobomb is true it's being handled differently.
336  if ( !‪IS_TRUE( e_grenade.b_special_octobomb ) )
337  {
338  e_grenade.clone_model ‪zm_utility::self_delete();
339 
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) )
343  {
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);
348  }
349  e_grenade.anim_model ‪clientfield::set( "octobomb_fx", ‪CF_OCTOBOMB_EXPLODE_FX );
350  wait ‪SERVER_FRAME; // Wait for explostion FX to get called and fired before starting spore FX
351  e_grenade.anim_model ‪clientfield::set( "octobomb_fx", n_cf_val );
352 
353  e_grenade thread ‪animate_octobomb( is_upgraded );
354  e_grenade thread ‪do_octobomb_sound();
355  }
356 
357  e_grenade thread ‪do_tentacle_burst( self, is_upgraded );
358  e_grenade thread ‪do_tentacle_grab( self, is_upgraded );
359  e_grenade thread ‪sndAttackVox();
360 
361  // Attracts elementals and parasites
362  e_grenade thread ‪special_attractor_spawn( self, max_attract_dist );
363 
364  level.octobombs[ level.octobombs.size ] = e_grenade;
365  }
366  else
367  {
368  e_grenade.script_noteworthy = undefined;
369  level thread ‪grenade_stolen_by_sam( e_grenade );
370  }
371 }
372 
373 // Checks if octobomb is on or within 200 units of a valid navmesh point. If not, will cause grenade to be stolen by Samantha
375 {
376  self endon( "death" );
377 
378  if ( IsPointOnNavMesh( self.origin, 60 ) == true )
379  {
380  self.navmesh_check = true;
381  return;
382  }
383 
384  v_valid_point = GetClosestPointOnNavMesh( self.origin, 100 );
385 
386  if ( isdefined( v_valid_point ) )
387  {
388  n_z_correct = 0.0;
389 
390  if ( self.origin[2] > v_valid_point[2] )
391  {
392  n_z_correct = self.origin[2] - v_valid_point[2];
393  }
394 
395  self.origin = v_valid_point + ( 0, 0, n_z_correct );
396  self.navmesh_check = true;
397  return;
398  }
399  self.navmesh_check = false;
400 }
401 
402 function ‪animate_octobomb( is_upgraded )
403 {
404  self endon( "death" );
405 
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 );
409 
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 );
413 
414  wait n_life_time * .75;
415 
416  if ( is_upgraded )
417  {
418  n_fx = ‪CF_OCTOBOMB_UG_FX;
419  }
420  else
421  {
422  n_fx = ‪CF_OCTOBOMB_FX;
423  }
424  self thread ‪clientfield::set( "octobomb_spit_fx", n_fx ); // with a quarter of Li'l Arnie's lifespan left, start spitting
425 
426  wait n_life_time * .25;
427 
428  self ‪scene::play( "p7_fxanim_zm_zod_octobomb_end_bundle", self.anim_model );
429 
430  self playsound( "wpn_octobomb_end" );
431 }
432 
433 #define NUM_TRIES 5
435 {
436  v_orig = self.origin;
437  n_angles = self.angles;
438  n_z_correct = 0.0; // Corrects for PositionQuery_Source_Navigation lowering Z positioning
439  queryResult = PositionQuery_Source_Navigation(
440  self.origin, // origin
441  0, // min radius
442  200, // max radius
443  100, // half height
444  2, // inner spacing
445  20 // radius from edges
446  );
447 
448  if ( queryResult.data.size )
449  {
450  foreach ( point in queryResult.data )
451  {
452  if ( BulletTracePassed( point.origin + ( 0, 0, 20 ), v_orig + ( 0, 0, 20 ), false, self, undefined, false, false ) )
453  {
454  if ( self.origin[2] > queryResult.origin[2] )
455  {
456  n_z_correct = self.origin[2] - queryResult.origin[2];
457  }
458  self.origin = point.origin + (0, 0, n_z_correct);
459  self.angles = n_angles;
460  break;
461  }
462  }
463  }
464 }
465 
466 
467 // if the player throws it to an unplayable area samantha steals it
468 function ‪grenade_stolen_by_sam( e_grenade )
469 {
470  if( !isdefined( e_grenade ) )
471  {
472  return;
473  }
474 
475  //ent_grenade notify( "sam_stole_it" );
476 
477  direction = e_grenade.origin;
478  direction = ( direction[ 1 ], direction[ 0 ], 0 );
479 
480  if ( direction[ 1 ] < 0 || ( direction[ 0 ] > 0 && direction[ 1 ] > 0 ) )
481  {
482  direction = ( direction[ 0 ], direction[ 1 ] * -1, 0 );
483  }
484  else if ( direction[ 0 ] < 0 )
485  {
486  direction = ( direction[ 0 ] * -1, direction[ 1 ], 0 );
487  }
488 
489  // Play laugh sound here, players should connect the laugh with the movement which will tell the story of who is moving it
490  if( !‪IS_TRUE(e_grenade.sndNoSamLaugh) )
491  {
492  players = GetPlayers();
493  for ( i = 0; i < players.size; i++ )
494  {
495  if ( IsAlive( players[ i ] ) )
496  {
497  players[ i ] PlayLocalSound( level.zmb_laugh_alias );
498  }
499  }
500  }
501 
502  // play the fx on the model
503  PlayFXOnTag( level._effect[ "grenade_samantha_steal" ], e_grenade, "tag_origin" );
504 
505  e_grenade.clone_model Unlink();
506 
507  // raise the model
508  e_grenade.clone_model MoveZ( 60, 1.0, 0.25, 0.25 );
509 
510  // spin it
511  e_grenade.clone_model Vibrate( direction, 1.5, 2.5, 1.0 );
512  e_grenade.clone_model waittill( "movedone" );
513 
514  if ( isdefined( self.damagearea ) )
515  {
516  self.damagearea Delete();
517  }
518 
519  e_grenade.clone_model Delete();
520 
521  if ( isdefined( e_grenade ) )
522  {
523  if ( isdefined( e_grenade.damagearea ) )
524  {
525  e_grenade.damagearea Delete();
526  }
527 
528  e_grenade Delete();
529  }
530 }
531 
533 {
534  while ( true )
535  {
536  if ( !isdefined( self ) )
537  {
538  if ( isdefined( self.clone_model ) )
539  {
540  self.clone_model Delete();
541  }
542 
543  if ( isdefined( self.anim_model ) )
544  {
545  self.anim_model Delete();
546  }
547 
548  if ( isdefined( self ) && ‪IS_TRUE( self.dud ) ) // wait for the screams to die out
549  {
550  wait 6;
551  }
552 
553  if ( isdefined( self.simulacrum ) )
554  {
555  self.simulacrum delete();
556  }
557 
559  return;
560  }
561 
563  }
564 }
565 
567 {
568  self waittill( "explode", position );
569  level notify( "grenade_exploded", position, 100, 5000, 450 );
570 
571  octobomb_index = -1;
572  for ( i = 0; i < level.octobombs.size; i++ )
573  {
574  if ( !isdefined( level.octobombs[ i ] ) )
575  {
576  octobomb_index = i;
577  break;
578  }
579  }
580 
581  if ( octobomb_index >= 0 )
582  {
583  ArrayRemoveIndex( level.octobombs, octobomb_index );
584  }
585 }
586 
587 // self == octobomb
588 function ‪do_tentacle_burst( e_player, is_upgraded )
589 {
590  self endon( "explode" );
591 
592  n_time_started = GetTime() / 1000;
593 
594  while ( true )
595  {
596  n_time_current = GetTime() / 1000;
597  n_time_elapsed = n_time_current - n_time_started;
598 
599  if ( n_time_elapsed < ‪OCTOBOMB_DAMAGE_GROWTH_DURATION )
600  {
601  n_radius = LerpFloat( 0, ‪OCTOBOMB_DAMAGE_RADIUS, n_time_elapsed / ‪OCTOBOMB_DAMAGE_GROWTH_DURATION );
602  }
603  else if ( n_time_elapsed == ‪OCTOBOMB_DAMAGE_GROWTH_DURATION )
604  {
605  n_radius = ‪OCTOBOMB_DAMAGE_RADIUS;
606  }
607 
608  a_ai_potential_targets = ‪zombie_utility::get_zombie_array();
609 
610  if ( isdefined( level.octobomb_targets ) )
611  {
612  a_ai_potential_targets = [[ level.octobomb_targets ]]( a_ai_potential_targets );
613  }
614 
615  a_ai_targets = ArraySortClosest( a_ai_potential_targets, self.origin, a_ai_potential_targets.size, 0, ‪OCTOBOMB_DAMAGE_RADIUS );
616 
617  foreach ( ai_target in a_ai_targets )
618  {
619  if ( IsAlive( ai_target ) )
620  {
621  ai_target thread ‪clientfield::set( "octobomb_tentacle_hit_fx", 1 );
622 
623  if ( ai_target.b_octobomb_infected !== true )
624  {
625  self notify( "sndKillVox" );
626 
627  ai_target playsound( "wpn_octobomb_zombie_imp" );
628  ai_target thread ‪zombie_explodes();
629  ai_target thread ‪zombie_spore_infect( e_player, self, is_upgraded );
630  }
631 
632  wait ‪SERVER_FRAME;
633 
634  ai_target thread ‪clientfield::set( "octobomb_tentacle_hit_fx", 0 );
635  }
636  }
638  }
639 }
640 
641 // DOT on zombie
642 // self is a zombie
643 function ‪zombie_spore_infect( e_player, e_grenade, is_upgraded )
644 {
645  self endon( "death" );
646 
647  self.octobomb_infected = true;
648  n_infection_time = 0;
649  n_infection_half_time = ‪OCTOBOMB_DAMAGE_TIME / 2;
650  n_burst_damage = 3;
651 
652  if ( is_upgraded )
653  {
654  n_damage = ‪OCTOBOMB_UG_DAMAGE_TICK;
655  n_spore_val = ‪CF_OCTOBOMB_UG_FX;
656  }
657  else
658  {
659  n_damage = ‪OCTOBOMB_DAMAGE_TICK;
660  n_spore_val = ‪CF_OCTOBOMB_FX;
661  }
662 
663  self ‪clientfield::set( "octobomb_spores_fx", n_spore_val );
664  while ( n_infection_time < ‪OCTOBOMB_DAMAGE_TIME )
665  {
667  n_infection_time++;
668 
669  // Initial burst damage
670  self DoDamage( n_damage * n_burst_damage, self.origin, e_player, e_grenade );
671  n_burst_damage = 1;
672  }
673  self.octobomb_infected = false;
674  self ‪clientfield::set( "octobomb_spores_fx", 0 );
675 }
676 
677 // If infected, zombie explodes on death
679 {
680  self waittill( "death" );
681  if ( isdefined(self) )
682  {
683  if ( self.octobomb_infected == true )
684  {
685  self ‪clientfield::increment( "octobomb_zombie_explode_fx", 1 );
686  self ‪octo_gib();
687  }
688  }
689 }
690 
691 // self == octobomb
692 function ‪do_tentacle_grab( e_player, is_upgraded ) // Randomly grabs farthest zombie with a time range of n_wait_grab
693 {
694  self endon( "death" );
695 
696  b_fast_grab = true; // Tracks if the octobomb immediately grabs the next targetR
697  n_grabs = 0; // Tracks consecutive fast grabs
698 
699  if ( is_upgraded )
700  {
701  n_spore_val = ‪CF_OCTOBOMB_UG_FX;
702  n_time_min = ‪OCTOBOMB_UG_GRAB_MIN_TIME;
703  n_time_max = ‪OCTOBOMB_UG_GRAB_MAX_TIME;
704  }
705  else
706  {
707  n_spore_val = ‪CF_OCTOBOMB_FX;
708  n_time_min = ‪OCTOBOMB_GRAB_MIN_TIME;
709  n_time_max = ‪OCTOBOMB_GRAB_MAX_TIME;
710  }
711 
712  while ( true )
713  {
714  if ( b_fast_grab == false )
715  {
716  n_wait_grab = RandomFloatRange( n_time_min, n_time_max );
717  }
718  else
719  {
720  n_wait_grab = 0.1;
721  }
722 
723  wait n_wait_grab;
724 
725  a_ai_potential_targets = ‪zombie_utility::get_zombie_array();
726 
727  if ( isdefined( level.octobomb_targets ) )
728  {
729  a_ai_potential_targets = [[ level.octobomb_targets ]]( a_ai_potential_targets );
730  }
731 
732  a_ai_targets = ArraySort( a_ai_potential_targets, self.origin, true, a_ai_potential_targets.size, ‪OCTOBOMB_GRAB_RADIUS );
733 
734  n_random_x = RandomFloatRange( -5, 5 );
735  n_random_y = RandomFloatRange( -5, 5 );
736 
737  if ( a_ai_targets.size > 0 )
738  {
739  ai_target = array::random( a_ai_targets );
740 
741  if ( IsAlive( ai_target ) )
742  {
743  ai_target ‪clientfield::set( "octobomb_spores_fx", n_spore_val );
744  self.octobomb_infected = true;
745 
746  self notify( "sndKillVox" );
747 
748  ai_target playsound( "wpn_octobomb_zombie_imp" );
749  ai_target ‪octo_gib();
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) ) );
753  }
754 
755  // 4+ on D6 roll to grab a second zombie. Becomes 5+, 6+, with each successful grab, then restarts
756  if ( RandomInt( 6 ) > ( n_grabs + 3 ) )
757  {
758  b_fast_grab = true;
759  n_grabs++;
760  }
761  else
762  {
763  b_fast_grab = false;
764  n_grabs = 0;
765  }
766  }
767  else
768  {
769  b_fast_grab = true;
770  }
771  }
772 }
773 
774 function ‪octo_gib()
775 {
776  gibserverutils::gibhead( self );
777 
778  if ( ‪math::cointoss() )
779  {
780  gibserverutils::gibleftarm( self );
781  }
782  else
783  {
784  gibserverutils::gibrightarm( self );
785  }
786 
787  gibserverutils::giblegs( self );
788 }
789 
790 // Spawn elemental/parasite attractor
791 function ‪special_attractor_spawn( e_player, max_attract_dist )
792 {
793  self endon ( "death" );
794  self MakeSentient();
795  self SetMaxHealth ( 1000 ) ;
796  self SetNormalHealth( 1 );
797 
798  self thread ‪parasite_attractor_grab( self );
799 
800  while ( true )
801  {
802  a_ai_zombies = array::get_all_closest( self.origin, getAITeamArray( level.zombie_team ), undefined, undefined, max_attract_dist * 1.5 );
803 
804  foreach ( ai_zombie in a_ai_zombies )
805  {
806  if ( IsVehicle( ai_zombie ) )
807  {
808  // Li'l Arnie attracts parasites (only does so after the parasites have done their spawn in FX)
809  if ( ai_zombie.archetype == ‪ARCHETYPE_PARASITE && ai_zombie.ignoreme !== true && ai_zombie ‪vehicle_ai::get_current_state() != "scripted" )
810  {
811  if ( !isdefined( self.v_parasite_attractor_center ) )
812  {
814  }
815  ai_zombie thread ‪parasite_variables( self );
816  ai_zombie thread ‪parasite_attractor( self );
817  continue;
818  }
819 
820  // Li'l Arnie attracts elementals
821  if ( ai_zombie.archetype == ‪ARCHETYPE_RAPS && ai_zombie.b_attracted_to_octobomb !== true )
822  {
823  ai_zombie thread ‪vehicle_attractor( self );
824  }
825 
826  // Li'l Arnie infects/DOTs elementals
827  if ( ai_zombie.archetype == ‪ARCHETYPE_RAPS && ai_zombie.octobomb_infected !== true && Distance( self.origin, ai_zombie.origin) <= ‪OCTOBOMB_DAMAGE_RADIUS )
828  {
829  ai_zombie thread ‪vehicle_attractor_damage( e_player );
830  }
831 
832  // Li'l Arnie infects/DOTs spiders
833  if ( ai_zombie.archetype == ‪ARCHETYPE_SPIDER && ai_zombie.octobomb_infected !== true && Distance( self.origin, ai_zombie.origin) <= ‪OCTOBOMB_DAMAGE_RADIUS )
834  {
835  ai_zombie thread ‪vehicle_attractor_damage( e_player );
836  }
837  }
838  }
839  wait ‪SERVER_FRAME;
840  }
841 }
842 
843 // Attracts Vehicles
844 function ‪vehicle_attractor( e_grenade )
845 {
846  self endon( "death" );
847 
848  self.favoriteenemy = e_grenade;
849  self.b_attracted_to_octobomb = true;
850  self.ignoreme = true;
851 
852  e_grenade waittill( "death" );
853 
854  self.b_attracted_to_octobomb = false;
855  self.ignoreme = false;
856 }
857 
858 // DOT on Vehicles
859 function ‪vehicle_attractor_damage( e_player )
860 {
861  self endon( "death" );
862 
863  self.octobomb_infected = true;
864  n_infection_time = 0;
865 
866  while ( n_infection_time < ‪OCTOBOMB_DAMAGE_TIME )
867  {
868  self DoDamage( ‪OCTOBOMB_DAMAGE_TICK, self.origin, e_player );
870  }
871  self.octobomb_infected = false;
872 }
873 
874 // Initializes Parasite attractor points
876 {
877  self.v_parasite_attractor_center = self.origin + (0, 0, ‪OCTOBOMB_PARASITE_ATTRACT_RADIUS);
878 
879  // Initialize attractor points
880  self.a_v_parasite_attractors = [];
881  ‪ARRAY_ADD( self.a_v_parasite_attractors, self.v_parasite_attractor_center + ( ‪OCTOBOMB_PARASITE_ATTRACT_RADIUS, 0, 0 ) );
882  ‪ARRAY_ADD( self.a_v_parasite_attractors, self.v_parasite_attractor_center + ( 0, ‪OCTOBOMB_PARASITE_ATTRACT_RADIUS, 0 ) );
883  ‪ARRAY_ADD( self.a_v_parasite_attractors, self.v_parasite_attractor_center + ( -‪OCTOBOMB_PARASITE_ATTRACT_RADIUS, 0, 0 ) );
884  ‪ARRAY_ADD( self.a_v_parasite_attractors, self.v_parasite_attractor_center + ( 0, -‪OCTOBOMB_PARASITE_ATTRACT_RADIUS, 0 ) );
885 }
886 
887 // Shuts off variables for surviving parasites
888 function ‪parasite_variables( e_grenade )
889 {
890  self endon( "death" );
891 
892  self.favoriteenemy = e_grenade;
893  self ‪vehicle_ai::set_state( "scripted" );
894  self.b_parasite_attracted = true;
895  self.ignoreme = true;
896  self.parasiteEnemy = e_grenade;
897  self ‪ai::set_ignoreall( true );
898 
899  e_grenade waittill( "death" );
900 
901  self ResumeSpeed();
902  self ‪vehicle_ai::set_state( "combat" );
903  self.b_parasite_attracted = false;
904  self.ignoreme = false;
905  self ‪ai::set_ignoreall( false );
906 }
907 
908 // Attract Parasites
909 function ‪parasite_attractor( e_grenade )
910 {
911  self endon( "death" );
912  e_grenade endon( "death" );
913 
914  f_speed = 10.0;
915 
916  if ( Distance( e_grenade.v_parasite_attractor_center, self.origin ) > ‪OCTOBOMB_PARASITE_ATTRACT_RADIUS )
917  {
918  self SetSpeed( 10 );
919  self SetVehGoalPos( e_grenade.v_parasite_attractor_center, false, true );
920  while ( Distance( e_grenade.v_parasite_attractor_center, self.origin ) > ‪OCTOBOMB_PARASITE_ATTRACT_RADIUS )
921  {
922  wait ‪SERVER_FRAME;
923  }
924  self ClearVehGoalPos();
925  }
926 
927  i = 0;
928  while( self.b_parasite_attracted )
929  {
930  // Resets array of attractors
931  if ( i == 4 )
932  {
933  i = 0;
934  }
935 
936  // Get as close as possible to the goal POS
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 )
939  {
940  if ( !self.b_parasite_attracted )
941  {
942  break;
943  }
944  wait ‪SERVER_FRAME;
945  }
946  self ClearVehGoalPos();
947 
948  i++;
949 
950  wait ‪SERVER_FRAME;
951  }
952 }
953 
954 // Grabs and flings parasites
955 function ‪parasite_attractor_grab( e_grenade )
956 {
957  e_grenade endon( "death" );
958  self endon( "death" );
959 
960  b_fast_grab = true;
961  n_grabs = 0;
962 
963  while ( true )
964  {
965  if ( b_fast_grab == false )
966  {
967  n_wait_grab = RandomFloatRange( ‪OCTOBOMB_GRAB_MIN_TIME, ‪OCTOBOMB_GRAB_MAX_TIME );
968  }
969  else
970  {
971  n_wait_grab = 0.1;
972  }
973  wait n_wait_grab;
974 
975  a_ai_parasites = array::get_all_closest( self.origin, getAITeamArray( level.zombie_team ), undefined, undefined, 150 );
976  i=0;
977  while (i < a_ai_parasites.size)
978  {
979  if ( isdefined( a_ai_parasites[i] ) && (a_ai_parasites[i].archetype != ‪ARCHETYPE_PARASITE) )
980  {
981  ArrayRemoveValue( a_ai_parasites, a_ai_parasites[i] );
982  i=0;
983  continue;
984  }
985  i++;
986  }
987 
988  if ( a_ai_parasites.size > 0 )
989  {
990  ai_parasite = array::random( a_ai_parasites );
991 
992  v_fling = VectorNormalize( ai_parasite.origin - e_grenade.origin );
993 
994  ai_parasite DoDamage( ai_parasite.maxhealth, self.origin );
995 
996  if ( RandomInt( 6 ) > ( n_grabs + 3 ) )
997  {
998  b_fast_grab = true;
999  n_grabs++;
1000  }
1001  else
1002  {
1003  b_fast_grab = false;
1004  n_grabs = 0;
1005  }
1006  }
1007  else
1008  {
1009  b_fast_grab = true;
1010  }
1011  }
1012 }
1013 
1015 {
1016  self endon( "explode" );
1017 
1018  while(1)
1019  {
1020  self waittill( "sndKillVox" );
1021  wait(.25);
1022  self playsound( "wpn_octobomb_attack_vox" );
1023  wait(2.5);
1024  }
1025 }
1026 
1028 {
1029  self endon( "death" );
1030  self endon( "starting_octobomb_watch" );
1031 
1032  while ( true )
1033  {
1034  self waittill( "grenade_fire", e_grenade, w_weapon );
1035  if ( w_weapon == level.w_octobomb || w_weapon == level.w_octobomb_upgraded )
1036  {
1037  e_grenade.use_grenade_special_long_bookmark = true;
1038  e_grenade.grenade_multiattack_bookmark_count = 1;
1039  e_grenade.weapon = w_weapon;
1040  return e_grenade;
1041  }
1042 
1044  }
1045 }
1046 
1048 {
1049  return ‪zm_weapons::is_weapon_included( level.w_octobomb );
1050 }
1051 
1052 // devgui so we can test the Octobomb
1053 // let the player give themselves the magic jar or the octobomb itself
1055 {
1056  for( i = 0; i < 4; i++ )
1057  {
1058  // devgui to give the octobomb to individual players
1059  level thread ‪setup_devgui_func( "ZM/Weapons/Offhand/Octobomb/Give" + i, "zod_give_octobomb", i, &‪devgui_octobomb_give );
1060  }
1061  // devgui to give the octobomb to ALL players
1062  level thread ‪setup_devgui_func( "ZM/Weapons/Offhand/Octobomb/Give to All", "zod_give_octobomb", 4, &‪devgui_octobomb_give );
1063 }
1064 
1065 function private ‪setup_devgui_func( str_devgui_path, str_dvar, n_value, func, n_base_value )
1066 {
1067  if( !isdefined( n_base_value ) )
1068  {
1069  n_base_value = -1;
1070  }
1071 
1072  SetDvar( str_dvar, n_base_value );
1073 
1074  AddDebugCommand( "devgui_cmd \"" + str_devgui_path + "\" \"" + str_dvar + " " + n_value + "\"\n" );
1075 
1076  // now watch the dvar
1077  while ( true )
1078  {
1079  n_dvar = GetDvarInt( str_dvar );
1080  if ( n_dvar > n_base_value )
1081  {
1082  // call the target func, then reset the dvar
1083  [[ func ]]( n_dvar );
1084  SetDvar( str_dvar, n_base_value );
1085  }
1086 
1088  }
1089 }
1090 
1091 function ‪devgui_octobomb_give( n_player_index )
1092 {
1093  players = GetPlayers();
1094 
1095  player = players[ n_player_index ];
1096  if( isdefined( player ) ) // give the activating player the octobomb
1097  {
1098  ‪octobomb_give( player );
1099  }
1100  else if( n_player_index === 4 ) // give all players the octobomb
1101  {
1102  foreach( player in players )
1103  {
1104  ‪octobomb_give( player );
1105  }
1106  }
1107 }
1108 
1109 function ‪octobomb_give( player )
1110 {
1111  player ‪clientfield::set_to_player( "octobomb_state", 3 );
1112 
1113  weapon = GetWeapon( ‪STR_WEAP_OCTOBOMB );
1114  player TakeWeapon( weapon ); // take away if it's already there, to make sure it replenishes properly
1115  player ‪zm_weapons::weapon_give( weapon, undefined, undefined, true );
1116 }
1117 
1118 
1119 
‪STR_WEAP_OCTOBOMB
‪#define STR_WEAP_OCTOBOMB
Definition: _zm_weap_octobomb.gsh:1
‪FakeLinkto
‪function FakeLinkto(linkee)
Definition: _zm_weap_octobomb.gsc:200
‪sndAttackVox
‪function sndAttackVox()
Definition: _zm_weap_octobomb.gsc:1014
‪set_state
‪function set_state(name, state_params)
Definition: statemachine_shared.gsc:133
‪animate_octobomb
‪function animate_octobomb(is_upgraded)
Definition: _zm_weap_octobomb.gsc:402
‪OCTOBOMB_DAMAGE_TICK
‪#define OCTOBOMB_DAMAGE_TICK
Definition: _zm_weap_octobomb.gsh:6
‪move_away_from_edges
‪function move_away_from_edges()
Definition: _zm_weap_octobomb.gsc:434
‪OCTOBOMB_UG_GRAB_MIN_TIME
‪#define OCTOBOMB_UG_GRAB_MIN_TIME
Definition: _zm_weap_octobomb.gsh:15
‪player_handle_octobomb
‪function player_handle_octobomb()
Definition: _zm_weap_octobomb.gsc:93
‪setup_devgui_func
‪function private setup_devgui_func(str_devgui_path, str_dvar, n_value, func, n_base_value)
Definition: _zm_weap_octobomb.gsc:1065
‪get_current_state
‪function get_current_state()
Definition: vehicle_ai_shared.gsc:960
‪set_to_player
‪function set_to_player(str_field_name, n_value)
Definition: clientfield_shared.gsc:58
‪create_zombie_point_of_interest
‪function create_zombie_point_of_interest(attract_dist, num_attractors, added_poi_value, start_turned_on, initial_attract_func, arrival_attract_func, poi_team)
Definition: _zm_utility.gsc:624
‪vehicle_attractor
‪function vehicle_attractor(e_grenade)
Definition: _zm_weap_octobomb.gsc:844
‪detonate
‪function detonate(attacker)
Definition: vehicle_ai_shared.gsc:1650
‪play
‪function play(animation, v_origin_or_ent, v_angles_or_tag, n_rate=1, n_blend_in=.2, n_blend_out=.2, n_lerp, b_link=false)
Definition: animation_shared.csc:44
‪is_on_navmesh
‪function is_on_navmesh()
Definition: _zm_weap_octobomb.gsc:374
‪VERSION_SHIP
‪#define VERSION_SHIP
Definition: version.gsh:36
‪STR_WEAP_OCTOBOMB_UPGRADED
‪#define STR_WEAP_OCTOBOMB_UPGRADED
Definition: _zm_weap_octobomb.gsh:2
‪cointoss
‪function cointoss()
Definition: math_shared.csc:171
‪OCTOBOMB_UG_DAMAGE_TICK
‪#define OCTOBOMB_UG_DAMAGE_TICK
Definition: _zm_weap_octobomb.gsh:14
‪special_attractor_spawn
‪function special_attractor_spawn(e_player, max_attract_dist)
Definition: _zm_weap_octobomb.gsc:791
‪player_give_octobomb
‪function player_give_octobomb(str_weapon=STR_WEAP_OCTOBOMB)
Definition: _zm_weap_octobomb.gsc:77
‪do_tentacle_burst
‪function do_tentacle_burst(e_player, is_upgraded)
Definition: _zm_weap_octobomb.gsc:588
‪self_delete
‪function self_delete()
Definition: _util.gsc:739
‪CF_OCTOBOMB_FX
‪#define CF_OCTOBOMB_FX
Definition: _zm_weap_octobomb.gsh:20
‪IS_TRUE
‪#define IS_TRUE(__a)
Definition: shared.gsh:251
‪check_point_in_enabled_zone
‪function check_point_in_enabled_zone(origin, zone_is_active, player_zones)
Definition: _zm_utility.gsc:512
‪get
‪function get(kvp_value, kvp_key="targetname")
Definition: struct.csc:13
‪OCTOBOMB_PARASITE_ATTRACT_RADIUS
‪#define OCTOBOMB_PARASITE_ATTRACT_RADIUS
Definition: _zm_weap_octobomb.gsh:18
‪is_weapon_included
‪function is_weapon_included(weapon)
Definition: _zm_weapons.csc:51
‪spawn_model
‪function spawn_model(n_client, str_model, origin=(0, 0, 0), angles=(0, 0, 0))
Definition: util_shared.csc:92
‪show_briefly
‪function show_briefly(showtime)
Definition: _zm_weap_octobomb.gsc:128
‪ARCHETYPE_PARASITE
‪#define ARCHETYPE_PARASITE
Definition: archetype_shared.gsh:38
‪CF_OCTOBOMB_UG_FX
‪#define CF_OCTOBOMB_UG_FX
Definition: _zm_weap_octobomb.gsh:21
‪hide_owner
‪function hide_owner(owner)
Definition: _zm_weap_octobomb.gsc:166
‪__main__
‪function __main__()
Definition: _zm_weap_octobomb.gsc:48
‪OCTOBOMB_DAMAGE_RADIUS
‪#define OCTOBOMB_DAMAGE_RADIUS
Definition: _zm_weap_octobomb.gsh:5
‪VERSION_TU8
‪#define VERSION_TU8
Definition: version.gsh:54
‪zombie_spore_infect
‪function zombie_spore_infect(e_player, e_grenade, is_upgraded)
Definition: _zm_weap_octobomb.gsc:643
‪parasite_attractor_init
‪function parasite_attractor_init()
Definition: _zm_weap_octobomb.gsc:875
‪player_throw_octobomb
‪function player_throw_octobomb(e_grenade, num_attractors, max_attract_dist, attract_dist_custom)
Definition: _zm_weap_octobomb.gsc:265
‪wait_for_attractor_positions_complete
‪function wait_for_attractor_positions_complete()
Definition: _zm_utility.gsc:5941
‪waittill_any_ex
‪function waittill_any_ex(...)
Definition: util_shared.csc:270
‪zombie_explodes
‪function zombie_explodes()
Definition: _zm_weap_octobomb.gsc:678
‪wait_network_frame
‪function wait_network_frame(n_count=1)
Definition: util_shared.gsc:64
‪check_octobomb_on_train
‪function check_octobomb_on_train()
Definition: _zm_weap_octobomb.gsc:249
‪octobomb_cleanup
‪function octobomb_cleanup()
Definition: _zm_weap_octobomb.gsc:532
‪get_thrown_octobomb
‪function get_thrown_octobomb()
Definition: _zm_weap_octobomb.gsc:1027
‪octobomb_devgui
‪function octobomb_devgui()
Definition: _zm_weap_octobomb.gsc:1054
‪set_player_tactical_grenade
‪function set_player_tactical_grenade(weapon)
Definition: _zm_utility.gsc:4250
‪REGISTER_SYSTEM_EX
‪#define REGISTER_SYSTEM_EX(__sys, __func_init_preload, __func_init_postload, __reqs)
Definition: shared.gsh:209
‪set_ignoreall
‪function set_ignoreall(val)
Definition: ai_shared.gsc:49
‪player_give_octobomb_upgraded
‪function player_give_octobomb_upgraded()
Definition: _zm_weap_octobomb.gsc:70
‪ARRAY_ADD
‪#define ARRAY_ADD(__array, __item)
Definition: shared.gsh:304
‪SERVER_FRAME
‪#define SERVER_FRAME
Definition: shared.gsh:264
‪create_zombie_point_of_interest_attractor_positions
‪function create_zombie_point_of_interest_attractor_positions(num_attract_dists, attract_dist)
Definition: _zm_utility.gsc:717
‪register_zombie_weapon_callback
‪function register_zombie_weapon_callback(weapon, func)
Definition: _zm_weapons.gsc:3317
‪ARCHETYPE_RAPS
‪#define ARCHETYPE_RAPS
Definition: archetype_shared.gsh:33
‪parasite_variables
‪function parasite_variables(e_grenade)
Definition: _zm_weap_octobomb.gsc:888
‪CF_OCTOBOMB_EXPLODE_FX
‪#define CF_OCTOBOMB_EXPLODE_FX
Definition: _zm_weap_octobomb.gsh:22
‪increment
‪function increment(str_field_name, n_increment_count=1)
Definition: clientfield_shared.gsc:110
‪OCTOBOMB_GRAB_MIN_TIME
‪#define OCTOBOMB_GRAB_MIN_TIME
Definition: _zm_weap_octobomb.gsh:10
‪ARCHETYPE_SPIDER
‪#define ARCHETYPE_SPIDER
Definition: archetype_shared.gsh:41
‪parasite_attractor_grab
‪function parasite_attractor_grab(e_grenade)
Definition: _zm_weap_octobomb.gsc:955
‪OCTOBOMB_DAMAGE_TIME
‪#define OCTOBOMB_DAMAGE_TIME
Definition: _zm_weap_octobomb.gsh:7
‪OCTOBOMB_GRAB_MAX_TIME
‪#define OCTOBOMB_GRAB_MAX_TIME
Definition: _zm_weap_octobomb.gsh:11
‪get_player_tactical_grenade
‪function get_player_tactical_grenade()
Definition: _zm_utility.gsc:4237
‪OCTOBOMB_DAMAGE_GROWTH_DURATION
‪#define OCTOBOMB_DAMAGE_GROWTH_DURATION
Definition: _zm_weap_octobomb.gsh:8
‪set
‪function set(str_field_name, n_value)
Definition: clientfield_shared.gsc:34
‪IS_EQUAL
‪#define IS_EQUAL(__a, __b)
Definition: shared.gsh:250
‪show_owner_on_attack
‪function show_owner_on_attack(owner)
Definition: _zm_weap_octobomb.gsc:148
‪OCTOBOMB_UG_GRAB_MAX_TIME
‪#define OCTOBOMB_UG_GRAB_MAX_TIME
Definition: _zm_weap_octobomb.gsh:16
‪player_is_in_laststand
‪function player_is_in_laststand()
Definition: laststand_shared.gsc:18
‪OCTOBOMB_DAMAGE_INTERVAL
‪#define OCTOBOMB_DAMAGE_INTERVAL
Definition: _zm_weap_octobomb.gsh:4
‪OCTOBOMB_GRAB_RADIUS
‪#define OCTOBOMB_GRAB_RADIUS
Definition: _zm_weap_octobomb.gsh:9
‪__init__
‪function __init__()
Definition: _zm_weap_octobomb.gsc:34
‪get_zombie_array
‪function get_zombie_array()
Definition: zombie_utility.gsc:2043
‪weapon_give
‪function weapon_give(weapon, is_upgrade=false, magic_box=false, nosound=false, b_switch_weapon=true)
Definition: _zm_weapons.gsc:2603
‪octo_gib
‪function octo_gib()
Definition: _zm_weap_octobomb.gsc:774
‪octobomb_exists
‪function octobomb_exists()
Definition: _zm_weap_octobomb.gsc:1047
‪register
‪function register()
Definition: _ai_tank.gsc:126
‪entity_in_zone
‪function entity_in_zone(zone_name, ignore_enabled_check=false)
Definition: _zm_zonemgr.gsc:214
‪devgui_octobomb_give
‪function devgui_octobomb_give(n_player_index)
Definition: _zm_weap_octobomb.gsc:1091
‪vehicle_attractor_damage
‪function vehicle_attractor_damage(e_player)
Definition: _zm_weap_octobomb.gsc:859
‪grenade_stolen_by_sam
‪function grenade_stolen_by_sam(e_grenade)
Definition: _zm_weap_octobomb.gsc:468
‪do_tentacle_grab
‪function do_tentacle_grab(e_player, is_upgraded)
Definition: _zm_weap_octobomb.gsc:692
‪do_octobomb_sound
‪function do_octobomb_sound()
Definition: _zm_weap_octobomb.gsc:566
‪parasite_attractor
‪function parasite_attractor(e_grenade)
Definition: _zm_weap_octobomb.gsc:909
‪grenade_planted
‪function grenade_planted(grenade, model)
Definition: _zm_weap_octobomb.gsc:214
‪octobomb_give
‪function octobomb_give(player)
Definition: _zm_weap_octobomb.gsc:1109
‪WAIT_SERVER_FRAME
‪#define WAIT_SERVER_FRAME
Definition: shared.gsh:265