‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
_globallogic_vehicle.gsc
Go to the documentation of this file.
1 #using scripts\codescripts\struct;
2 
3 #using scripts\shared\damagefeedback_shared;
4 #using scripts\shared\spawner_shared;
5 #using scripts\shared\vehicle_shared;
6 #using scripts\shared\weapons\_weapons;
7 
8 #insert scripts\shared\shared.gsh;
9 
10 #using scripts\mp\gametypes\_globallogic_player;
11 #using scripts\mp\gametypes\_loadout;
12 #using scripts\mp\killstreaks\_killstreak_bundles;
13 #using scripts\mp\killstreaks\_killstreaks;
14 
15 #using scripts\mp\_vehicle;
16 
17 #namespace globallogic_vehicle;
18 
19 function ‪Callback_VehicleSpawned( spawner )
20 {
21  self.health = self.healthdefault;
22 
23  if ( IsSentient( self ) )
24  {
25  self ‪spawner::spawn_think( spawner );
26  }
27  else
28  {
29  ‪vehicle::init( self );
30  }
31 
32  if ( isdefined( level.vehicle_main_callback ) )
33  {
34  if( isdefined( level.vehicle_main_callback[ self.vehicleType ] ) )
35  {
36  self thread [[level.vehicle_main_callback[ self.vehicleType ]]]();
37  }
38  else if( isdefined( self.scriptVehicleType ) && isdefined( level.vehicle_main_callback[ self.scriptVehicleType ] ) )
39  {
40  self thread [[level.vehicle_main_callback[ self.scriptVehicleType ]]]();
41  }
42  }
43 }
44 
45 function ‪Callback_VehicleDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal )
46 {
47  selfEntNum = self getEntityNumber(); // need to cache off as "self" will become a removed entity after finishVehicleDamage executes.
48  eAttackerNotSelf = ( isdefined( eAttacker ) && ( eAttacker != self ) );
49  eAttackerIsNotOwner = ( isdefined( eAttacker ) && isdefined( self.owner ) && ( eAttacker != self.owner ) );
50  tryToDoDamageFeedback = !isdefined( self.noDamageFeedback ) || !self.noDamageFeedback;
51 
52  // already applied in the Callback_VehicleDamage
53  if ( !(‪IDFLAGS_RADIUS & iDFlags) )
54  {
55  // create a class specialty checks; CAC:bulletdamage, CAC:armorvest
56  iDamage = ‪loadout::cac_modified_vehicle_damage( self, eAttacker, iDamage, sMeansOfDeath, weapon, eInflictor );
57  }
58 
59  self.iDFlags = iDFlags;
60  self.iDFlagsTime = getTime();
61 
62  if ( game["state"] == "postgame" )
63  {
64  // at the end of a game, all vehicles should explode without any game logic firing off
65  self finishVehicleDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, damageFromUnderneath, modelIndex, partName, false);
66  return;
67  }
68 
69  if ( isdefined( eAttacker ) && isPlayer( eAttacker ) && isdefined( eAttacker.canDoCombat ) && !eAttacker.canDoCombat )
70  return;
71 
72  if ( self ‪weapons::should_suppress_damage( weapon, eInflictor ) )
73  return;
74 
75  if ( isdefined( self.overrideVehicleDamage ) )
76  {
77  iDamage = self [[self.overrideVehicleDamage]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal );
78  }
79  else if ( isdefined( level.overrideVehicleDamage ) )
80  {
81  iDamage = self [[level.overrideVehicleDamage]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal );
82  }
83 
84  assert(isdefined(iDamage), "You must return a value from a damage override function.");
85 
86  if( iDamage == 0 )
87  return;
88 
89  // Don't do knockback if the damage direction was not specified
90  if( !isdefined( vDir ) )
91  iDFlags |= ‪IDFLAGS_NO_KNOCKBACK;
92 
93  if ( ( isdefined( self.maxhealth ) && (self.health == self.maxhealth)) || !isdefined( self.attackers ) )
94  {
95  self.attackers = [];
96  self.attackerData = [];
97  self.attackerDamage = [];
98  }
99 
100  // explosive barrel/car detection
101  if ( weapon == level.weaponNone && isdefined( eInflictor ) )
102  {
103  if ( isdefined( eInflictor.targetname ) && eInflictor.targetname == "explodable_barrel" )
104  weapon = GetWeapon( "explodable_barrel" );
105  else if ( isdefined( eInflictor.destructible_type ) && isSubStr( eInflictor.destructible_type, "vehicle_" ) )
106  weapon = GetWeapon( "destructible_car" );
107  }
108 
109 
110  // check for completely getting out of the damage
111  if( !(iDFlags & ‪IDFLAGS_NO_PROTECTION) )
112  {
113  if ( self IsVehicleImmuneToDamage( iDFlags, sMeansOfDeath, weapon ) )
114  {
115  return;
116  }
117 
118  // This handles direct damage only. Splash is done in VehicleRadiusDamage
119  if ( sMeansOfDeath == "MOD_PROJECTILE" || sMeansOfDeath == "MOD_GRENADE" )
120  {
121  iDamage *= weapon.vehicleProjectileDamageScalar;
122  iDamage = int(iDamage);
123 
124  if ( iDamage == 0 )
125  {
126  return;
127  }
128  }
129  // Except for splash that we want to modify additionally based on "underneath"
130  else if ( sMeansOfDeath == "MOD_GRENADE_SPLASH" )
131  {
132  iDamage *= ‪GetVehicleUnderneathSplashScalar( weapon );
133  iDamage = int(iDamage);
134 
135  if ( iDamage == 0 )
136  {
137  return;
138  }
139  }
140 
141  iDamage *= level.vehicleDamageScalar;
142  iDamage = int(iDamage);
143 
144  if ( isPlayer( eAttacker ) )
145  eAttacker.pers["participation"]++;
146 
147  if( !IsDefined( self.maxhealth ) )
148  {
149  self.maxhealth = self.healthdefault; // healthdefault if from the GDT
150  }
151 
152  prevHealthRatio = self.health / self.maxhealth;
153 
154  if ( isdefined( self.owner ) && IsPlayer(self.owner) )
155  {
156  team = self.owner.pers["team"];
157  }
158  else
159  {
160  team = self vehicle::vehicle_get_occupant_team();
161  }
162 
163  if ( level.teamBased && isPlayer( eAttacker ) && (team == eAttacker.pers["team"]) )
164  {
165  // do not use level.friendlyfire per design as it allows for griefing
166  // we still need to ask though so that killstreaks can self destruct as needed
167  if( !‪AllowFriendlyFireDamage( eInflictor, eAttacker, sMeansOfDeath, weapon ) )
168  return;
169 
170  self.lastDamageWasFromEnemy = false;
171  self finishVehicleDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, damageFromUnderneath, modelIndex, partName, false);
172  }
173  else if( !level.hardcoreMode && isdefined( self.owner ) && isdefined( eAttacker ) && isdefined( eAttacker.owner ) && ( self.owner == eAttacker.owner ) && ( self != eAttacker ) )
174  {
175  //don't allow your killstreaks to kill your other killstreaks
176  return;
177  }
178  else
179  {
180  if ( !level.teamBased && isdefined( self.archetype ) && self.archetype == "raps" )
181  {
182  // allow raps to be damaged by owners in FFA games
183  }
184  else if ( !level.teamBased && isdefined( self.targetname ) && self.targetname == "rcbomb" )
185  {
186  // allow the rc bomb to be damaged by owners in FFA games (DT 75676)
187  }
188  else if ( isdefined( self.owner ) && isdefined( eAttacker ) && self.owner == eAttacker )
189  {
190  return;
191  }
192 
193  // Make sure at least one point of damage is done
194  if(iDamage < 1)
195  iDamage = 1;
196 
197  if ( issubstr( sMeansOfDeath, "MOD_GRENADE" ) && isdefined( eInflictor ) && isdefined( eInflictor.isCooked ) )
198  self.wasCooked = getTime();
199  else
200  self.wasCooked = undefined;
201 
202  attacker_seat = undefined;
203  if ( isdefined( eAttacker ) )
204  attacker_seat = self GetOccupantSeat( eAttacker );
205 
206  self.lastDamageWasFromEnemy = (isdefined( eAttacker ) && !isdefined(attacker_seat));
207 
208  self ‪globallogic_player::giveAttackerAndInflictorOwnerAssist( eAttacker, eInflictor, iDamage, sMeansOfDeath, weapon );
209 
210  self finishVehicleDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, damageFromUnderneath, modelIndex, partName, false);
211 
212  // IMPORTANT NOTE: "self" is a removed entity from here on out!!!
213 
214  if ( level.gameType == "hack" && !weapon.isEmp )
215  {
216  iDamage = 0;
217  }
218  }
219 
220  if ( eAttackerNotSelf && ( eAttackerIsNotOwner || ( isdefined( self.selfDestruct ) && !self.selfDestruct ) || ( self.forceDamageFeedback === true ) ) )
221  {
222  if ( tryToDoDamageFeedback )
223  {
224  dofeedback = true;
225  if( isdefined( self.damageTaken ) && isdefined( self.maxhealth ) && self.damageTaken > self.maxhealth )
226  dofeedback = false;
227 
228  if( ‪IS_TRUE( self.shuttingDown ) )
229  dofeedback = false;
230 
231  if ( dofeedback && ‪damagefeedback::doDamageFeedback( weapon, eInflictor ) )
232  {
233  if ( iDamage > 0 )
234  eAttacker thread ‪damagefeedback::update( sMeansOfDeath, eInflictor );
235  }
236  }
237  }
238  }
239 
240  if(1) // self.sessionstate != "dead")
241  {
242  lpselfnum = selfEntNum;
243  lpselfteam = "";
244  lpattackerteam = "";
245 
246  if(isPlayer(eAttacker))
247  {
248  lpattacknum = eAttacker getEntityNumber();
249  lpattackGuid = eAttacker getGuid();
250  lpattackname = eAttacker.name;
251  lpattackerteam = eAttacker.pers["team"];
252  }
253  else
254  {
255  lpattacknum = -1;
256  lpattackGuid = "";
257  lpattackname = "";
258  lpattackerteam = "world";
259  }
260 
261  /#logPrint("VD;" + lpselfnum + ";" + lpselfteam + ";" + lpattackGuid + ";" + lpattacknum + ";" + lpattackerteam + ";" + lpattackname + ";" + weapon.name + ";" + iDamage + ";" + sMeansOfDeath + ";" + sHitLoc + "\n");#/
262  }
263 
264 }
265 
266 function ‪Callback_VehicleRadiusDamage( eInflictor, eAttacker, iDamage, fInnerDamage, fOuterDamage, iDFlags, sMeansOfDeath, weapon, vPoint, fRadius, fConeAngleCos, vConeDir, psOffsetTime )
267 {
268  // create a class specialty checks; CAC:bulletdamage, CAC:armorvest
269  iDamage = ‪loadout::cac_modified_vehicle_damage( self, eAttacker, iDamage, sMeansOfDeath, weapon, eInflictor );
270  fInnerDamage = ‪loadout::cac_modified_vehicle_damage( self, eAttacker, fInnerDamage, sMeansOfDeath, weapon, eInflictor );
271  fOuterDamage = ‪loadout::cac_modified_vehicle_damage( self, eAttacker, fOuterDamage, sMeansOfDeath, weapon, eInflictor );
272  self.iDFlags = iDFlags;
273  self.iDFlagsTime = getTime();
274 
275  if ( game["state"] == "postgame" )
276  return;
277 
278  if ( isdefined( eAttacker ) && isPlayer( eAttacker ) && isdefined( eAttacker.canDoCombat ) && !eAttacker.canDoCombat )
279  return;
280 
281  if ( isdefined( self.killstreakType ) )
282  {
283  maxhealth = ‪VAL( self.maxhealth, self.health );
284  ‪DEFAULT( maxhealth, 200 );
285  iDamage = self ‪killstreaks::OnDamagePerWeapon( self.killstreakType, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, maxhealth, undefined, maxhealth * 0.4, undefined, 0, undefined, true, 1.0 );
286  }
287 
288  // check for completely getting out of the damage
289  if( !(iDFlags & ‪IDFLAGS_NO_PROTECTION) )
290  {
291  if ( self IsVehicleImmuneToDamage( iDFlags, sMeansOfDeath, weapon ) )
292  {
293  return;
294  }
295 
296  // THIS HANDLES SPLASH DAMAGE ONLY. SPLASH IS DONE IN VehicleRadiusDamage
297  if ( sMeansOfDeath == "MOD_PROJECTILE_SPLASH" || sMeansOfDeath == "MOD_GRENADE_SPLASH" || sMeansOfDeath == "MOD_EXPLOSIVE" )
298  {
299  scalar = weapon.vehicleProjectileSplashDamageScalar;
300  iDamage = int(iDamage * scalar);
301  fInnerDamage = (fInnerDamage * scalar);
302  fOuterDamage = (fOuterDamage * scalar);
303 
304  if ( fInnerDamage == 0 )
305  {
306  return;
307  }
308  if ( iDamage < 1 )
309  {
310  iDamage = 1;
311  }
312  }
313 
314  occupant_team = self vehicle::vehicle_get_occupant_team();
315 
316  if ( level.teamBased && isPlayer( eAttacker ) && (occupant_team == eAttacker.pers["team"]) )
317  {
318  // do not use level.friendlyfire per design as it allows for griefing
319  // we still need to ask though so that killstreaks can self destruct as needed
320  if( !‪AllowFriendlyFireDamage( eInflictor, eAttacker, sMeansOfDeath, weapon ) )
321  return;
322 
323  self.lastDamageWasFromEnemy = false;
324  self finishVehicleRadiusDamage(eInflictor, eAttacker, iDamage, fInnerDamage, fOuterDamage, iDFlags, sMeansOfDeath, weapon, vPoint, fRadius, fConeAngleCos, vConeDir, psOffsetTime);
325  }
326  else if( !level.hardcoreMode && isdefined( self.owner ) && isdefined( eAttacker.owner ) && self.owner == eAttacker.owner )//don't allow your killstreaks to kill your other killstreaks
327  {
328  return;
329  }
330  else
331  {
332  // Make sure at least one point of damage is done
333  if(iDamage < 1)
334  iDamage = 1;
335 
336  self finishVehicleRadiusDamage(eInflictor, eAttacker, iDamage, fInnerDamage, fOuterDamage, iDFlags, sMeansOfDeath, weapon, vPoint, fRadius, fConeAngleCos, vConeDir, psOffsetTime);
337  }
338  }
339 }
340 
341 function ‪Callback_VehicleKilled( eInflictor, eAttacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime )
342 {
343  if ( game["state"] == "postgame" && ( !isdefined( self.selfDestruct ) || !self.selfDestruct ) )
344  {
345  if( isdefined( self.overrideVehicleDeathPostGame ) )
346  {
347  self [[self.overrideVehicleDeathPostGame]]( eInflictor, eAttacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime );
348  }
349  return;
350  }
351 
352  // do vehicle killed callback
353  // generally this should be used as system callback, and the callback "on_vehicle_killed" callback can be used by level script
354  if ( isdefined( self.overrideVehicleKilled ) )
355  {
356  self [[self.overrideVehicleKilled]]( eInflictor, eAttacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime );
357  }
358 
359  if( isdefined( self.overrideVehicleDeath ) )
360  {
361  self [[self.overrideVehicleDeath]]( eInflictor, eAttacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime );
362  }
363 }
364 
365 function ‪vehicleCrush()
366 {
367  self endon("disconnect");
368 
369  if(isdefined( level._effect ) && isdefined( level._effect["tanksquish"] ) )
370  {
371  PlayFX( level._effect["tanksquish"], self.origin + (0, 0, 30));
372  }
373 
374  self playsound( "chr_crunch" );
375 }
376 
377 // damage going through this function will have already passed through the
378 // GetVehicleProjectileSplashScalar so keep that in mind when adjusting values
380 {
381  if ( isdefined( self ) && isdefined( self.ignore_vehicle_underneath_splash_scalar ) )
382  return 1.0;
383 
384  if ( weapon.name == "satchel_charge" )
385  {
386  // canceling all splash scaling done by the other function
387  scale = 10.0;
388 
389  // making it really deadly
390  scale *= 3.0;
391  }
392  else
393  {
394  scale = 1.0;
395  }
396 
397  return scale;
398 }
399 
400 function ‪AllowFriendlyFireDamage( eInflictor, eAttacker, sMeansOfDeath, weapon )
401 {
402  if (isdefined( self.allowFriendlyFireDamageOverride ) )
403  {
404  return [[self.allowFriendlyFireDamageOverride]](eInflictor, eAttacker, sMeansOfDeath, weapon );
405  }
406 
407  return false;
408 }
‪IDFLAGS_RADIUS
‪#define IDFLAGS_RADIUS
Definition: shared.gsh:411
‪Callback_VehicleRadiusDamage
‪function Callback_VehicleRadiusDamage(eInflictor, eAttacker, iDamage, fInnerDamage, fOuterDamage, iDFlags, sMeansOfDeath, weapon, vPoint, fRadius, fConeAngleCos, vConeDir, psOffsetTime)
Definition: _globallogic_vehicle.gsc:266
‪Callback_VehicleDamage
‪function Callback_VehicleDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal)
Definition: _globallogic_vehicle.gsc:45
‪spawn_think
‪function spawn_think(spawner)
Definition: spawner_shared.gsc:504
‪Callback_VehicleSpawned
‪function Callback_VehicleSpawned(spawner)
Definition: _globallogic_vehicle.gsc:19
‪VAL
‪#define VAL(__var, __default)
Definition: shared.gsh:272
‪OnDamagePerWeapon
‪function OnDamagePerWeapon(killstreak_ref, attacker, damage, flags, type, weapon, max_health, destroyed_callback, low_health, low_health_callback, emp_damage, emp_callback, allow_bullet_damage, chargeLevel)
Definition: _killstreaks.gsc:2667
‪Callback_VehicleKilled
‪function Callback_VehicleKilled(eInflictor, eAttacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime)
Definition: _globallogic_vehicle.gsc:341
‪IS_TRUE
‪#define IS_TRUE(__a)
Definition: shared.gsh:251
‪giveAttackerAndInflictorOwnerAssist
‪function giveAttackerAndInflictorOwnerAssist(eAttacker, eInflictor, iDamage, sMeansOfDeath, weapon)
Definition: _globallogic_player.gsc:4233
‪IDFLAGS_NO_KNOCKBACK
‪#define IDFLAGS_NO_KNOCKBACK
Definition: shared.gsh:413
‪DEFAULT
‪#define DEFAULT(__var, __default)
Definition: shared.gsh:270
‪should_suppress_damage
‪function should_suppress_damage(weapon, inflictor)
Definition: _weapons.gsc:1905
‪GetVehicleUnderneathSplashScalar
‪function GetVehicleUnderneathSplashScalar(weapon)
Definition: _globallogic_vehicle.gsc:379
‪doDamageFeedback
‪function doDamageFeedback(weapon, eInflictor, iDamage, sMeansOfDeath)
Definition: damagefeedback_shared.gsc:423
‪cac_modified_vehicle_damage
‪function cac_modified_vehicle_damage(victim, attacker, damage, meansofdeath, weapon, inflictor)
Definition: _loadout.gsc:1276
‪vehicleCrush
‪function vehicleCrush()
Definition: _globallogic_vehicle.gsc:365
‪IDFLAGS_NO_PROTECTION
‪#define IDFLAGS_NO_PROTECTION
Definition: shared.gsh:425
‪init
‪function init()
Definition: struct.csc:1
‪update
‪function update()
Definition: _serversettings.gsc:71
‪AllowFriendlyFireDamage
‪function AllowFriendlyFireDamage(eInflictor, eAttacker, sMeansOfDeath, weapon)
Definition: _globallogic_vehicle.gsc:400