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