‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
_scout_drone.gsc
Go to the documentation of this file.
1 #using scripts\codescripts\struct;
2 
3 #using scripts\shared\math_shared;
4 #using scripts\shared\statemachine_shared;
5 #using scripts\shared\system_shared;
6 #using scripts\shared\util_shared;
7 #using scripts\shared\vehicle_shared;
8 #using scripts\shared\vehicle_ai_shared;
9 #using scripts\shared\vehicle_death_shared;
10 
11 #insert scripts\shared\shared.gsh;
12 #insert scripts\shared\statemachine.gsh;
13 
14 #insert scripts\shared\ai\utility.gsh;
15 
16 #define PROTOTYPE_SCOUT_HP_MOD 1
17 #define SCOUT_DEFAULT_RADIUS_FOR_DEFEND_ROLE 64
18 #define SCOUT_DEFAULT_RADIUS_FOR_GUARD_ROLE 64
19 #define SCOUT_DEFAULT_RADIUS_FOR_LOITER_ROLE 64
20 #define SCOUT_TRACK_DISTANCE 256 // distance that the scout tries to stay from the player while tracking it
21 #define SCOUT_DEFEND_HEIGHT 300
22 #define SCOUT_LOITER_HEIGHT 300
23 #define SCOUT_PATROL_HEIGHT 300
24 #define SCOUT_TRACK_HEIGHT 128
25 #define SCOUT_TRACK_TETHER 512
26 #define SCOUT_BASE_SPEED_MODIFIER 0.33
27 
28 #precache( "fx", "_t6/destructibles/fx_quadrotor_crash01" );
29 
30 #namespace scout_drone;
31 
32 ‪REGISTER_SYSTEM( "scout_drone", &‪__init__, undefined )
33 
34 function ‪__init__()
35 {
36  vehicle::add_main_callback( "scout", &‪scout_drone_initialize );
37 
38  level._effect[ "quadrotor_crash" ] = "_t6/destructibles/fx_quadrotor_crash01";
39 }
40 
42 {
43  self.health = self.healthdefault;
44 
46 
47  self EnableAimAssist();
48  self SetHoverParams( 25.0, 120.0, 80 );
49  self SetNearGoalNotifyDist( 40 );
50 
51  self.flyheight = GetDvarFloat( "g_quadrotorFlyHeight" );
52 
53  self.fovcosine = 0; // +/-90 degrees = 180
54  self.fovcosinebusy = 0.574; //+/- 55 degrees = 110 fov
55 
56  self.vehAirCraftCollisionEnabled = true;
57 
58  self.original_vehicle_type = self.vehicletype;
59 
60  self.settings = ‪struct::get_script_bundle( "vehiclecustomsettings", self.scriptbundlesettings );
61 
62  self.overrideVehicleDamage = &‪scout_callback_damage;
63 
64  self thread ‪vehicle_ai::nudge_collision();
65 
66  self.goalpos = self.origin;
67  self.goalradius = 40;
68 
69  // for testing
70  ‪patrol( undefined );
71 }
72 
73 function ‪defend( s_centerpoint, n_radius )
74 {
75  Assert( false, "defend is not implemented for scout" );
76 }
77 
78 function ‪guard( v_centerpoint )
79 {
80  Assert( false, "guard is not implemented for scout" );
81 }
82 
83 function ‪loiter( v_center, n_radius )
84 {
85  Assert( false, "loiter is not implemented for scout" );
86 }
87 
88 function ‪patrol( start_node )
89 {
91 
92  self ‪vehicle_ai::get_state_callbacks( "patrol", "unaware" ).enter_func = &‪state_unaware_enter;
93  self ‪vehicle_ai::get_state_callbacks( "patrol", "unaware" ).update_func = &‪state_unaware_update;
94  self ‪vehicle_ai::get_state_callbacks( "patrol", "low_alert" ).enter_func = &‪state_lowalert_enter;
95  self ‪vehicle_ai::get_state_callbacks( "patrol", "low_alert" ).update_func = &‪state_alert_update;
96  self ‪vehicle_ai::get_state_callbacks( "patrol", "high_alert" ).enter_func = &‪state_highalert_enter;
97  self ‪vehicle_ai::get_state_callbacks( "patrol", "high_alert" ).update_func = &‪state_alert_update;
98  self ‪vehicle_ai::get_state_callbacks( "patrol", "combat" ).enter_func = &‪state_combat_enter;
99  self ‪vehicle_ai::get_state_callbacks( "patrol", "combat" ).update_func = &‪state_combat_update;
100 
101  self ‪vehicle_ai::get_state_callbacks( "patrol", "death" ).update_func = &‪vehicle_death::flipping_shooting_death;
102 
103  self ‪vehicle_ai::set_role( "patrol" );
104 
105  ‪set_patrol_path( start_node );
106  self ‪vehicle_ai::set_state( "unaware" );
107 }
108 
109 // ----------------------------------------------
110 // State: unaware
111 // ----------------------------------------------
112 function ‪set_patrol_path( patrol_path_start_node )
113 {
114  self.patrol_path = patrol_path_start_node;
115 }
116 
118 {
119  baseSpeed = 7;
120  randomHalfRange = 2;
121  self SetSpeed( RandomFloatRange( baseSpeed - randomHalfRange, baseSpeed + randomHalfRange ) );
122 
123 /# println( "^1WARNING: No patrol path defined, taking the nearest one" ); #/
124 
125  searchRadius = 256;
126  while ( !isdefined( self.patrol_path ) )
127  {
128  searchRadius = searchRadius * 2;
129  nodes = GetNodesInRadius( self.origin, searchRadius, 0, searchRadius, "Path", 1 );
130 
131  if ( nodes.size > 0 )
132  {
133  self.patrol_path = nodes[ 0 ];
134  }
135  wait 0.02;
136  }
137 }
138 
139 function ‪state_unaware_update() // follow a path
140 {
141  self endon( "change_state" );
142  self endon( "death" );
143 
144  for( ;; )
145  {
146  // follow the .target kvp on the struct path
147  if ( isdefined( self.patrol_path ) )
148  {
149  nd_current = self.patrol_path;
150  nd_first = nd_current; // save off the first node, so we know when we've made a full circuit
151 
152  v_height_offset = ‪SCOUT_PATROL_HEIGHT;
153  if ( isdefined( nd_current.script_height ) ) // designer can override patrol height on pathnode
154  {
155  v_height_offset = nd_current.script_height;
156  }
157 
158  self SetVehGoalPos( nd_current.origin + ( 0, 0, v_height_offset ), 0, 2 );
160  self ClearVehGoalPos();
161  nd_current ‪util::script_wait();
162 
163  nd_detour_entry = undefined; // this will be used in the loop below for keeping track of when we get back from a detour
164  b_currently_on_detour = false; // track whether we're on a detour or not
165 
166  while( isdefined( nd_current.target ) )
167  {
168  //CreateDynEntAndLaunch( self.model, self.origin, self.angles, self.origin, (0,0,100), level._effect[ "quadrotor_crash" ] );
169 
170  if ( nd_current == nd_first )
171  {
172  a_explored_sidepaths = []; // this array will hold nodes for detours and POIs that we have already explored; if we've made a full circuit, reset this
173  }
174 
175  // check if we're back from a detour
176  if ( isdefined( nd_detour_entry ) && ( nd_current == nd_detour_entry ) )
177  {
178  nd_detour_entry = undefined;
179  b_currently_on_detour = false;
180  }
181 
182  // save off nd_previous before updating nd_current
183  nd_previous = nd_current;
184 
185  // get target nodes so we can start choosing the next nd_current
186  a_nodes = GetNodeArray( nd_current.target, "targetname" );
187 
188  // remove any already-explored nodes from consideration ( in-case we're coming back from a detour or POI )
189  for( i = 0; i < a_nodes.size; i++ )
190  {
191  node = a_nodes[i];
192 
193  if ( isinarray( a_explored_sidepaths, node ) )
194  {
195  ArrayRemoveValue( a_nodes, node ); // remove any already-explored nodes
196  i = 0; // restart
197  }
198  }
199 
200  // assign a random node (even chances)
201  nd_current = ‪RANDOM( a_nodes );
202 
203  if ( isdefined( nd_current.script_string ) )
204  {
205  // if the node we're traveling to is a detour, add it to the explored nodes array
206  if ( nd_current.script_string == "detour" )
207  {
208  ArrayInsert( a_explored_sidepaths, nd_current, 0 );
209  nd_detour_entry = nd_previous;
210  b_currently_on_detour = true;
211  }
212  // if the node we're traveling to is a detour, add it to the explored nodes array AND set it as the look ent
213  else if ( nd_current.script_string == "poi" )
214  {
215  ArrayInsert( a_explored_sidepaths, nd_current, 0 );
216  nd_detour_entry = nd_previous;
217  b_currently_on_detour = true;
218  //self SetLookAtEnt( nd_current );
219  }
220  }
221 
222  /*
223  if ( b_currently_on_detour )
224  {
225  IPrintLn( "ON DETOUR" );
226  }
227  else
228  {
229  IPrintLn( "NOT ON DETOUR" );
230  }
231  */
232 
233  // go to the node
234  v_height_offset = ‪SCOUT_PATROL_HEIGHT;
235  if ( isdefined( nd_current.script_height ) ) // designer can override patrol height on pathnode
236  {
237  v_height_offset = nd_current.script_height;
238  }
239  self SetVehGoalPos( nd_current.origin + ( 0, 0, v_height_offset ), 0, 2 );
241  self ClearVehGoalPos();
242  self SetVehGoalPos( self.origin, 0, 2 );
243  // if the node is marked "nostop" or "detour", continue past without pausing
244  if ( isdefined( nd_current.script_string ) && ( ( nd_current.script_string == "nostop" ) || ( nd_current.script_string == "detour" ) ) )
245  {
246  }
247  else
248  {
249  nd_current ‪util::script_wait();
250  }
251 
252  // reset this
253  self ClearLookAtEnt();
254  wait 0.02;
255  }
256  }
257  wait 0.1;
258  }
259 }
260 // ----------------------------------------------
261 
262 // ----------------------------------------------
263 // State: low alert and high alert
264 // ----------------------------------------------
266 {
267  self SetSpeed( 5 );
268 }
269 
271 {
272  self SetSpeed( 10 );
273 }
274 
276 {
277  self endon( "change_state" );
278  self endon( "death" );
279 
280  for ( ;; )
281  {
282  if ( IsDefined( self.alertSource ) )
283  {
284  self ClearLookAtEnt();
285 
286  goalpos = self.alertSource;
287  goalpos = self GetClosestPointOnNavVolume( goalpos, 128 );
288 
289  self.debugGoal = goalpos;
290 
291  if ( IsDefined( goalpos ) && self SetVehGoalPos( goalpos, true, 2 ) )
292  {
294 
295  // stop, look around
296  wait 3;
297  }
298  else
299  {
300  wait 1;
301  }
302  }
303  }
304 }
305 // ----------------------------------------------
306 
307 // ----------------------------------------------
308 // State: combat
309 // ----------------------------------------------
311 {
312  self SetSpeed( 12 );
313 
314  if ( !isdefined( self.enemy ) )
315  {
316  self ‪vehicle_ai::set_state( "high_alert" );
317  /# println("^1Error: Scout drone trying to enter combat state without an enemy as target."); #/
318  }
319 
320  self.lockOnTarget = self.enemy;
321 
322  goalpos = ‪_track_target_position( self.lockOnTarget );
323  self SetVehGoalPos( goalpos, true, 2 );
324 }
325 
326 function ‪_track_target_position( target )
327 {
328  targetForward = AnglesToForward( target.angles ) * ‪SCOUT_TRACK_DISTANCE;
329  return target.origin + targetForward + ( 0, 0, ‪SCOUT_TRACK_HEIGHT );
330 }
331 
332 function ‪state_combat_update() // track player
333 {
334  self endon( "change_state" );
335  self endon( "death" );
336 
337 
338  lastHasTargetTime = GetTime();
339 
340  for ( ;; )
341  {
342  if ( isAlive( self.lockOnTarget ) )
343  {
344  if ( Distance2DSquared( self.origin, self.lockOnTarget.origin ) > ‪SQR( ‪SCOUT_TRACK_TETHER ) )
345  {
346  self ClearLookAtEnt();
347 
348  goalpos = ‪_track_target_position( self.lockOnTarget );
349 
350  if ( self SetVehGoalPos( goalpos, true, 2 ) )
351  {
353  }
354  else
355  {
356  wait 1;
357  }
358  }
359  else
360  {
361  self SetLookAtEnt( self.lockOnTarget );
362  }
363 
364  lastHasTargetTime = GetTime();
365  }
366  else if ( isAlive( self.enemy ) )
367  {
368  self.lockOnTarget = self.enemy;
369  }
370  else
371  {
372  if ( GetTime() - lastHasTargetTime > 4000 )
373  {
374 
375  }
376  }
377 
378  wait 0.01;
379  }
380 }
381 // ----------------------------------------------
382 
383 function ‪get_custom_damage_effect( health_pct )
384 {
385  if( health_pct < .25 )
386  {
387  return level._effect[ "quadrotor_damage04" ];
388  }
389  else if( health_pct < .5 )
390  {
391  return level._effect[ "quadrotor_damage03" ];
392  }
393  else if( health_pct < .75 )
394  {
395  return level._effect[ "quadrotor_damage02" ];
396  }
397  else if( health_pct < 0.9 )
398  {
399  return level._effect[ "quadrotor_damage01" ];
400  }
401 
402  return undefined;
403 }
404 
405 function ‪scout_callback_damage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, damageFromUnderneath, modelIndex, partName )
406 {
407  if ( self.health > 0 && iDamage > 1 ) // emp does one damage and we don't want to look like it damaged us
408  {
409  health_percent = ( self.health - iDamage ) / self.healthdefault;
410  effect = ‪get_custom_damage_effect( health_percent );
411  }
412 
413  self ‪vehicle_ai::throw_off_balance( sMeansOfDeath, vPoint, vDir, sHitLoc );
414 
415  self notify ( "awareness_level_increase" );
416 
417  self.lockOnTarget = eAttacker;
418 
419  return iDamage;
420 }
421 
423 {
424  patrolHeight = 140;
425 
426  if ( !isdefined( self.goalpos ) )
427  {
428  self.goalpos = self.origin;
429  }
430 
431  origin = self.goalpos;
432 
433  points = []; // deprecated // self GetNavVolumePointsInBox( self.origin, 512, 128, 100, 64, 256, 32 );
434 
435  best_point = undefined;
436  best_score = 0;
437 
438  foreach( point in points )
439  {
440  score = RandomFloat( 100 );
441 
442  pointAboveNavMesh = point;
443  if ( IsDefined( pointAboveNavMesh ) )
444  {
445  score = score + 100 - Abs( pointAboveNavMesh[2] - point[2] ) * 0.1;
446  }
447 
448  if ( score > best_score )
449  {
450  best_score = score;
451  best_point = point;
452  }
453  }
454 
455  if ( isdefined( best_point ) )
456  {
457  origin = best_point + ( 0, 0, self.flyheight + RandomFloatRange( -30, 40 ) );
458  }
459 
460  return origin;
461 }
462 
‪SCOUT_TRACK_DISTANCE
‪#define SCOUT_TRACK_DISTANCE
Definition: _scout_drone.gsc:20
‪set_state
‪function set_state(name, state_params)
Definition: statemachine_shared.gsc:133
‪SCOUT_TRACK_TETHER
‪#define SCOUT_TRACK_TETHER
Definition: _scout_drone.gsc:25
‪defend
‪function defend(s_centerpoint, n_radius)
Definition: _scout_drone.gsc:73
‪nudge_collision
‪function nudge_collision()
Definition: vehicle_ai_shared.gsc:437
‪RANDOM
‪#define RANDOM(__array)
Definition: shared.gsh:302
‪SQR
‪#define SQR(__var)
Definition: shared.gsh:293
‪guard
‪function guard(v_centerpoint)
Definition: _scout_drone.gsc:78
‪state_combat_update
‪function state_combat_update()
Definition: _scout_drone.gsc:332
‪state_unaware_update
‪function state_unaware_update()
Definition: _scout_drone.gsc:139
‪set_patrol_path
‪function set_patrol_path(patrol_path_start_node)
Definition: _scout_drone.gsc:112
‪__init__
‪function __init__()
Definition: _scout_drone.gsc:34
‪get_custom_damage_effect
‪function get_custom_damage_effect(health_pct)
Definition: _scout_drone.gsc:383
‪flipping_shooting_death
‪function flipping_shooting_death(attacker, hitDir)
Definition: vehicle_death_shared.gsc:1442
‪scout_drone_initialize
‪function scout_drone_initialize()
Definition: _scout_drone.gsc:41
‪friendly_fire_shield
‪function friendly_fire_shield()
Definition: vehicle_shared.gsc:2194
‪SCOUT_PATROL_HEIGHT
‪#define SCOUT_PATROL_HEIGHT
Definition: _scout_drone.gsc:23
‪init_state_machine_for_role
‪function init_state_machine_for_role(rolename)
Definition: vehicle_ai_shared.gsc:1034
‪waittill_pathing_done
‪function waittill_pathing_done(maxtime=15)
Definition: vehicle_ai_shared.gsc:340
‪scout_find_new_position
‪function scout_find_new_position()
Definition: _scout_drone.gsc:422
‪set_role
‪function set_role(rolename)
Definition: vehicle_ai_shared.gsc:910
‪state_unaware_enter
‪function state_unaware_enter()
Definition: _scout_drone.gsc:117
‪script_wait
‪function script_wait(called_from_spawner=false)
Definition: util_shared.gsc:1930
‪patrol
‪function patrol(start_node)
Definition: _scout_drone.gsc:88
‪REGISTER_SYSTEM
‪#define REGISTER_SYSTEM(__sys, __func_init_preload, __reqs)
Definition: shared.gsh:204
‪state_combat_enter
‪function state_combat_enter()
Definition: _scout_drone.gsc:310
‪loiter
‪function loiter(v_center, n_radius)
Definition: _scout_drone.gsc:83
‪get_script_bundle
‪function get_script_bundle(str_type, str_name)
Definition: struct.csc:45
‪state_highalert_enter
‪function state_highalert_enter()
Definition: _scout_drone.gsc:270
‪throw_off_balance
‪function throw_off_balance(damageType, hitPoint, hitDirection, hitLocationInfo)
Definition: vehicle_ai_shared.gsc:391
‪SCOUT_TRACK_HEIGHT
‪#define SCOUT_TRACK_HEIGHT
Definition: _scout_drone.gsc:24
‪scout_callback_damage
‪function scout_callback_damage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, damageFromUnderneath, modelIndex, partName)
Definition: _scout_drone.gsc:405
‪_track_target_position
‪function _track_target_position(target)
Definition: _scout_drone.gsc:326
‪state_alert_update
‪function state_alert_update()
Definition: _scout_drone.gsc:275
‪state_lowalert_enter
‪function state_lowalert_enter()
Definition: _scout_drone.gsc:265
‪get_state_callbacks
‪function get_state_callbacks(statename)
Definition: vehicle_ai_shared.gsc:927