‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
_spider.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\array_shared;
7 #using scripts\shared\util_shared;
8 
9 #using scripts\shared\vehicle_shared;
10 #using scripts\shared\vehicle_death_shared;
11 #using scripts\shared\vehicle_ai_shared;
12 #using scripts\shared\audio_shared;
13 #using scripts\shared\clientfield_shared;
14 
15 #using scripts\shared\ai\systems\blackboard;
16 #using scripts\shared\ai\blackboard_vehicle;
17 
18 #insert scripts\shared\version.gsh;
19 #insert scripts\shared\shared.gsh;
20 #insert scripts\shared\statemachine.gsh;
21 #insert scripts\shared\archetype_shared\archetype_shared.gsh;
22 
23 #insert scripts\shared\ai\utility.gsh;
24 
25 #namespace spider;
26 
27 #define SPIDER_MOVE_DIST_MAX 300
28 #define SPIDER_MOVE_DIST_MIN 80
29 
30 #using_animtree( "generic" );
31 
32 ‪REGISTER_SYSTEM( "spider", &‪__init__, undefined )
33 
34 function ‪__init__()
35 {
36  vehicle::add_main_callback( "spider", &‪spider_initialize );
37  /#
38  SetDvar( "debug_spider_noswitch", 0 );
39  #/
40 }
41 
42 function ‪NO_SWITCH_ON()
43 {
44  return GetDvarInt( "debug_spider_noswitch", 0 ) === 1;
45 }
46 
48 {
49  self.fovcosine = 0;
50  self.fovcosinebusy = 0;
51  self.delete_on_death = true;
52  self.health = self.healthdefault;
53 
54  self UseAnimTree( #animtree );
55 
57 
58  assert( isdefined( self.scriptbundlesettings ) );
59  self.settings = ‪struct::get_script_bundle( "vehiclecustomsettings", self.scriptbundlesettings );
60 
61  self EnableAimAssist();
62 
63  self SetDrawInfrared( true );
64 
67 
68  self SetNearGoalNotifyDist( 40 );
69  self.goalRadius = 999999;
70  self.goalHeight = 999999;
71  self SetGoal( self.origin, false, self.goalRadius, self.goalHeight );
72 
73  self SetOnTargetAngle( 3 );
74 
75  self.overrideVehicleDamage = &‪spider_callback_damage;
76 
77  self thread ‪vehicle_ai::nudge_collision();
78 
79  //disable some cybercom abilities
80  if( IsDefined( level.vehicle_initializer_cb ) )
81  {
82  [[level.vehicle_initializer_cb]]( self );
83  }
84 
85  self ASMRequestSubstate( "locomotion@movement" );
86 
88 }
89 
90 function ‪defaultRole()
91 {
93 
95  self ‪vehicle_ai::get_state_callbacks( "death" ).update_func = &‪state_death_update;
96  self ‪vehicle_ai::get_state_callbacks( "driving" ).update_func = &‪state_driving_update;
97 
98  self ‪vehicle_ai::add_state( "meleeCombat",
99  undefined,
101  undefined );
102 
105 
107 
109 }
110 
111 // ----------------------------------------------
112 // State: death
113 // ----------------------------------------------
114 function ‪state_death_update( params )
115 {
116  self endon( "death" );
117 
118  self ASMRequestSubstate( "death@stationary" );
119  ‪vehicle_ai::waittill_asm_complete( "death@stationary", 2 );
120 
122 
124 }
125 
126 // ----------------------------------------------
127 // State: driving
128 // ----------------------------------------------
129 function ‪state_driving_update( params )
130 {
131  self endon( "change_state" );
132  self endon( "death" );
133 
134  self ASMRequestSubstate( "locomotion@aggressive" );
135 }
136 
137 // ----------------------------------------------
138 // State: range combat
139 // ----------------------------------------------
141 {
142  if( self.goalforced )
143  {
144  return self.goalpos;
145  }
146 
147  // distance based multipliers
148  selfDistToTarget = Distance2D( self.origin, enemy.origin );
149 
150  goodDist = 0.5 * ( self.settings.engagementDistMin + self.settings.engagementDistMax );
151 
152  tooCloseDist = 150;
153  closeDist = 1.2 * goodDist;
154  farDist = 3 * goodDist;
155 
156  queryMultiplier = MapFloat( closeDist, farDist, 1, 3, selfDistToTarget );
157 
158  preferedDistAwayFromOrigin = 300;
159  randomness = 30;
160 
161  // query
162  queryResult = PositionQuery_Source_Navigation( self.origin, ‪SPIDER_MOVE_DIST_MIN, ‪SPIDER_MOVE_DIST_MAX * queryMultiplier, 0.5 * ‪SPIDER_MOVE_DIST_MAX, 2 * self.radius * queryMultiplier, self, 1 * self.radius * queryMultiplier );
163 
164  // filter
165  PositionQuery_Filter_DistanceToGoal( queryResult, self );
167  PositionQuery_Filter_InClaimedLocation( queryResult, self );
168  ‪vehicle_ai::PositionQuery_Filter_EngagementDist( queryResult, enemy, self.settings.engagementDistMin, self.settings.engagementDistMax );
169 
170  if ( isdefined( self.avoidEntities ) && isdefined( self.avoidEntitiesDistance ) )
171  {
172  ‪vehicle_ai::PositionQuery_Filter_DistAwayFromTarget( queryResult, self.avoidEntities, self.avoidEntitiesDistance, -500 );
173  }
174 
175  // score points
176  best_point = undefined;
177  best_score = -999999;
178 
179  foreach ( point in queryResult.data )
180  {
181  // distance from origin
182  ADD_POINT_SCORE( point, "distToOrigin", MapFloat( 0, preferedDistAwayFromOrigin, 0, 300, point.distToOrigin2D ) );
183 
184  if( point.inClaimedLocation )
185  {
186  ADD_POINT_SCORE( point, "inClaimedLocation", -500 );
187  }
188 
189  ADD_POINT_SCORE( point, "random", randomFloatRange( 0, randomness ) );
190 
191  ADD_POINT_SCORE( point, "engagementDist", -point.distAwayFromEngagementArea );
192 
193  if ( point.score > best_score )
194  {
195  best_score = point.score;
196  best_point = point;
197  }
198  }
199 
200  self ‪vehicle_ai::PositionQuery_DebugScores( queryResult );
201 
202  /# self.debug_ai_move_to_points_considered = queryResult.data; #/
203 
204  if( !isdefined( best_point ) )
205  {
206  return undefined;
207  }
208 
209 /#
210  if ( ‪IS_TRUE( GetDvarInt("hkai_debugPositionQuery") ) )
211  {
212  recordLine( self.origin, best_point.origin, (0.3,1,0) );
213  recordLine( self.origin, enemy.origin, (1,0,0.4) );
214  }
215 #/
216 
217  return best_point.origin;
218 }
219 
221 {
222  self endon( "change_state" );
223  self endon( "death" );
224 
225  self.pathfailcount = 0;
226  self.foundpath = true;
227 
228  if ( params.playTransition === true )
229  {
230  self ‪vehicle_ai::ClearAllMovement( true );
231  self ASMRequestSubstate( "exit@aggressive" );
232  self ‪vehicle_ai::waittill_asm_complete( "exit@aggressive", 1.6 );
233  }
234 
235  self ‪vehicle_ai::Cooldown( "state_change", 15 );
236 
237  self thread ‪prevent_stuck();
238  self thread ‪nudge_collision();
239  self thread ‪state_range_combat_attack();
240 
241  self SetSpeed( self.settings.defaultMoveSpeed );
242  self ASMRequestSubstate( "locomotion@movement" );
243 
244  self.dont_move = undefined;
245 
246  for( ;; )
247  {
248  if ( !IsDefined( self.enemy ) )
249  {
250  self ‪force_get_enemies();
251  wait 0.1;
252  continue;
253  }
254  else if ( self.dont_move === true )
255  {
256  wait 0.1;
257  continue;
258  }
259 
260  if ( IsDefined( self.can_reach_enemy ) )
261  {
262  if ( !self [[ self.can_reach_enemy ]]() )
263  {
264  wait 0.1;
265  continue;
266  }
267  }
268 
269  if ( !self VehSeenRecently( self.enemy, 5 ) )
270  {
271  self.current_pathto_pos = ‪spider_get_target_position();
272  }
273  else
274  {
275  self.current_pathto_pos = ‪GetNextMovePosition_ranged( self.enemy );
276  }
277 
278  if ( IsDefined( self.current_pathto_pos ) )
279  {
280  if ( self SetVehGoalPos( self.current_pathto_pos, false, true ) )
281  {
283  }
284  }
285 
287  }
288 }
289 
291 {
292  self endon( "change_state" );
293  self endon( "death" );
294 
295  for( ;; )
296  {
297  if ( !IsDefined( self.enemy ) )
298  {
299  wait 0.1;
300  continue;
301  }
302 
303  state_params = SpawnStruct();
304  state_params.playTransition = true;
305  self ‪vehicle_ai::evaluate_connections( undefined, state_params );
306 
307  can_attack = true;
308  foreach( player in level.players )
309  {
310  self GetPerfectInfo( player, false );
311  if ( player.b_is_designated_target === true && self.enemy.b_is_designated_target !== true )
312  {
313  self GetPerfectInfo( player, true );
314  self SetPersonalThreatBias( player, 100000, 2.0 );
315  can_attack = false;
316  }
317  }
318 
319  if ( can_attack )
320  {
321  if ( self vehCanSee( self.enemy ) )
322  {
323  self SetLookAtEnt( self.enemy );
324  self SetTurretTargetEnt( self.enemy );
325  }
326 
327  if ( Distance2DSquared( self.origin, self.enemy.origin ) < ‪SQR( self.settings.engagementDistMax * 1.5 ) && ‪vehicle_ai::IsCooldownReady( "rocket" ) && self VehCanSee( self.enemy ) /*&& self.turretontarget*/ )
328  {
329  self ‪do_ranged_attack( self.enemy );
330  wait 0.5;
331  }
332  }
333 
334  wait 0.1;
335  }
336 }
337 
338 function ‪do_ranged_attack( enemy )
339 {
340  self notify( "near_goal" );
341  self ‪vehicle_ai::ClearAllMovement( true );
342  self.dont_move = true;
343 
344  self SetLookAtEnt( enemy );
345  self SetTurretTargetEnt( enemy );
346  self SetVehGoalPos( enemy.origin, false, false );
347 
348  targetAngleDiff = 30;
349  v_to_enemy = ‪FLAT_ORIGIN( (enemy.origin - self.origin) );
350  goalAngles = VectortoAngles( v_to_enemy );
351  angleDiff = AbsAngleClamp180( self.angles[1] - goalAngles[1] );
352  angleAdjustingStart = GetTime();
353  while( angleDiff > targetAngleDiff && ‪vehicle_ai::TimeSince( angleAdjustingStart ) < 0.8 )
354  {
355  angleDiff = AbsAngleClamp180( self.angles[1] - goalAngles[1] );
357  }
358 
359  self ‪vehicle_ai::ClearAllMovement( true );
360 
361  if ( angleDiff <= targetAngleDiff )
362  {
363  self ASMRequestSubstate( "fire@stationary" );
364 
365  timedout = self ‪util::waittill_notify_or_timeout( "spider_fire", 5 );
366  if ( timedout !== true )
367  {
368  self FireWeapon();
369  self ‪vehicle_ai::Cooldown( "rocket", 3 );
370 
371  self ‪vehicle_ai::waittill_asm_complete( "fire@stationary", 5 );
372  }
373  }
374 
375  self ASMRequestSubstate( "locomotion@movement" );
376  self.dont_move = undefined;
377 }
378 
380 {
381  self.switch_to_melee = true;
382 }
383 
384 function ‪should_switch_to_melee( from_state, to_state, connection )
385 {
386 /#
387  if ( ‪NO_SWITCH_ON() )
388  {
389  return false;
390  }
391 #/
392 
393  if ( !‪vehicle_ai::IsCooldownReady( "state_change" ) )
394  {
395  return false;
396  }
397 
398  if ( !isdefined( self.enemy ) )
399  {
400  return false;
401  }
402 
403  if ( self.‪switch_to_melee === true ||
404  ( Distance2DSquared( self.origin, self.enemy.origin ) < ‪SQR( self.settings.meleedist ) && Abs( self.origin[2] - self.enemy.origin[2] ) < self.settings.meleedist ) )
405  {
406  return true;
407  }
408 
409  return false;
410 }
411 // ----------------------------------------------
412 
413 // ----------------------------------------------
414 // State: melee combat
415 // ----------------------------------------------
417 {
418  self endon( "change_state" );
419  self endon( "death" );
420 
421  if ( params.playTransition === true )
422  {
423  self ‪vehicle_ai::ClearAllMovement( true );
424  self ASMRequestSubstate( "enter@aggressive" );
425  self ‪vehicle_ai::waittill_asm_complete( "enter@aggressive", 1.6 );
426  }
427 
428  self ‪vehicle_ai::Cooldown( "state_change", 8 );
429 
430  self thread ‪prevent_stuck();
431  self thread ‪nudge_collision();
432  self thread ‪state_melee_combat_attack();
433 
434  self.pathfailcount = 0;
435  self.switch_to_melee = undefined;
436 
437  self SetSpeed( self.settings.defaultMoveSpeed * 1.5 );
438 
439  self ASMRequestSubstate( "locomotion@aggressive" );
440 
441  self.dont_move = undefined;
442 
443  wait 0.5;
444 
445  for( ;; )
446  {
447  foreach( player in level.players )
448  {
449  self GetPerfectInfo( player, true );
450  if ( player.b_is_designated_target === true )
451  {
452  self SetPersonalThreatBias( player, 100000, 3.0 );
453  }
454  }
455 
456  if ( !IsDefined( self.enemy ) )
457  {
458  self ‪force_get_enemies();
459  wait 0.1;
460  continue;
461  }
462  else if ( self.dont_move === true )
463  {
464  wait 0.1;
465  continue;
466  }
467 
468  if ( IsDefined( self.can_reach_enemy ) )
469  {
470  if ( !self [[ self.can_reach_enemy ]]() )
471  {
472  wait 0.1;
473  continue;
474  }
475  }
476 
477  self.foundpath = false;
478 
479  targetPos = ‪spider_get_target_position();
480 
481  if ( isdefined( targetPos ) )
482  {
483  // Prevent training by not sending every raps to the same location unless they are getting close
484  if( DistanceSquared( self.origin, targetPos ) > ‪SQR( 1000 ) && self IsPosInClaimedLocation( targetPos ) )
485  {
486  queryResult = PositionQuery_Source_Navigation( targetPos, 0, self.settings.max_move_dist, self.settings.max_move_dist, self.radius, self );
487 
488  PositionQuery_Filter_InClaimedLocation( queryResult, self.enemy );
489 
490  best_point = undefined;
491  best_score = -999999;
492  foreach ( point in queryResult.data )
493  {
494  ADD_POINT_SCORE( point, "distToOrigin", MapFloat( 0, 200, 0, -200, Distance( point.origin, queryResult.origin ) ) );
495  ADD_POINT_SCORE( point, "heightToOrigin", MapFloat( 50, 200, 0, -200, Abs( point.origin[2] - queryResult.origin[2] ) ) );
496 
497  if( point.inClaimedLocation === true )
498  {
499  ADD_POINT_SCORE( point, "inClaimedLocation", -500 );
500  }
501 
502  if ( point.score > best_score )
503  {
504  best_score = point.score;
505  best_point = point;
506  }
507  }
508 
509  self ‪vehicle_ai::PositionQuery_DebugScores( queryResult );
510 
511  if( isdefined( best_point ) )
512  {
513  targetPos = best_point.origin;
514  }
515  }
516 
517  self SetVehGoalPos( targetPos, false, true );
518  self.foundpath = self ‪vehicle_ai::waittill_pathresult();
519 
520  if ( self.foundpath )
521  {
522  self.current_pathto_pos = targetPos;
523  self thread ‪path_update_interrupt_melee();
524 
525  self.pathfailcount = 0;
526 
528  }
529  }
530 
531  if ( !self.foundpath )
532  {
533  self.pathfailcount++;
534 
535  if ( self.pathfailcount > 2 )
536  {
537  if( IsDefined( self.enemy ) )
538  {
539  // Try to change enemies
540  self SetPersonalThreatBias( self.enemy, -2000, 5.0 );
541  }
542  }
543 
544  wait 0.1;
545 
546  // just try to path strait to a nearby position on the path
547  queryResult = PositionQuery_Source_Navigation( self.origin, 0, self.settings.max_move_dist, self.settings.max_move_dist, self.radius, self );
548 
549  if( queryResult.data.size )
550  {
551  point = queryResult.data[ randomint( queryResult.data.size ) ];
552 
553  self SetVehGoalPos( point.origin, false, false );
554  self.current_pathto_pos = undefined;
555  self thread ‪path_update_interrupt_melee();
556  wait 2;
557  self notify( "near_goal" ); // kill the path_update_interrupt just in case
558  }
559  }
560 
561  wait 0.2;
562  }
563 }
564 
566 {
567  self endon( "change_state" );
568  self endon( "death" );
569 
570  for( ;; )
571  {
572  state_params = SpawnStruct();
573  state_params.playTransition = true;
574 
575  if ( !IsDefined( self.enemy ) )
576  {
577  wait 0.1;
578  self ‪vehicle_ai::evaluate_connections( undefined, state_params );
579  continue;
580  }
581 
582  self ‪vehicle_ai::evaluate_connections( undefined, state_params );
583 
584  if ( self vehCanSee( self.enemy ) )
585  {
586  self SetLookAtEnt( self.enemy );
587  self SetTurretTargetEnt( self.enemy );
588  }
589 
590  if ( Distance2DSquared( self.origin, self.enemy.origin ) < ‪SQR( self.settings.meleereach ) && self VehCanSee( self.enemy ) )
591  {
592  if ( BulletTracePassed( self.origin + (0,0,10), self.enemy.origin + (0,0,20), false, self, self.enemy, false, true ) )
593  {
594  self ‪do_melee_attack( self.enemy );
595  wait 0.5;
596  }
597  }
598 
599  wait 0.1;
600  }
601 }
602 
603 function ‪do_melee_attack( enemy )
604 {
605  self notify( "near_goal" );
606  self ‪vehicle_ai::ClearAllMovement( true ); // TODO: bug in quadtank movement causing it sliding and poping
607  self.dont_move = true;
608  self ASMRequestSubstate( "melee@stationary" );
609 
610  timedout = self ‪util::waittill_notify_or_timeout( "spider_melee", 3 );
611  if ( timedout !== true )
612  {
613  if ( isalive( enemy ) && Distance2DSquared( self.origin, enemy.origin ) < ‪SQR( self.settings.meleereach * 1.2 ) )
614  {
615  enemy DoDamage( self.settings.meleedamage, self.origin, self, self );
616  }
617 
618  self ‪vehicle_ai::waittill_asm_complete( "melee@stationary", 2 );
619  }
620 
621  self ASMRequestSubstate( "locomotion@aggressive" );
622  self.dont_move = undefined;
623 }
624 
625 function ‪should_switch_to_range( from_state, to_state, connection )
626 {
627 /#
628  if ( ‪NO_SWITCH_ON() )
629  {
630  return false;
631  }
632 #/
633 
634  if ( self.pathfailcount > 4 )
635  {
636  return true;
637  }
638 
639  if ( !‪vehicle_ai::IsCooldownReady( "state_change" ) )
640  {
641  return false;
642  }
643 
644  if ( IsAlive( self.enemy ) && Distance2DSquared( self.origin, self.enemy.origin ) > ‪SQR( self.settings.meleedist * 4 ) )
645  {
646  return true;
647  }
648 
649  if ( !isdefined( self.enemy ) )
650  {
651  return true;
652  }
653 
654  return false;
655 }
656 // ----------------------------------------------
657 
659 {
660  self endon( "change_state" );
661  self endon( "death" );
662  self notify( "end_prevent_stuck" );
663  self endon( "end_prevent_stuck" );
664 
665  wait 2;
666 
667  count = 0;
668  previous_origin = undefined;
669 
670  // detonate if position hasn't change for N counts
671  while( true )
672  {
673  if ( isdefined( previous_origin ) && DistanceSquared( previous_origin, self.origin ) < ‪SQR( 0.1 ) && !‪IS_TRUE( level.bzm_worldPaused ) )
674  {
675  count++;
676  }
677  else
678  {
679  previous_origin = self.origin;
680  count = 0;
681  }
682 
683  if ( count > 10 )
684  {
685  self.pathfailcount = 10;
686  // TODO: teleport (e.g. dig into the ground)
687  }
688 
689  wait 1;
690  }
691 }
692 
694 {
695  if( self.goalforced )
696  {
697  return self.goalpos;
698  }
699 
700  if( isdefined( self.settings.all_knowing ) )
701  {
702  if( isdefined( self.enemy ) )
703  {
704  target_pos = self.enemy.origin;
705  }
706  }
707  else
708  {
710  }
711 
712  enemy = self.enemy;
713 
714  if( isdefined( target_pos ) )
715  {
716  target_pos_onnavmesh = GetClosestPointOnNavMesh( target_pos, self.settings.detonation_distance * 1.5, self.radius, ‪NMMF_ALL & ~‪NMMF_NOVEHICLE );
717  }
718 
719  // if we can't find a position on the navmesh then just keep going to the current position
720  if( !isdefined( target_pos_onnavmesh ) )
721  {
722  if( isdefined( self.enemy ) )
723  {
724  self SetPersonalThreatBias( self.enemy, -2000, 5.0 );
725  }
726 
727  if ( isdefined( self.current_pathto_pos ) && DistanceSquared( self.origin, self.current_pathto_pos ) > ‪SQR( self.settings.meleereach ) )
728  {
729  return self.current_pathto_pos;
730  }
731  else
732  {
733  return undefined;
734  }
735  }
736  else if ( isdefined( self.enemy ) )
737  {
738  if ( DistanceSquared( target_pos, target_pos_onnavmesh ) > ‪SQR( self.settings.detonation_distance * 0.9 ) )
739  {
740  self SetPersonalThreatBias( self.enemy, -2000, 5.0 );
741  }
742  }
743 
744  if( isdefined( enemy ) && IsPlayer( enemy ) )
745  {
746  enemy_vel_offset = enemy GetVelocity() * 0.5;
747 
748  enemy_look_dir_offset = AnglesToForward( enemy.angles );
749  if( distance2dSquared( self.origin, enemy.origin ) > ‪SQR( 500 ) )
750  {
751  enemy_look_dir_offset *= 110;
752  }
753  else
754  {
755  enemy_look_dir_offset *= 35;
756  }
757 
758  offset = enemy_vel_offset + enemy_look_dir_offset;
759  offset = ‪FLAT_ORIGIN( offset ); // just 2d
760 
761  if( TracePassedOnNavMesh( target_pos_onnavmesh, target_pos + offset ) )
762  {
763  target_pos += offset;
764  }
765  else
766  {
767  target_pos = target_pos_onnavmesh;
768  }
769  }
770  else
771  {
772  target_pos = target_pos_onnavmesh;
773  }
774 
775  return target_pos;
776 }
777 
779 {
780  self endon( "death" );
781  self endon( "change_state" );
782  self endon( "near_goal" );
783  self endon( "reached_end_node" );
784 
785  //ensure only one path_update_interrupt is running
786  self notify( "clear_interrupt_threads" );
787  self endon( "clear_interrupt_threads" );
788 
789  wait .1; // sometimes endons may get fired off so wait a bit for the goal to get updated
790 
791  while( 1 )
792  {
793  if( isdefined( self.current_pathto_pos ) )
794  {
795  if( distance2dSquared( self.current_pathto_pos, self.goalpos ) > ‪SQR( self.goalRadius ) )
796  {
797  wait 0.5;
798 
799  self notify( "near_goal" );
800  }
801 
802  targetPos = ‪spider_get_target_position();
803  if ( isdefined( targetPos ) )
804  {
805  // optimization, don't keep repathing as often when far away
806  if( DistanceSquared( self.origin, targetPos ) > ‪SQR( 1000 ) )
807  {
808  repath_range = self.settings.repath_range * 2;
809  wait 0.1;
810  }
811  else
812  {
813  repath_range = self.settings.repath_range;
814  }
815 
816  if( distance2dSquared( self.current_pathto_pos, targetPos ) > ‪SQR( repath_range ) )
817  {
818  self notify( "near_goal" );
819  }
820  }
821 
822  if( isdefined( self.enemy ) && IsPlayer( self.enemy ) )
823  {
824  forward = AnglesToForward( self.enemy GetPlayerAngles() );
825  dir_to_raps = self.origin - self.enemy.origin;
826 
827  speedToUse = self.settings.defaultMoveSpeed * 2;
828  if( VectorDot( forward, dir_to_raps ) > 0 )
829  {
830  self SetSpeed( speedToUse );
831  }
832  else
833  {
834  self SetSpeed( speedToUse * 0.75 );
835  }
836  }
837  else
838  {
839  speedToUse = self.settings.defaultMoveSpeed * 2;
840  self SetSpeed( speedToUse );
841  }
842 
843  wait 0.2;
844  }
845  else
846  {
847  wait 0.4;
848  }
849  }
850 }
851 
853 {
854  self endon( "death" );
855  self endon( "change_state" );
856  self notify( "end_nudge_collision" );
857  self endon( "end_nudge_collision" );
858 
859  while ( 1 )
860  {
861  self waittill( "veh_collision", velocity, normal );
862  ang_vel = self GetAngularVelocity() * 0.8;
863  self SetAngularVelocity( ang_vel );
864 
865  // bounce off walls
866  if ( IsAlive( self ) && VectorDot( normal, (0,0,1) ) < 0.5 ) // angle is more than 60 degree away from up direction
867  {
868  self SetVehVelocity( self.velocity + normal * 400 );
869  }
870  }
871 }
872 
873 
875 {
876  foreach( player in level.players )
877  {
878  if( self ‪util::IsEnemyPlayer( player ) && !player.ignoreme )
879  {
880  self GetPerfectInfo( player, true );
881  return;
882  }
883  }
884 }
885 
886 function ‪spider_callback_damage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal )
887 {
888  if ( IsAlive( eAttacker ) && eAttacker.team === self.team )
889  {
890  return 0;
891  }
892 
893  return iDamage;
894 }
‪call_custom_add_state_callbacks
‪function call_custom_add_state_callbacks()
Definition: vehicle_ai_shared.gsc:1152
‪defaultRole
‪function defaultRole()
Definition: _spider.gsc:90
‪nudge_collision
‪function nudge_collision()
Definition: _spider.gsc:852
‪add_state
‪function add_state(name, enter_func, update_func, exit_func, reenter_func)
Definition: statemachine_shared.gsc:59
‪evaluate_connections
‪function evaluate_connections(eval_func, params)
Definition: statemachine_shared.gsc:266
‪SPIDER_MOVE_DIST_MIN
‪#define SPIDER_MOVE_DIST_MIN
Definition: _spider.gsc:28
‪switch_to_melee
‪function switch_to_melee()
Definition: _spider.gsc:379
‪NMMF_NOVEHICLE
‪#define NMMF_NOVEHICLE
Definition: archetype_shared.gsh:49
‪should_switch_to_range
‪function should_switch_to_range(from_state, to_state, connection)
Definition: _spider.gsc:625
‪ClearAllMovement
‪function ClearAllMovement(zeroOutSpeed=false)
Definition: vehicle_ai_shared.gsc:707
‪state_range_combat_attack
‪function state_range_combat_attack()
Definition: _spider.gsc:290
‪state_melee_combat_update
‪function state_melee_combat_update(params)
Definition: _spider.gsc:416
‪IsCooldownReady
‪function IsCooldownReady(name, timeForward_seconds)
Definition: vehicle_ai_shared.gsc:1968
‪force_get_enemies
‪function force_get_enemies()
Definition: _spider.gsc:874
‪spider_get_target_position
‪function spider_get_target_position()
Definition: _spider.gsc:693
‪DeleteWhenSafe
‪function DeleteWhenSafe(time=4)
Definition: vehicle_death_shared.gsc:1761
‪GetTargetPos
‪function GetTargetPos(target, geteye)
Definition: vehicle_ai_shared.gsc:115
‪IS_TRUE
‪#define IS_TRUE(__a)
Definition: shared.gsh:251
‪spider_initialize
‪function spider_initialize()
Definition: _spider.gsc:47
‪SQR
‪#define SQR(__var)
Definition: shared.gsh:293
‪IsEnemyPlayer
‪function IsEnemyPlayer(player)
Definition: util_shared.csc:1220
‪state_range_combat_update
‪function state_range_combat_update(params)
Definition: _spider.gsc:220
‪StartInitialState
‪function StartInitialState(defaultState="combat")
Definition: vehicle_ai_shared.gsc:866
‪NO_SWITCH_ON
‪function NO_SWITCH_ON()
Definition: _spider.gsc:42
‪GetNextMovePosition_ranged
‪function GetNextMovePosition_ranged(enemy)
Definition: _spider.gsc:140
‪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
‪state_melee_combat_attack
‪function state_melee_combat_attack()
Definition: _spider.gsc:565
‪__init__
‪function __init__()
Definition: _spider.gsc:34
‪NMMF_ALL
‪#define NMMF_ALL
Definition: archetype_shared.gsh:50
‪waittill_notify_or_timeout
‪function waittill_notify_or_timeout(msg, timer)
Definition: util_shared.csc:473
‪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
‪death_fx
‪function death_fx()
Definition: _qrdrone.gsc:958
‪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
‪PositionQuery_Filter_OutOfGoalAnchor
‪function PositionQuery_Filter_OutOfGoalAnchor(queryResult, tolerance=1)
Definition: vehicle_ai_shared.gsc:2104
‪REGISTER_SYSTEM
‪#define REGISTER_SYSTEM(__sys, __func_init_preload, __reqs)
Definition: shared.gsh:204
‪SPIDER_MOVE_DIST_MAX
‪#define SPIDER_MOVE_DIST_MAX
Definition: _spider.gsc:27
‪do_melee_attack
‪function do_melee_attack(enemy)
Definition: _spider.gsc:603
‪spider_callback_damage
‪function spider_callback_damage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal)
Definition: _spider.gsc:886
‪do_ranged_attack
‪function do_ranged_attack(enemy)
Definition: _spider.gsc:338
‪state_driving_update
‪function state_driving_update(params)
Definition: _spider.gsc:129
‪waittill_asm_complete
‪function waittill_asm_complete(substate_to_wait, timeout=10)
Definition: vehicle_ai_shared.gsc:374
‪state_death_update
‪function state_death_update(params)
Definition: _spider.gsc:114
‪PositionQuery_Filter_EngagementDist
‪function PositionQuery_Filter_EngagementDist(queryResult, enemy, engagementDistanceMin, engagementDistanceMax)
Definition: vehicle_ai_shared.gsc:2116
‪RegisterVehicleBlackBoardAttributes
‪function RegisterVehicleBlackBoardAttributes()
Definition: blackboard_vehicle.gsc:24
‪prevent_stuck
‪function prevent_stuck()
Definition: _spider.gsc:658
‪CreateBlackBoardForEntity
‪function CreateBlackBoardForEntity(entity)
Definition: blackboard.gsc:77
‪TimeSince
‪function TimeSince(startTimeInMilliseconds)
Definition: vehicle_ai_shared.gsc:1930
‪path_update_interrupt_melee
‪function path_update_interrupt_melee()
Definition: _spider.gsc:778
‪add_utility_connection
‪function add_utility_connection(from_state_name, to_state_name, checkfunc, defaultScore)
Definition: statemachine_shared.gsc:112
‪GetEnemyTarget
‪function GetEnemyTarget()
Definition: vehicle_ai_shared.gsc:101
‪PositionQuery_Filter_DistAwayFromTarget
‪function PositionQuery_Filter_DistAwayFromTarget(queryResult, targetArray, distance, tooClosePenalty)
Definition: vehicle_ai_shared.gsc:2168
‪should_switch_to_melee
‪function should_switch_to_melee(from_state, to_state, connection)
Definition: _spider.gsc:384
‪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
‪get_state_callbacks
‪function get_state_callbacks(statename)
Definition: vehicle_ai_shared.gsc:927
‪WAIT_SERVER_FRAME
‪#define WAIT_SERVER_FRAME
Definition: shared.gsh:265