‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
_dragon_whelp.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\clientfield_shared;
6 #using scripts\shared\system_shared;
7 #using scripts\shared\array_shared;
8 #using scripts\shared\util_shared;
9 
10 #using scripts\shared\vehicle_shared;
11 #using scripts\shared\vehicle_death_shared;
12 #using scripts\shared\vehicle_ai_shared;
13 
14 #using scripts\shared\ai\systems\blackboard;
15 #using scripts\shared\ai\blackboard_vehicle;
16 #using scripts\shared\animation_shared;
17 #using scripts\shared\ai\systems\gib;
18 #using scripts\shared\ai\zombie_utility;
19 
20 #insert scripts\shared\shared.gsh;
21 #insert scripts\shared\statemachine.gsh;
22 #insert scripts\shared\version.gsh;
23 #insert scripts\shared\archetype_shared\archetype_shared.gsh;
24 #insert scripts\shared\ai\utility.gsh;
25 #insert scripts\shared\ai\systems\gib.gsh;
26 
27 #define DRAGON_FOV_ANGLE 60
28 
29 #define DRAGON_MOVE_DIST_HEIGHT 90
30 
31 #define DRAGON_FOLLOW_DIST 80
32 
33 #define DRAGON_MELEE_DIST 400
34 
35 #namespace dragon;
36 
37 ‪REGISTER_SYSTEM( "dragon", &‪__init__, undefined )
38 
39 #using_animtree( "generic" );
40 
41 function ‪__init__()
42 {
43  vehicle::add_main_callback( "dragon", &‪dragon_initialize );
44 }
45 
47 {
48  self useanimtree( #animtree );
49 
50  //Target_Set( self, ( 0, 0, 0 ) );
51 
52  self.health = self.healthdefault;
53 
55 
56  if ( isdefined( self.scriptbundlesettings ) )
57  {
58  self.settings = ‪struct::get_script_bundle( "vehiclecustomsettings", self.scriptbundlesettings );
59  }
60 
61  assert( isdefined( self.settings ) );
62 
63  //self EnableAimAssist();
64  self SetNearGoalNotifyDist( self.radius * 1.5 );
65  self SetHoverParams( self.radius, self.settings.defaultMoveSpeed * 2, self.radius );
66  self SetSpeed( self.settings.defaultMoveSpeed );
67 
68  // AI SPECIFIC INITIALIZATION
71 
72  self.fovcosine = 0; // +/-90 degrees = 180
73  self.fovcosinebusy = 0; //+/- 55 degrees = 110 fov
74 
75  self.vehAirCraftCollisionEnabled = false;
76  //self thread vehicle_ai::nudge_collision();
77 
78  self.goalRadius = 9999999;
79  self.goalHeight = 512;
80  self SetGoal( self.origin, false, self.goalRadius, self.goalHeight );
81  self.delete_on_death = true;
82 
83  self.overrideVehicleDamage = &‪dragon_callback_damage;
84  self.allowFriendlyFireDamageOverride = &‪dragon_AllowFriendlyFireDamage;
85 
86  self.ignoreme = true;
87 
88  if( IsDefined( level.vehicle_initializer_cb ) )
89  {
90  [[level.vehicle_initializer_cb]]( self );
91  }
92 
94 }
95 
96 function ‪defaultRole()
97 {
99 
100  self ‪vehicle_ai::get_state_callbacks( "combat" ).update_func = &‪state_combat_update;
101  self ‪vehicle_ai::get_state_callbacks( "death" ).update_func = &‪state_death_update;
102 
103  if ( SessionModeIsZombiesGame() )
104  {
105  self ‪vehicle_ai::add_state( "power_up",
106  undefined,
108  undefined );
109 
111  self ‪vehicle_ai::add_utility_connection( "power_up", "combat" );
112  }
113 
114  /#
115  SetDvar( "debug_dragon_threat_selection", 0 );
116  #/
117 
118  //kick off target selection
119  self thread ‪dragon_target_selection();
120 
122  self.startTime = GetTime();
123 }
124 
125 //function that validates if enemies are appropriate
126 function private ‪is_enemy_valid( target )
127 {
128  if( !IsDefined( target ) )
129  {
130  return false;
131  }
132 
133  if( !IsAlive( target ) )
134  {
135  return false;
136  }
137 
138  if( ‪IS_TRUE(self.‪intermission) )
139  {
140  return false;
141  }
142 
143  if( ‪IS_TRUE( target.ignoreme ) )
144  {
145  return false;
146  }
147 
148  if( target IsNoTarget() )
149  {
150  return false;
151  }
152 
153  if( ‪IS_TRUE( target._dragon_ignoreme ) )
154  {
155  return false;
156  }
157 
158  /*
159  if( IsDefined( target.archetype ) && target.archetype == ARCHETYPE_MARGWA )
160  {
161  if( !target margwaserverutils::margwaCanDamageAnyHead() )
162  {
163  return false;
164  }
165  }
166 
167  if( IsDefined( target.archetype ) && target.archetype == ARCHETYPE_ZOMBIE ) && !IS_TRUE( target.completed_emerging_into_playable_area ) )
168  {
169  return false;
170  }
171  */
172 
173  if( DistanceSquared( self.owner.origin, target.origin ) > ‪SQR( self.settings.guardradius ) )
174  {
175  return false;
176  }
177 
178  if ( self VehCanSee( target ) )
179  {
180  return true;
181  }
182 
183  if ( IsActor( target ) && target CanSee( self.owner ) )
184  {
185  return true;
186  }
187 
188  if ( IsVehicle( target ) && target VehCanSee( self.owner ) )
189  {
190  return true;
191  }
192 
193  return false;
194 }
195 
196 //sets the dragon enemy
197 function private ‪get_dragon_enemy()
198 {
199  dragon_enemies = GetAITeamArray( "axis" );
200 
201  distSqr = ‪SQR( 10000 );
202  best_enemy = undefined;
203  foreach( enemy in dragon_enemies )
204  {
205  newDistSqr = Distance2DSquared( enemy.origin, self.owner.origin );
206  if( ‪is_enemy_valid( enemy ) )
207  {
208  if ( enemy.archetype === ‪ARCHETYPE_RAZ )
209  {
210  newDistSqr = Max( Distance2D( enemy.origin, self.owner.origin ) - 700, 0 );
211  newDistSqr = ‪SQR( newDistSqr );
212  }
213  else if ( enemy.archetype === ‪ARCHETYPE_SENTINEL_DRONE )
214  {
215  newDistSqr = Max( Distance2D( enemy.origin, self.owner.origin ) - 500, 0 );
216  newDistSqr = ‪SQR( newDistSqr );
217  }
218  else if ( enemy === self.dragonEnemy )
219  {
220  newDistSqr = Max( Distance2D( enemy.origin, self.owner.origin ) - 300, 0 );
221  newDistSqr = ‪SQR( newDistSqr );
222  }
223 
224  if ( newDistSqr < distSqr )
225  {
226  distSqr = newDistSqr;
227  best_enemy = enemy;
228  }
229  }
230  }
231 
232  return best_enemy;
233 }
234 
235 //thread that sets the enemy if no valid one exists currently
236 function private ‪dragon_target_selection()
237 {
238  self endon( "death" );
239 
240  for( ;; )
241  {
242  //dragon should always have an owner to do target selection
243  if( !IsDefined( self.owner ) )
244  {
245  wait 0.25;
246  continue;
247  }
248 
249  if ( ‪IS_TRUE( self.ignoreall ) )
250  {
251  wait 0.25;
252  continue;
253  }
254 
255  /#
256  //debug sword threat selection
257  if( GetDvarInt( "debug_dragon_threat_selection", 0 ) )
258  {
259  if( IsDefined( self.dragonEnemy ) )
260  {
261  line( self.origin, self.dragonEnemy.origin, ( 1, 0, 0 ), 1.0, false, 5 );
262  }
263  }
264  #/
265 
266  //decide who the enemy should be
267  target = ‪get_dragon_enemy();
268 
269  if( !isDefined( target ) )
270  {
271  self.dragonEnemy = undefined;
272  }
273  else
274  {
275  self.dragonEnemy = target;
276  }
277 
278  wait 0.25;
279  }
280 }
281 
282 // ----------------------------------------------
283 // State: power_up
284 // ----------------------------------------------
285 function ‪state_power_up_update( params )
286 {
287  self endon( "change_state" );
288  self endon( "death" );
289 
290  closest_distSqr = ‪SQR( 10000 );
291  closest = undefined;
292  foreach( powerup in level.active_powerups )
293  {
294  powerup.navVolumeOrigin = self GetClosestPointOnNavVolume( powerup.origin, 100 );
295  if ( !isdefined( powerup.navVolumeOrigin ) )
296  {
297  continue;
298  }
299 
300  distSqr = DistanceSquared( powerup.origin, self.origin );
301  if ( distSqr < closest_distSqr )
302  {
303  closest_distSqr = distSqr;
304  closest = powerup;
305  }
306  }
307 
308  if ( isdefined( closest ) && distSqr < ‪SQR( 2000 ) )
309  {
310  self SetVehGoalPos( closest.navVolumeOrigin, true, true );
312  {
314  }
315 
316  if ( isdefined( closest ) )
317  {
318  ‪trace = BulletTrace( self.origin, closest.origin, false, self );
319  if( ‪trace["fraction"] == 1 )
320  {
321  self SetVehGoalPos( closest.origin, true, false );
322  }
323  }
324  }
325 
327 }
328 
329 function ‪should_go_for_power_up( from_state, to_state, connection )
330 {
331  if ( level.whelp_no_power_up_pickup === true )
332  {
333  return false;
334  }
335 
336  if ( isdefined( self.dragonEnemy ) )
337  {
338  return false;
339  }
340 
341  if ( level.active_powerups.size < 1 )
342  {
343  return false;
344  }
345 
346  return true;
347 }
348 
349 // ----------------------------------------------
350 // State: combat
351 // ----------------------------------------------
352 function ‪state_combat_update( params )
353 {
354  self endon( "change_state" );
355  self endon( "death" );
356 
357  idealDistToOwner = 300;
358 
359  self ASMRequestSubstate( "locomotion@movement" );
360 
361  while ( !isdefined( self.owner ) )
362  {
364  }
365 
366  self thread ‪attack_thread();
367 
368  for( ;; )
369  {
370  self SetSpeed( self.settings.defaultMoveSpeed );
371  self ASMRequestSubstate( "locomotion@movement" );
372 
373  if ( IsDefined( self.owner ) && Distance2DSquared( self.origin, self.owner.origin ) < ‪SQR( idealDistToOwner ) && IsPointInNavVolume( self.origin, "navvolume_small" ) )
374  {
375  if ( !isdefined( self.current_pathto_pos ) )
376  {
377  self.current_pathto_pos = self GetClosestPointOnNavVolume( self.origin, 100 );
378  }
379 
380  self SetVehGoalPos( self.current_pathto_pos, true, false );
381  wait 0.1;
382  continue;
383  }
384 
385  if( IsDefined( self.owner ) )
386  {
387  queryResult = PositionQuery_Source_Navigation( self.origin, 0, 256, ‪DRAGON_MOVE_DIST_HEIGHT, self.radius, self );
388 
389  sightTarget = undefined;
390  if ( isdefined( self.dragonEnemy ) )
391  {
392  sightTarget = self.dragonEnemy GetEye();
393  PositionQuery_Filter_Sight( queryResult, sightTarget, (0,0,0), self, 4 );
394  }
395 
396  if( ‪IS_TRUE( queryResult.centerOnNav ) )
397  {
398  ownerOrigin = self.owner.origin;
399  ownerForward = AnglesToForward( self.owner.angles );
400 
401  // score points
402  best_point = undefined;
403  best_score = -999999;
404 
405  foreach ( point in queryResult.data )
406  {
407  distSqr = Distance2DSquared( point.origin, ownerOrigin );
408  if ( distSqr > ‪SQR( idealDistToOwner ) )
409  {
410  ADD_POINT_SCORE( point, "distToOwner", -Sqrt( distSqr ) * 2 );
411  }
412 
413  if ( ‪IS_TRUE( point.visibility ) )
414  {
415  if ( BulletTracePassed( point.origin, sightTarget, false, self ) )
416  {
417  ADD_POINT_SCORE( point, "visibility", 400 );
418  }
419  }
420 
421  vecToOwner = point.origin - ownerOrigin;
422  dirToOwner = VectorNormalize( ‪FLAT_ORIGIN( vecToOwner ) );
423  if ( VectorDot( ownerForward, dirToOwner ) > 0.34 ) // 0.34 = cos(70)
424  {
425  if ( Abs( vecToOwner[2] ) < 100 )
426  {
427  ADD_POINT_SCORE( point, "frontOfPlayer", 300 );
428  }
429  else if ( Abs( vecToOwner[2] ) < 200 )
430  {
431  ADD_POINT_SCORE( point, "frontOfPlayer", 100 );
432  }
433  }
434 
435  if ( point.score > best_score )
436  {
437  best_score = point.score;
438  best_point = point;
439  }
440  }
441 
442  self ‪vehicle_ai::PositionQuery_DebugScores( queryResult );
443 
444  if ( isdefined( best_point ) )
445  {
446  /#
447  if ( ‪IS_TRUE( GetDvarInt("hkai_debugPositionQuery") ) )
448  {
449  recordLine( self.origin, best_point.origin, (0.3,1,0) );
450  recordLine( self.origin, self.owner.origin, (1,0,0.4) );
451  }
452  #/
453 
454  if ( DistanceSquared( self.origin, best_point.origin ) > ‪SQR( 50 ) )
455  {
456  self.current_pathto_pos = best_point.origin;
457 
458  self SetVehGoalPos( self.current_pathto_pos, true, true );
460  }
461  else
462  {
463  self ‪vehicle_ai::Cooldown( "move_cooldown", 4 );
464  }
465  }
466  }
467  else
468  {
470  }
471  }
472 
473  wait 0.1;
474  }
475 }
476 
478 {
479  self endon( "change_state" );
480  self endon( "death" );
481 
482  for( ;; )
483  {
484  wait 0.1;
485 
487 
488  if ( !self ‪vehicle_ai::IsCooldownReady( "attack" ) )
489  {
490  continue;
491  }
492 
493  if ( !IsDefined( self.dragonEnemy ) )
494  {
495  continue;
496  }
497 
498  self SetLookAtEnt( self.dragonEnemy );
499 
500  if ( !self VehCanSee( self.dragonEnemy ) )
501  {
502  continue;
503  }
504 
505  if ( Distance2DSquared( self.dragonEnemy.origin, self.owner.origin ) > ‪SQR( self.settings.guardradius ) )
506  {
507  continue;
508  }
509 
510  eyeOffset = ( self.dragonEnemy GetEye() - self.dragonEnemy.origin ) * 0.6;
511 
512  if ( !BulletTracePassed( self.origin, self.dragonEnemy GetEye() - eyeOffset, false, self, self.dragonEnemy ) )
513  {
514  self.dragonEnemy = undefined;
515  continue;
516  }
517 
518  aimOffset = self.dragonEnemy GetVelocity() * 0.3 - eyeOffset;
519  self SetTurretTargetEnt( self.dragonEnemy, aimOffset );
520 
521  wait 0.2;
522 
523  if ( isdefined( self.dragonEnemy ) )
524  {
525  self FireWeapon( 0, self.dragonEnemy, (0,0,0), self );
526  self ‪vehicle_ai::Cooldown( "attack", 1 );
527  }
528 
529  //self util::waittill_notify_or_timeout( "wing_start", 1 );
530  //self ASMRequestSubstate( "fire@stationary" );
531  //self vehicle_ai::waittill_asm_complete( "fire@stationary", 3 );
532  //self ASMRequestSubstate( "locomotion@movement" );
533 
534  }
535 }
536 
538 {
539  // try to path straight to a nearby position on the nav volume
540  queryResult = PositionQuery_Source_Navigation( self.origin, 0, 100, ‪DRAGON_MOVE_DIST_HEIGHT, self.radius, self );
541 
542  multiplier = 2;
543  while ( queryResult.data.size < 1 )
544  {
545  queryResult = PositionQuery_Source_Navigation( self.origin, 0, 100 * multiplier, ‪DRAGON_MOVE_DIST_HEIGHT * multiplier, self.radius * multiplier, self );
546  multiplier += 2;
547  }
548 
549  if ( queryResult.data.size && !queryResult.centerOnNav )
550  {
551  best_point = undefined;
552  best_score = 999999;
553 
554  foreach ( point in queryResult.data )
555  {
556  point.score = Abs( point.origin[2] - queryResult.origin[2] );
557 
558  if ( point.score < best_score )
559  {
560  best_score = point.score;
561  best_point = point;
562  }
563  }
564 
565  if( IsDefined( best_point ) )
566  {
567  //force it to move to favorable point
568  self SetNearGoalNotifyDist( 2 );
569 
570  point = best_point;
571 
572  self.current_pathto_pos = point.origin;
573 
574  foundpath = self SetVehGoalPos( self.current_pathto_pos, true, false );
575  if( foundpath )
576  {
578  }
579 
580  self SetNearGoalNotifyDist( self.radius );
581  }
582  }
583 }
584 
585 function ‪dragon_AllowFriendlyFireDamage( eInflictor, eAttacker, sMeansOfDeath, weapon )
586 {
587  return false;
588 }
589 
590 function ‪dragon_callback_damage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal )
591 {
592  if( self.dragon_recall_death !== true )
593  {
594  return 0;
595  }
596 
597  return iDamage;
598 }
599 
600 // ----------------------------------------------
601 // State: death
602 // ----------------------------------------------
603 function ‪state_death_update( params )
604 {
605  self endon ( "death" );
606 
607  attacker = params.inflictor;
608  if( !isdefined( attacker ) )
609  {
610  attacker = params.attacker;
611  }
612 
613  if( attacker !== self && ( !isdefined( self.owner ) || ( self.owner !== attacker ) ) && ( IsAI( attacker) || IsPlayer( attacker ) ) )
614  {
615  self.damage_on_death = false;
617 
618  // need to retest for attacker validity because of the wait
619  attacker = params.inflictor;
620  if( !isdefined( attacker ) )
621  {
622  attacker = params.attacker;
623  }
624  }
625 
627 }
‪dragon_initialize
‪function dragon_initialize()
Definition: _dragon_whelp.gsc:46
‪add_state
‪function add_state(name, enter_func, update_func, exit_func, reenter_func)
Definition: statemachine_shared.gsc:59
‪state_combat_update
‪function state_combat_update(params)
Definition: _dragon_whelp.gsc:352
‪evaluate_connections
‪function evaluate_connections(eval_func, params)
Definition: statemachine_shared.gsc:266
‪IsCooldownReady
‪function IsCooldownReady(name, timeForward_seconds)
Definition: vehicle_ai_shared.gsc:1968
‪intermission
‪function intermission()
Definition: _zm.gsc:6542
‪defaultRole
‪function defaultRole()
Definition: _dragon_whelp.gsc:96
‪ARCHETYPE_RAZ
‪#define ARCHETYPE_RAZ
Definition: archetype_shared.gsh:20
‪trace
‪function trace(from, to, target)
Definition: grapple.gsc:369
‪defaultstate_death_update
‪function defaultstate_death_update(params)
Definition: vehicle_ai_shared.gsc:1355
‪IS_TRUE
‪#define IS_TRUE(__a)
Definition: shared.gsh:251
‪__init__
‪function __init__()
Definition: _dragon_whelp.gsc:41
‪SQR
‪#define SQR(__var)
Definition: shared.gsh:293
‪StartInitialState
‪function StartInitialState(defaultState="combat")
Definition: vehicle_ai_shared.gsc:866
‪waittill_pathresult
‪function waittill_pathresult(maxtime=0.5)
Definition: vehicle_ai_shared.gsc:347
‪friendly_fire_shield
‪function friendly_fire_shield()
Definition: vehicle_shared.gsc:2194
‪dragon_target_selection
‪function private dragon_target_selection()
Definition: _dragon_whelp.gsc:236
‪Cooldown
‪function Cooldown(name, time_seconds)
Definition: vehicle_ai_shared.gsc:1943
‪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
‪PositionQuery_DebugScores
‪function PositionQuery_DebugScores(queryResult)
Definition: vehicle_ai_shared.gsc:2010
‪is_enemy_valid
‪function private is_enemy_valid(target)
Definition: _dragon_whelp.gsc:126
‪REGISTER_SYSTEM
‪#define REGISTER_SYSTEM(__sys, __func_init_preload, __reqs)
Definition: shared.gsh:204
‪state_power_up_update
‪function state_power_up_update(params)
Definition: _dragon_whelp.gsc:285
‪attack_thread
‪function attack_thread()
Definition: _dragon_whelp.gsc:477
‪RegisterVehicleBlackBoardAttributes
‪function RegisterVehicleBlackBoardAttributes()
Definition: blackboard_vehicle.gsc:24
‪get_dragon_enemy
‪function private get_dragon_enemy()
Definition: _dragon_whelp.gsc:197
‪DRAGON_MOVE_DIST_HEIGHT
‪#define DRAGON_MOVE_DIST_HEIGHT
Definition: _dragon_whelp.gsc:29
‪CreateBlackBoardForEntity
‪function CreateBlackBoardForEntity(entity)
Definition: blackboard.gsc:77
‪add_utility_connection
‪function add_utility_connection(from_state_name, to_state_name, checkfunc, defaultScore)
Definition: statemachine_shared.gsc:112
‪dragon_callback_damage
‪function dragon_callback_damage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal)
Definition: _dragon_whelp.gsc:590
‪should_go_for_power_up
‪function should_go_for_power_up(from_state, to_state, connection)
Definition: _dragon_whelp.gsc:329
‪FLAT_ORIGIN
‪#define FLAT_ORIGIN(__origin)
Definition: shared.gsh:256
‪get_script_bundle
‪function get_script_bundle(str_type, str_name)
Definition: struct.csc:45
‪dragon_AllowFriendlyFireDamage
‪function dragon_AllowFriendlyFireDamage(eInflictor, eAttacker, sMeansOfDeath, weapon)
Definition: _dragon_whelp.gsc:585
‪go_back_on_navvolume
‪function go_back_on_navvolume()
Definition: _dragon_whelp.gsc:537
‪state_death_update
‪function state_death_update(params)
Definition: _dragon_whelp.gsc:603
‪get_state_callbacks
‪function get_state_callbacks(statename)
Definition: vehicle_ai_shared.gsc:927
‪ARCHETYPE_SENTINEL_DRONE
‪#define ARCHETYPE_SENTINEL_DRONE
Definition: archetype_shared.gsh:40
‪WAIT_SERVER_FRAME
‪#define WAIT_SERVER_FRAME
Definition: shared.gsh:265