‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
_destructible.gsc
Go to the documentation of this file.
1 #using scripts\shared\challenges_shared;
2 #using scripts\shared\clientfield_shared;
3 #using scripts\shared\system_shared;
4 #using scripts\shared\util_shared;
5 
6 #insert scripts\shared\shared.gsh;
7 #insert scripts\shared\version.gsh;
8 #insert scripts\mp\_destructible.gsh;
9 
10 #using scripts\mp\gametypes\_battlechatter;
11 #using scripts\mp\gametypes\_globallogic_player;
12 
13 #using scripts\mp\_challenges;
14 
15 #insert scripts\shared\clientfields.gsh;
16 
17 #namespace destructible;
18 
19 ‪REGISTER_SYSTEM( "destructible", &‪__init__, undefined )
20 
21 #using_animtree ( "mp_vehicles" );
22 
23 function ‪__init__()
24 {
26 
27  level.destructible_callbacks = [];
28  destructibles = GetEntArray( "destructible", "targetname" );
29 
30  // since this is globally run, only continue if we have a destructible in the level
31  if( destructibles.size <= 0 )
32  {
33  return;
34  }
35 
36  // array::thread_all( destructibles,&destructible_think );
37 
38  for ( i = 0; i < destructibles.size; i++ )
39  {
40  if ( GetSubStr( destructibles[i].destructibledef, 0, 4 ) == "veh_" )
41  {
42  destructibles[i] thread ‪car_death_think();
43  destructibles[i] thread ‪car_grenade_stuck_think();
44  }
45  else if ( destructibles[i].destructibledef == "fxdest_upl_metal_tank_01" )
46  {
47  destructibles[i] thread ‪tank_grenade_stuck_think();
48  }
49  }
50 
52 }
53 
55 {
56  level.explosion_manager = SpawnStruct();
57  level.explosion_manager.count = 0;
58  level.explosion_manager.a_explosions = [];
59 
60  i = 0;
61  while( i < 32 )
62  {
63  sExplosion = ‪Spawn( "script_model", (0,0,0) );
64  ‪ARRAY_ADD( level.explosion_manager.a_explosions, sExplosion );
65  i++;
66  }
67 }
68 
70 {
71  foreach( explosion in level.explosion_manager.a_explosions )
72  {
73  if( !‪IS_TRUE( explosion.in_use ) )
74  {
75  return explosion;
76  }
77  }
78  return level.explosion_manager.a_explosions[0];
79 }
80 
81 //assumes explosion radius will never be greater than 2 ^ ( DESTRUCTIBLE_CLIENTFIELD_NUM_BITS )
82 function ‪physics_explosion_and_rumble( origin, radius, physics_explosion )
83 {
84  sExplosion = ‪get_unused_explosion();
85  sExplosion.in_use = true;
86  sExplosion.origin = origin;
87 
88  assert( radius <= ‪pow( 2, ‪DESTRUCTIBLE_CLIENTFIELD_NUM_BITS ) - 1 );
89 
90  if( ‪IS_TRUE( physics_explosion ) )
91  {
92  radius += ( 1 << ( ‪DESTRUCTIBLE_CLIENTFIELD_NUM_BITS - 1 ) );
93  }
94 
96 
98 
99  sExplosion.in_use = false;
100 }
101 
102 function ‪event_callback( destructible_event, attacker, weapon ) // self == the destructible object (like the car or barrel)
103 {
104  explosion_radius = 0;
105  if(IsSubStr(destructible_event, "explode") && destructible_event != "explode")
106  {
107  tokens = StrTok(destructible_event, "_");
108  explosion_radius = tokens[1];
109 
110  if(explosion_radius == "sm")
111  {
112  explosion_radius = 150;
113  }
114  else if(explosion_radius == "lg")
115  {
116  explosion_radius = 450;
117  }
118  else
119  {
120  explosion_radius = Int(explosion_radius);
121  }
122 
123  destructible_event = "explode_complex"; // use a different explosion function
124  }
125 
126  if( IsSubStr( destructible_event, "explosive" ) )
127  {
128  tokens = StrTok(destructible_event, "_");
129  explosion_radius_type = tokens[3];
130 
131  if(explosion_radius_type == "small")
132  {
133  explosion_radius = 150;
134  }
135  else if(explosion_radius_type == "large")
136  {
137  explosion_radius = 450;
138  }
139  else
140  {
141  explosion_radius = 300;
142  }
143  }
144 
145  if ( IsSubStr( destructible_event, "simple_timed_explosion" ) )
146  {
147  self thread ‪simple_timed_explosion( destructible_event, attacker );
148  return;
149  }
150 
151  switch ( destructible_event )
152  {
153  case "destructible_car_explosion":
154  self ‪car_explosion( attacker );
155  if ( isdefined( weapon ) )
156  {
157  self.destroyingWeapon = weapon;
158  }
159  break;
160 
161  case "destructible_car_fire":
162  level thread ‪battlechatter::on_player_near_explodable( self, "car" );
163  self thread ‪car_fire_think(attacker);
164  if ( isdefined( weapon ) )
165  {
166  self.destroyingWeapon = weapon;
167  }
168  break;
169 
170  case "explode":
171  self thread ‪simple_explosion( attacker );
172  break;
173 
174  case "explode_complex":
175  self thread ‪complex_explosion( attacker, explosion_radius );
176  break;
177 
178  case "destructible_explosive_incendiary_small":
179  case "destructible_explosive_incendiary_large":
180  self ‪explosive_incendiary_explosion( attacker, explosion_radius, false );
181  if ( isdefined( weapon ) )
182  {
183  self.destroyingWeapon = weapon;
184  }
185  break;
186 
187  case "destructible_explosive_electrical_small":
188  case "destructible_explosive_electrical_large":
189  self ‪explosive_electrical_explosion( attacker, explosion_radius, false );
190  if ( isdefined( weapon ) )
191  {
192  self.destroyingWeapon = weapon;
193  }
194  break;
195 
196  case "destructible_explosive_concussive_small":
197  case "destructible_explosive_concussive_large":
198  self ‪explosive_concussive_explosion( attacker, explosion_radius, false );
199  if ( isdefined( weapon ) )
200  {
201  self.destroyingWeapon = weapon;
202  }
203  break;
204 
205  default:
206  //iprintln( "_destructible.gsc: unknown destructible event: '" + destructible_event + "'" );
207  break;
208  }
209 
210  if ( isdefined( level.destructible_callbacks[ destructible_event ] ) )
211  {
212  self thread [[level.destructible_callbacks[ destructible_event ]]]( destructible_event, attacker, weapon );
213  }
214 }
215 
216 function ‪simple_explosion( attacker )
217 {
218  if ( ‪IS_TRUE( self.exploded ) )
219  {
220  return;
221  }
222 
223  self.exploded = true;
224 
225  offset = (0, 0, 5);
226  self RadiusDamage( self.origin + offset, 256, 300, 75, attacker, "MOD_EXPLOSIVE", GetWeapon( "explodable_barrel" ) );
227  ‪physics_explosion_and_rumble( self.origin, 255, true );
228 
229  if ( isdefined( attacker ) )
230  {
231  self DoDamage( self.health + 10000, self.origin + offset, attacker );
232  }
233  else
234  {
235  self DoDamage( self.health + 10000, self.origin + offset );
236  }
237 }
238 
239 function ‪simple_timed_explosion( destructible_event, attacker )
240 {
241  self endon( "death" );
242 
243  wait_times = [];
244 
245  str = GetSubStr( destructible_event, 23 /* strlen( simple_timed_explosion ) */ );
246  tokens = StrTok( str, "_" );
247 
248  for ( i = 0; i < tokens.size; i++ )
249  {
250  wait_times[ wait_times.size ] = Int( tokens[i] );
251  }
252 
253  if ( wait_times.size <= 0 )
254  {
255  wait_times[ 0 ] = 5;
256  wait_times[ 1 ] = 10;
257  }
258 
259  wait( RandomIntRange( wait_times[0], wait_times[1] ) );
260  ‪simple_explosion( attacker );
261 }
262 
263 function ‪complex_explosion( attacker, max_radius )
264 {
265  offset = (0, 0, 5);
266 
267  if( isdefined( attacker ) )
268  {
269  self RadiusDamage( self.origin + offset, max_radius, 300, 100, attacker );
270  }
271  else
272  {
273  self RadiusDamage( self.origin + offset, max_radius, 300, 100 );
274  }
275 
276  ‪physics_explosion_and_rumble( self.origin, max_radius, true );
277  if( isdefined( attacker ) )
278  {
279  self DoDamage( 20000, self.origin + offset, attacker );
280  }
281  else
282  {
283  self DoDamage( 20000, self.origin + offset );
284  }
285 }
286 
287 
288 function ‪car_explosion( attacker, physics_explosion )
289 {
290  if ( isdefined( self.car_dead ) && self.car_dead )
291  {
292  // prevents recursive entry caused by DoDamage call below
293  return;
294  }
295 
296  if ( !isdefined( physics_explosion ) )
297  {
298  physics_explosion = true;
299  }
300 
301  self notify( "car_dead" );
302  self.car_dead = true;
303 
304  if ( isdefined( attacker ))
305  {
306  self RadiusDamage( self.origin, 256, 300, 75, attacker, "MOD_EXPLOSIVE", GetWeapon( "destructible_car" ) );
307  }
308  else
309  {
310  self RadiusDamage( self.origin, 256, 300, 75 );
311  }
312 
313  ‪physics_explosion_and_rumble( self.origin, 255, physics_explosion );
314 
315  if ( isdefined ( attacker ) )
316  attacker thread ‪challenges::destroyed_car();
317 
318  level.globalCarsDestroyed++;
319  if ( isdefined ( attacker ) )
320  {
321  self DoDamage( self.health + 10000, self.origin + (0, 0, 1), attacker );
322  }
323  else
324  {
325  self DoDamage( self.health + 10000, self.origin + (0, 0, 1));
326  }
327 
328  self MarkDestructibleDestroyed();
329 }
330 
332 {
333  self endon( "destructible_base_piece_death" );
334  self endon( "death" );
335 
336  for ( ;; )
337  {
338  self waittill( "grenade_stuck", missile );
339 
340  if ( !IsDefined( missile ) || !IsDefined( missile.model ) )
341  {
342  continue;
343  }
344 
345  if ( missile.model == "t5_weapon_crossbow_bolt" || missile.model == "t6_wpn_grenade_semtex_projectile" || missile.model == "wpn_t7_c4_world" )
346  {
347  self thread ‪tank_grenade_stuck_explode( missile );
348  }
349  }
350 }
351 
352 function ‪tank_grenade_stuck_explode( missile )
353 {
354  self endon( "destructible_base_piece_death" );
355  self endon( "death" );
356 
357  owner = GetMissileOwner( missile );
358 
359  if ( IsDefined( owner ) && missile.model == "wpn_t7_c4_world" )
360  {
361  owner endon( "disconnect" );
362  owner endon( "weapon_object_destroyed" );
363  missile endon( "picked_up" );
364 
365  missile thread ‪tank_hacked_c4( self );
366  }
367 
368  missile waittill( "explode" );
369 
370  if ( IsDefined( owner ) )
371  {
372  self DoDamage( self.health + 10000, self.origin + (0, 0, 1), owner );
373  }
374  else
375  {
376  self DoDamage( self.health + 10000, self.origin + (0, 0, 1) );
377  }
378 }
379 
380 function ‪tank_hacked_c4( tank )
381 {
382  tank endon( "destructible_base_piece_death" );
383  tank endon( "death" );
384  self endon( "death" );
385 
386  self waittill( "hacked" );
387 
388  self notify( "picked_up" );
389  tank thread ‪tank_grenade_stuck_explode( self );
390 }
391 
393 {
394  self endon( "car_dead" );
395  self.car_dead = false;
396 
397  self thread ‪car_death_notify();
398 
399  self waittill( "destructible_base_piece_death", attacker );
400 
401  if ( isdefined( self ) )
402  {
403  self thread ‪car_explosion( attacker, false );
404  }
405 }
406 
408 {
409  self endon( "destructible_base_piece_death" );
410  self endon( "car_dead" );
411  self endon( "death" );
412 
413  for ( ;; )
414  {
415  self waittill( "grenade_stuck", missile );
416 
417  if ( !isdefined( missile ) || !isdefined( missile.model ) )
418  {
419  continue;
420  }
421 
422  if ( missile.model == "t5_weapon_crossbow_bolt" || missile.model == "t6_wpn_grenade_semtex_projectile" || missile.model == "wpn_t7_c4_world" )
423  {
424  self thread ‪car_grenade_stuck_explode( missile );
425  }
426  }
427 }
428 
429 function ‪car_grenade_stuck_explode( missile )
430 {
431  self endon( "destructible_base_piece_death" );
432  self endon( "car_dead" );
433  self endon( "death" );
434 
435  owner = GetMissileOwner( missile );
436 
437  if ( isdefined( owner ) && missile.model == "wpn_t7_c4_world" )
438  {
439  owner endon( "disconnect" );
440  owner endon( "weapon_object_destroyed" );
441  missile endon( "picked_up" );
442 
443  missile thread ‪car_hacked_c4( self );
444  }
445 
446  missile waittill( "explode" );
447 
448  if ( isdefined( owner ) )
449  {
450  self DoDamage( self.health + 10000, self.origin + (0, 0, 1), owner );
451  }
452  else
453  {
454  self DoDamage( self.health + 10000, self.origin + (0, 0, 1) );
455  }
456 }
457 
458 function ‪car_hacked_c4( car )
459 {
460  car endon( "destructible_base_piece_death" );
461  car endon( "car_dead" );
462  car endon( "death" );
463  self endon( "death" );
464 
465  self waittill( "hacked" );
466 
467  self notify( "picked_up" );
468  car thread ‪car_grenade_stuck_explode( self );
469 }
470 
472 {
473  self endon( "car_dead" );
474 
475  self waittill( "death", attacker );
476  self notify( "destructible_base_piece_death", attacker );
477 }
478 
479 function ‪car_fire_think(attacker)
480 {
481  self endon( "death" );
482 
483  wait( RandomIntRange( 7, 10 ) );
484 
485  self thread ‪car_explosion( attacker );
486 }
487 
488 function ‪CodeCallback_DestructibleEvent( event, param1, param2, param3, param4 )
489 {
490  if( event == "broken" )
491  {
492  notify_type = param1;
493  attacker = param2;
494  piece = param3;
495  weapon = param4;
496 
497  ‪event_callback( notify_type, attacker, weapon );
498 
499  self notify( event, notify_type, attacker );
500  }
501  else if( event == "breakafter" )
502  {
503  piece = param1;
504  time = param2;
505  ‪damage = param3;
506  self thread ‪breakAfter( time, ‪damage, piece );
507  }
508 }
509 
510 function ‪breakAfter( time, ‪damage, piece )
511 {
512  self notify( "breakafter" );
513  self endon( "breakafter" );
514 
515  wait time;
516 
517  // this does not work in mp. DoDamage does not take a piece for mp.
518  self dodamage( ‪damage, self.origin, undefined, /*piece*/undefined );
519 }
520 
521 function ‪explosive_incendiary_explosion( attacker, explosion_radius, physics_explosion )
522 {
523  if ( !IsVehicle( self ) )
524  {
525  offset = (0, 0, 5);
526  if ( isdefined( attacker ))
527  {
528  self RadiusDamage( self.origin + offset, explosion_radius, 256, 75, attacker, "MOD_BURNED", GetWeapon( "incendiary_fire" ) );
529  }
530  else
531  {
532  self RadiusDamage( self.origin + offset, explosion_radius, 256, 75 );
533  }
534  ‪physics_explosion_and_rumble( self.origin, 255, physics_explosion );
535 
536  }
537 
538 
539  // delete the clip that is attached
540  if( isdefined( self.target ) )
541  {
542  dest_clip = GetEnt( self.target, "targetname" );
543  if( isDefined( dest_clip ) )
544  {
545  dest_clip delete();
546  }
547  }
548 
549  self MarkDestructibleDestroyed();
550 }
551 
552 function ‪explosive_electrical_explosion( attacker, explosion_radius, physics_explosion )
553 {
554  if ( !IsVehicle( self ) )
555  {
556  offset = (0, 0, 5);
557  if ( isdefined( attacker ))
558  {
559  self RadiusDamage( self.origin + offset, explosion_radius, 256, 75, attacker, "MOD_ELECTROCUTED" );
560  }
561  else
562  {
563  self RadiusDamage( self.origin + offset, explosion_radius, 256, 75 );
564  }
565  ‪physics_explosion_and_rumble( self.origin, 255, physics_explosion );
566  }
567 
568 
569  // delete the clip that is attached
570  if( isdefined( self.target ) )
571  {
572  dest_clip = GetEnt( self.target, "targetname" );
573  if( isDefined( dest_clip ) )
574  {
575  dest_clip delete();
576  }
577  }
578 
579  self MarkDestructibleDestroyed();
580 }
581 
582 function ‪explosive_concussive_explosion( attacker, explosion_radius, physics_explosion )
583 {
584  if ( !IsVehicle( self ) )
585  {
586  offset = (0, 0, 5);
587  if ( isdefined( attacker ))
588  {
589  self RadiusDamage( self.origin + offset, explosion_radius, 256, 75, attacker, "MOD_GRENADE" );
590  }
591  else
592  {
593  self RadiusDamage( self.origin + offset, explosion_radius, 256, 75 );
594  }
595  ‪physics_explosion_and_rumble( self.origin, 255, physics_explosion );
596  }
597 
598 
599  // delete the clip that is attached
600  if( isdefined( self.target ) )
601  {
602  dest_clip = GetEnt( self.target, "targetname" );
603  if( isDefined( dest_clip ) )
604  {
605  dest_clip delete();
606  }
607  }
608 
609  self MarkDestructibleDestroyed();
610 }
‪__init__
‪function __init__()
Definition: _destructible.gsc:23
‪simple_explosion
‪function simple_explosion(attacker)
Definition: _destructible.gsc:216
‪breakAfter
‪function breakAfter(time, damage, piece)
Definition: _destructible.gsc:510
‪explosive_concussive_explosion
‪function explosive_concussive_explosion(attacker, explosion_radius, physics_explosion)
Definition: _destructible.gsc:582
‪VERSION_SHIP
‪#define VERSION_SHIP
Definition: version.gsh:36
‪DESTRUCTIBLE_CLIENTFIELD_NUM_BITS
‪#define DESTRUCTIBLE_CLIENTFIELD_NUM_BITS
Definition: _destructible.gsh:2
‪on_player_near_explodable
‪function on_player_near_explodable(object, type)
Definition: _battlechatter.gsc:370
‪IS_TRUE
‪#define IS_TRUE(__a)
Definition: shared.gsh:251
‪get_unused_explosion
‪function get_unused_explosion()
Definition: _destructible.gsc:69
‪car_death_notify
‪function car_death_notify()
Definition: _destructible.gsc:471
‪destroyed_car
‪function destroyed_car()
Definition: challenges_shared.gsc:589
‪damage
‪function damage(trap)
Definition: _zm_trap_electric.gsc:116
‪pow
‪function pow(base, exp)
Definition: math_shared.gsc:544
‪explosive_incendiary_explosion
‪function explosive_incendiary_explosion(attacker, explosion_radius, physics_explosion)
Definition: _destructible.gsc:521
‪complex_explosion
‪function complex_explosion(attacker, max_radius)
Definition: _destructible.gsc:263
‪DESTRUCTIBLE_CLIENTFIELD
‪#define DESTRUCTIBLE_CLIENTFIELD
Definition: _destructible.gsh:1
‪car_grenade_stuck_explode
‪function car_grenade_stuck_explode(missile)
Definition: _destructible.gsc:429
‪tank_grenade_stuck_explode
‪function tank_grenade_stuck_explode(missile)
Definition: _destructible.gsc:352
‪ARRAY_ADD
‪#define ARRAY_ADD(__array, __item)
Definition: shared.gsh:304
‪REGISTER_SYSTEM
‪#define REGISTER_SYSTEM(__sys, __func_init_preload, __reqs)
Definition: shared.gsh:204
‪Spawn
‪function Spawn(parent, onDeathCallback)
Definition: _flak_drone.gsc:427
‪car_hacked_c4
‪function car_hacked_c4(car)
Definition: _destructible.gsc:458
‪physics_explosion_and_rumble
‪function physics_explosion_and_rumble(origin, radius, physics_explosion)
Definition: _destructible.gsc:82
‪car_grenade_stuck_think
‪function car_grenade_stuck_think()
Definition: _destructible.gsc:407
‪set
‪function set(str_field_name, n_value)
Definition: clientfield_shared.gsc:34
‪car_explosion
‪function car_explosion(attacker, physics_explosion)
Definition: _destructible.gsc:288
‪car_fire_think
‪function car_fire_think(attacker)
Definition: _destructible.gsc:479
‪explosive_electrical_explosion
‪function explosive_electrical_explosion(attacker, explosion_radius, physics_explosion)
Definition: _destructible.gsc:552
‪init_explosions
‪function init_explosions()
Definition: _destructible.gsc:54
‪register
‪function register()
Definition: _ai_tank.gsc:126
‪tank_hacked_c4
‪function tank_hacked_c4(tank)
Definition: _destructible.gsc:380
‪CodeCallback_DestructibleEvent
‪function CodeCallback_DestructibleEvent(event, param1, param2, param3, param4)
Definition: _destructible.gsc:488
‪car_death_think
‪function car_death_think()
Definition: _destructible.gsc:392
‪simple_timed_explosion
‪function simple_timed_explosion(destructible_event, attacker)
Definition: _destructible.gsc:239
‪event_callback
‪function event_callback(destructible_event, attacker, weapon)
Definition: _destructible.gsc:102
‪tank_grenade_stuck_think
‪function tank_grenade_stuck_think()
Definition: _destructible.gsc:331
‪WAIT_SERVER_FRAME
‪#define WAIT_SERVER_FRAME
Definition: shared.gsh:265