‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
antipersonnelguidance.gsc
Go to the documentation of this file.
1 #using scripts\codescripts\struct;
2 #using scripts\shared\array_shared;
3 #using scripts\shared\callbacks_shared;
4 #using scripts\shared\clientfield_shared;
5 #using scripts\shared\flagsys_shared;
6 #using scripts\shared\hud_util_shared;
7 #using scripts\shared\system_shared;
8 #using scripts\shared\util_shared;
9 #using scripts\shared\abilities\_ability_util;
10 
11 #insert scripts\shared\weapons\antipersonnelguidance.gsh;
12 #insert scripts\shared\shared.gsh;
13 #insert scripts\shared\version.gsh;
14 
15 #precache( "string", "MP_CANNOT_LOCKON_TO_TARGET" );
16 
17 #namespace singlelockap_guidance;
18 
19 #define MAX_SIMULTANEOUS_LOCKONS 1 //this number corresponds to a code define
20 
21 ‪REGISTER_SYSTEM( "singlelockap_guidance", &‪__init__, undefined )
22 
23 function ‪__init__()
24 {
26 }
27 
29 {
30  self endon( "disconnect" );
31 
32  self ‪ClearAPTarget();
33  thread ‪APToggleLoop();
34  self thread ‪APFiredNotify();
35 }
36 
37 function ‪ClearAPTarget( weapon, whom )
38 {
39  if (!IsDefined(self.multiLockList))
40  {
41  self.multiLockList=[];
42  }
43 
44  if (IsDefined(whom))
45  {
46  for(i=0;i<self.multiLockList.size;i++)
47  {
48  if (whom.apTarget == self.multiLockList[i].apTarget)
49  {
50  self.multiLockList[i].apTarget notify( "missile_unlocked" );
51  self notify( "stop_sound"+whom.apSoundId );
52  self WeaponLockRemoveSlot(i);
53  ArrayRemoveValue(self.multiLockList,whom,false);
54  break;
55  }
56  }
57  }
58  else
59  {
60  for(i=0;i<self.multiLockList.size;i++)
61  {
62  self.multiLockList[i].apTarget notify( "missile_unlocked" );
63  self notify( "stop_sound"+self.multiLockList[i].apSoundId );
64  }
65  self.multiLockList = [];
66  }
67 
68  if (self.multiLockList.size==0)
69  {
70  self StopRumble( "stinger_lock_rumble" );
71 
72  self WeaponLockRemoveSlot(-1);
73 
74  if (IsDefined(weapon))
75  {
76  if (IsDefined(weapon.lockonSeekerSearchSound))
77  self StopLocalSound( weapon.lockonSeekerSearchSound );
78  if (IsDefined(weapon.lockonSeekerLockedSound))
79  self StopLocalSound( weapon.lockonSeekerLockedSound );
80  }
81 
83  }
84 }
85 
86 
87 function ‪APFiredNotify()
88 {
89  self endon( "disconnect" );
90  self endon ( "death" );
91 
92  while ( true )
93  {
94  self waittill( "missile_fire", missile, weapon );
95 
96  if ( weapon.lockonType == "AP Single" )
97  {
98  foreach(target in self.multiLockList)
99  {
100  if( isdefined(target.apTarget) && target.apLockFinalized )
101  {
102  target.apTarget notify( "stinger_fired_at_me", missile, weapon, self );
103  }
104  }
105  }
106  }
107 }
108 
109 function ‪APToggleLoop()
110 {
111  self endon( "disconnect" );
112  self endon ( "death" );
113 
114  for (;;)
115  {
116  self waittill( "weapon_change", weapon );
117 
118  while ( weapon.lockonType == "AP Single" )
119  {
120  abort = false;
121 
122  while( !( self PlayerAds() == 1.0 ) )
123  {
125 
126  currentWeapon = self GetCurrentWeapon();
127  if ( currentWeapon.lockonType != "AP Single" )
128  {
129  abort = true;
130  break;
131  }
132  }
133 
134  if ( abort )
135  {
136  break;
137  }
138 
139  self thread ‪APLockLoop(weapon);
140 
141  while( ( self PlayerAds() == 1.0 ) )
142  {
144  }
145 
146  self notify( "ap_off" );
147  self ‪ClearAPTarget(weapon);
148 
149  weapon = self GetCurrentWeapon();
150  }
151  }
152 }
153 
154 function ‪APLockLoop(weapon)
155 {
156  self endon( "disconnect" );
157  self endon( "death" );
158  self endon( "ap_off" );
159 
160  lockLength = self getLockOnSpeed();
161  self.multiLockList = [];
162 
163  for (;;)
164  {
166 
167  //-------------------------
168  // Four possible states:
169  // No missile in the tube, so CLU will not search for targets.
170  // CLU has a lock.
171  // CLU is locking on to a target.
172  // CLU is searching for a target to begin locking on to.
173  //-------------------------
174 
175  do
176  {
177  done=true;
178  foreach(target in self.multiLockList)
179  {
180  if ( target.apLockFinalized )
181  {
182  if ( ! ‪IsStillValidTarget( weapon, target.apTarget ) )
183  {
184  self ‪ClearAPTarget(weapon, target);
185  //start over because the array has changed and it'll mess up foreach
186  done = false;
187  break;
188  }
189  }
190  }
191  }
192  while (!done);
193 
194 
195  inLockingState=false;
196 
197  do
198  {
199  done=true;
200  for(i=0;i<self.multiLockList.size;i++)
201  {
202  target=self.multiLockList[i];
203  if ( target.apLocking )
204  {
205  if ( ! ‪IsStillValidTarget( weapon, target.apTarget ) )
206  {
207  self ‪ClearAPTarget(weapon, target);
208  //start over because the array has changed and it'll mess up foreach
209  done=false;
210  break;
211  }
212 
213  inLockingState=true;
214 
215  timePassed = getTime() - target.apLockStartTime;
216  if ( timePassed < lockLength )
217  continue;
218 
219  assert( isdefined( target.apTarget ) );
220  target.apLockFinalized = true;
221  target.apLocking = false;
222  target.apLockPending = false;
223  self WeaponLockFinalize( target.apTarget, i );
224  self thread ‪SeekerSound( weapon.lockonSeekerLockedSound, weapon.lockonSeekerLockedSoundLoops, target.apSoundId );
225  target.apTarget notify( "missile_lock", self, weapon );
226  }
227  }
228  }
229  while (!done);
230 
231  //if anyone is in the locking state, then don't allow pending to change state to locking (this will make locking sequential)
232  if (!inLockingState)
233  {
234  do
235  {
236  done=true;
237  for(i=0;i<self.multiLockList.size;i++)
238  {
239  target=self.multiLockList[i];
240  if ( target.apLockPending )
241  {
242  if ( ! ‪IsStillValidTarget( weapon, target.apTarget ) )
243  {
244  self ‪ClearAPTarget(weapon, target);
245  //start over because the array has changed and it'll mess up foreach
246  done=false;
247  break;
248  }
249 
250  target.apLockStartTime = getTime();
251 
252  target.apLockFinalized = false;
253  target.apLockPending = false;
254  target.apLocking = true;
255 
256  self thread ‪SeekerSound( weapon.lockonSeekerSearchSound, weapon.lockonSeekerSearchSoundLoops, target.apSoundId );
257 
258  done=true;
259  break;
260  }
261  }
262  }
263  while (!done);
264  }
265 
266  if (self.multiLockList.size>=‪MAX_SIMULTANEOUS_LOCKONS)
267  {
268  continue;
269  }
270 
271  bestTarget = self ‪GetBestTarget(weapon);
272 
273  if ( !IsDefined(bestTarget) && self.multiLockList.size==0 )
274  {
276  continue;
277  }
278 
279  //append to the lock list if we have the space
280  if (IsDefined(bestTarget) && self.multiLockList.size<‪MAX_SIMULTANEOUS_LOCKONS)
281  {
282  self WeaponLockStart(bestTarget.apTarget,self.multiLockList.size);
283  self.multiLockList[self.multiLockList.size] = bestTarget;
284  }
285  }
286 }
287 
289 {
290  if( isdefined( self.LockOnCanceledMessage ) )
291  self.LockOnCanceledMessage ‪destroy();
292 }
293 
295 {
296  if( isdefined( self.LockOnCanceledMessage ) )
297  return;
298 
299  self.LockOnCanceledMessage = newclienthudelem( self );
300  self.LockOnCanceledMessage.fontScale = 1.25;
301  self.LockOnCanceledMessage.x = 0;
302  self.LockOnCanceledMessage.y = 50;
303  self.LockOnCanceledMessage.alignX = "center";
304  self.LockOnCanceledMessage.alignY = "top";
305  self.LockOnCanceledMessage.horzAlign = "center";
306  self.LockOnCanceledMessage.vertAlign = "top";
307  self.LockOnCanceledMessage.foreground = true;
308  self.LockOnCanceledMessage.hidewhendead = false;
309  self.LockOnCanceledMessage.hidewheninmenu = true;
310  self.LockOnCanceledMessage.archived = false;
311  self.LockOnCanceledMessage.alpha = 1.0;
312  self.LockOnCanceledMessage SetText( &"MP_CANNOT_LOCKON_TO_TARGET" );
313 }
314 
315 function ‪GetBestTarget(weapon)
316 {
317  playerTargets = GetPlayers();
318  vehicleTargets = target_getArray();
319  targetsAll = GetAITeamArray();
320  targetsAll = ArrayCombine(targetsAll, playerTargets, false, false);
321  targetsAll = ArrayCombine(targetsAll, vehicleTargets, false, false);
322  targetsValid = [];
323 
324  for ( idx = 0; idx < targetsAll.size; idx++ )
325  {
326  if ( level.teamBased ) //team based game modes
327  {
328  if ( isdefined(targetsAll[idx].team) && targetsAll[idx].team != self.team)
329  {
330  if ( self ‪InsideAPReticleNoLock( targetsAll[idx] ) )
331  {
332  if (self ‪LockSightTest(targetsAll[idx]))
333  {
334  targetsValid[targetsValid.size] = targetsAll[idx];
335  }
336  }
337  }
338  }
339  else
340  {
341  if( self ‪InsideAPReticleNoLock( targetsAll[idx] ) ) //Free for all
342  {
343  if( isdefined( targetsAll[idx].owner ) && self != targetsAll[idx].owner )
344  {
345  if (self ‪LockSightTest(targetsAll[idx]))
346  {
347  targetsValid[targetsValid.size] = targetsAll[idx];
348  }
349  }
350  }
351  }
352  }
353 
354  if ( targetsValid.size == 0 )
355  return undefined;
356 
357  //find the best target that isn't already in the list
358 
359  playerForward = AnglesToForward( self GetPlayerAngles());
360  dots=[];
361  for (i=0;i<targetsValid.size;i++)
362  {
363  newitem=spawnstruct();
364  newitem.index = i;
365  newitem.dot = VectorDot(playerForward,VectorNormalize(targetsValid[i].origin-self.origin));
366  array::insertion_sort(dots,&‪TargetInsertionSortCompare,newitem);
367  }
368 
369  index=0;
370  foreach(dot in dots)
371  {
372  found = false;
373  foreach(‪lock in self.multiLockList)
374  {
375  if (‪lock.apTarget == targetsValid[dot.index])
376  {
377  found=true;
378  }
379  }
380 
381  if (found)
382  {
383  continue;
384  }
385 
386  newEntry = spawnstruct();
387  newEntry.apTarget = targetsValid[dot.index];
388  newEntry.apLockStartTime = getTime();
389  newEntry.apLockPending = true;
390  newEntry.apLocking = false;
391  newEntry.apLockFinalized = false;
392  newEntry.apLostSightlineTime = 0;
393  newEntry.apSoundId = RandomInt(‪INT_MAX);
394  return newEntry;
395  }
396 
397  return undefined;
398 }
399 
401 {
402  if (‪a.dot<b.dot)
403  return -1;
404  if (‪a.dot>b.dot)
405  return 1;
406  return 0;
407 }
408 
409 function ‪InsideAPReticleNoLock( target )
410 {
411  radius = self getLockOnRadius();
412  return target_isincircle( target, self, 65, radius );
413 }
414 
415 function ‪InsideAPReticleLocked( target )
416 {
417  radius = (self getLockOnLossRadius()); //maintaining lock is slightly larger to avoid edge case of oscillation between lock and nolock
418  return target_isincircle( target, self, 65, radius );
419 }
420 
421 function ‪IsStillValidTarget( weapon, ent )
422 {
423  if ( ! isdefined( ent ) )
424  return false;
425  if ( ! ‪InsideAPReticleLocked( ent ) )
426  return false;
427  if ( !IsAlive( ent ) )
428  return false;
429  if (!‪LockSightTest(ent))
430  return false;
431 
432  return true;
433 }
434 
435 function ‪SeekerSound( alias, looping, id )
436 {
437  self notify( "stop_sound"+id);
438 
439  self endon ( "stop_sound"+id );
440  self endon( "disconnect" );
441  self endon ( "death" );
442 
443  if (IsDefined(alias))
444  {
445  self PlayRumbleOnEntity( "stinger_lock_rumble" );
446  time = SoundGetPlaybackTime(alias)*0.001;
447  do
448  {
449  self playLocalSound( alias );
450  wait(time);
451  }
452  while (looping);
453  self StopRumble( "stinger_lock_rumble" );
454  }
455 }
456 
457 function ‪LockSightTest( target )
458 {
459  eyePos = self GetEye();
460 
461  if ( !isdefined( target ) ) //targets can disapear during targeting.
462  return false;
463 
464  if ( !IsAlive( target ) )
465  return false;
466 
467  pos = target GetShootAtPos();
468  if (IsDefined(pos))
469  {
470  passed = BulletTracePassed( eyePos, pos, false, target, undefined, true, true );
471  if ( passed )
472  return true;
473  }
474 
475  pos = target GetCentroid();
476  if (IsDefined(pos))
477  {
478  passed = BulletTracePassed( eyePos, pos, false, target, undefined, true, true );
479  if ( passed )
480  return true;
481  }
482 
483  pos=target.origin;
484  passed = BulletTracePassed( eyePos, pos, false, target, undefined, true, true );
485  if ( passed )
486  return true;
487 
488  return false;
489 }
490 
491 
492 
493 
‪APLockLoop
‪function APLockLoop(weapon)
Definition: antipersonnelguidance.gsc:154
‪InsideAPReticleNoLock
‪function InsideAPReticleNoLock(target)
Definition: antipersonnelguidance.gsc:409
‪DestroyLockOnCanceledMessage
‪function DestroyLockOnCanceledMessage()
Definition: antipersonnelguidance.gsc:288
‪GetBestTarget
‪function GetBestTarget(weapon)
Definition: antipersonnelguidance.gsc:315
‪SeekerSound
‪function SeekerSound(alias, looping, id)
Definition: antipersonnelguidance.gsc:435
‪on_player_spawned
‪function on_player_spawned()
Definition: antipersonnelguidance.gsc:28
‪TargetInsertionSortCompare
‪function TargetInsertionSortCompare(a, b)
Definition: antipersonnelguidance.gsc:400
‪APToggleLoop
‪function APToggleLoop()
Definition: antipersonnelguidance.gsc:109
‪lock
‪function lock()
Definition: doors_shared.gsc:138
‪APFiredNotify
‪function APFiredNotify()
Definition: antipersonnelguidance.gsc:87
‪ClearAPTarget
‪function ClearAPTarget(weapon, whom)
Definition: antipersonnelguidance.gsc:37
‪a
‪function add_remove_list a
Definition: util_shared.csc:906
‪__init__
‪function __init__()
Definition: antipersonnelguidance.gsc:23
‪InsideAPReticleLocked
‪function InsideAPReticleLocked(target)
Definition: antipersonnelguidance.gsc:415
‪on_spawned
‪function on_spawned(func, obj)
Definition: callbacks_shared.csc:245
‪INT_MAX
‪#define INT_MAX
Definition: shared.gsh:161
‪LockSightTest
‪function LockSightTest(target)
Definition: antipersonnelguidance.gsc:457
‪MAX_SIMULTANEOUS_LOCKONS
‪#define MAX_SIMULTANEOUS_LOCKONS
Definition: antipersonnelguidance.gsc:19
‪REGISTER_SYSTEM
‪#define REGISTER_SYSTEM(__sys, __func_init_preload, __reqs)
Definition: shared.gsh:204
‪DisplayLockOnCanceledMessage
‪function DisplayLockOnCanceledMessage()
Definition: antipersonnelguidance.gsc:294
‪destroy
‪function destroy(watcher, owner)
Definition: _decoy.gsc:108
‪WAIT_SERVER_FRAME
‪#define WAIT_SERVER_FRAME
Definition: shared.gsh:265
‪IsStillValidTarget
‪function IsStillValidTarget(weapon, ent)
Definition: antipersonnelguidance.gsc:421