‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
_siegebot.gsc
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // #using
3 // ----------------------------------------------------------------------------
4 #using scripts\codescripts\struct;
5 
6 #using scripts\shared\gameskill_shared;
7 #using scripts\shared\math_shared;
8 #using scripts\shared\statemachine_shared;
9 #using scripts\shared\system_shared;
10 #using scripts\shared\array_shared;
11 #using scripts\shared\util_shared;
12 
13 #using scripts\shared\vehicle_shared;
14 #using scripts\shared\vehicle_death_shared;
15 #using scripts\shared\vehicle_ai_shared;
16 
17 #using scripts\shared\ai\systems\blackboard;
18 #using scripts\shared\ai\blackboard_vehicle;
19 
20 #using scripts\shared\turret_shared;
21 #using scripts\shared\weapons\_spike_charge_siegebot;
22 #insert scripts\shared\shared.gsh;
23 #insert scripts\shared\statemachine.gsh;
24 #insert scripts\shared\archetype_shared\archetype_shared.gsh;
25 
26 #insert scripts\shared\ai\utility.gsh;
27 
28 #define JUMP_COOLDOWN 7
29 #define DEBUG_ON false
30 
31 #namespace siegebot;
32 
33 ‪REGISTER_SYSTEM( "siegebot", &‪__init__, undefined )
34 
35 #using_animtree( "generic" );
36 
37 function ‪__init__()
38 {
39  vehicle::add_main_callback( "siegebot", &‪siegebot_initialize );
40 }
41 
43 {
44  self useanimtree( #animtree );
45 
48 
49  self.health = self.healthdefault;
50 
52 
53  Target_Set( self, ( 0, 0, 84 ) );
54 
55  self EnableAimAssist();
56  self SetNearGoalNotifyDist( 40 );
57 
58  self.fovcosine = 0.5; // +/-60 degrees = 120 fov
59  self.fovcosinebusy = 0.5;
60  self.maxsightdistsqrd = ‪SQR( 10000 );
61 
62  assert( isdefined( self.scriptbundlesettings ) );
63 
64  self.settings = ‪struct::get_script_bundle( "vehiclecustomsettings", self.scriptbundlesettings );
65 
66  self.goalRadius = 9999999;
67  self.goalHeight = 5000;
68  self SetGoal( self.origin, false, self.goalRadius, self.goalHeight );
69 
70  self.overrideVehicleDamage = &‪siegebot_callback_damage;
71 
73 
74  self SetGunnerTurretOnTargetRange( 0, self.settings.gunner_turret_on_target_range );
75 
76  self ASMRequestSubstate( "locomotion@movement" );
77 
78  if( self.vehicletype === "spawner_enemy_boss_siegebot_zombietron" )
79  {
80  self ASMSetAnimationRate( 0.5 );
81  self HidePart( "tag_turret_canopy_animate" );
82  self HidePart( "tag_turret_panel_01_d0" );
83  self HidePart( "tag_turret_panel_02_d0" );
84  self HidePart( "tag_turret_panel_03_d0" );
85  self HidePart( "tag_turret_panel_04_d0" );
86  self HidePart( "tag_turret_panel_05_d0" );
87  }
88  else if( self.vehicletype == "zombietron_veh_siegebot" )
89  {
90  self ASMSetAnimationRate( 1.429 );
91  }
92 
93  self ‪initJumpStruct();
94 
95  //disable some cybercom abilities
96  if( IsDefined( level.vehicle_initializer_cb ) )
97  {
98  [[level.vehicle_initializer_cb]]( self );
99  }
100 
101  self.ignoreFireFly = true;
102  self.ignoreDecoy = true;
104 
105  self thread ‪vehicle_ai::target_hijackers();
106 
107  if( !SessionModeIsMultiplayerGame() )
108  ‪defaultRole();
109 }
110 
111 
113 {
115 
116  scale_up = mapfloat( 0, 9, 0.8, 2.0, value );
117  scale_down = mapfloat( 0, 9, 1.0, 0.5, value );
118 
119  self.difficulty_scale_up = scale_up;
120  self.difficulty_scale_down = scale_down;
121 }
122 
123 function ‪defaultRole()
124 {
126 
127  self ‪vehicle_ai::get_state_callbacks( "combat" ).update_func = &‪state_combat_update;
128  self ‪vehicle_ai::get_state_callbacks( "combat" ).exit_func = &‪state_combat_exit;
129 
130  self ‪vehicle_ai::get_state_callbacks( "driving" ).update_func = &‪siegebot_driving;
131 
132  self ‪vehicle_ai::get_state_callbacks( "death" ).update_func = &‪state_death_update;
133 
134  self ‪vehicle_ai::get_state_callbacks( "pain" ).update_func = &‪pain_update;
135 
136  self ‪vehicle_ai::get_state_callbacks( "emped" ).enter_func = &‪emped_enter;
137  self ‪vehicle_ai::get_state_callbacks( "emped" ).update_func = &‪emped_update;
138  self ‪vehicle_ai::get_state_callbacks( "emped" ).exit_func = &‪emped_exit;
139  self ‪vehicle_ai::get_state_callbacks( "emped" ).reenter_func = &‪emped_reenter;
140 
141  self ‪vehicle_ai::add_state( "jump",
145 
147  ‪vehicle_ai::add_utility_connection( "jump", "combat" );
148 
149  self ‪vehicle_ai::add_state( "unaware",
150  undefined,
152  undefined );
153  // don't use this for now unless we really need it
154 
156 }
157 
158 // ----------------------------------------------
159 // State: death
160 // ----------------------------------------------
161 function ‪state_death_update( params )
162 {
163  self endon( "death" );
164  self endon( "nodeath_thread" );
165 
166  // Need to prep the death model
167  StreamerModelHint( self.deathmodel, 6 );
168 
169  death_type = ‪vehicle_ai::get_death_type( params );
170  if ( !isdefined( death_type ) )
171  {
172  params.death_type = "gibbed";
173  death_type = params.death_type;
174  }
175 
176  self ‪clean_up_spawned();
177 
178  self SetTurretSpinning( false );
180 
182  self playsound("veh_quadtank_sparks");
183 
184  if ( self.vehicletype === "spawner_enemy_boss_siegebot_zombietron" )
185  {
186  self ASMSetAnimationRate( 1.0 );
187  }
188 
189  self.turretRotScale = 3;
190  self SetTurretTargetRelativeAngles( (0,0,0), 0 );
191  self SetTurretTargetRelativeAngles( (0,0,0), 1 );
192  self SetTurretTargetRelativeAngles( (0,0,0), 2 );
193 
194  self ASMRequestSubstate( "death@stationary" );
195 
196  self waittill( "model_swap" ); // give the streamer time to load
197  self ‪vehicle_death::set_death_model( self.deathmodel, self.modelswapdelay );
200 
201  self waittill( "bodyfall large" );
202 
203  // falling damage
204  self RadiusDamage( self.origin + (0,0,10), self.radius * 0.8, 150, 60, self, "MOD_CRUSH" );
205 
206  //BadPlace_Box( "", 0, self.origin, 50, "neutral" );
207 
208  ‪vehicle_ai::waittill_asm_complete( "death@stationary", 3 );
209 
210  self thread ‪vehicle_death::CleanUp();
212 }
213 
214 // ----------------------------------------------
215 // State: scripted
216 // ----------------------------------------------
217 function ‪siegebot_driving( params )
218 {
219  self thread ‪siegebot_player_fireupdate();
220  self thread ‪siegebot_kill_on_tilting();
221 
222  self ClearTargetEntity();
223  self CancelAIMove();
224  self ClearVehGoalPos();
225 }
226 
228 {
229  self endon( "death" );
230  self endon( "exit_vehicle" );
231 
232  tileCount = 0;
233 
234  while( 1 )
235  {
236  selfup = AnglesToUp( self.angles );
237  worldup = ( 0, 0, 1 );
238 
239  if ( VectorDot( selfup, worldup ) < 0.64 ) // angle diff more than 50 degree
240  {
241  tileCount += 1;
242  }
243  else
244  {
245  tileCount = 0;
246  }
247 
248  if ( tileCount > 20 ) // more than 1 full second
249  {
250  driver = self GetSeatOccupant( 0 );
251  self Kill( self.origin );
252  }
253 
255  }
256 }
257 
259 {
260  self endon( "death" );
261  self endon( "exit_vehicle" );
262 
263  weapon = self SeatGetWeapon( 2 );
264  fireTime = weapon.fireTime;
265  driver = self GetSeatOccupant( 0 );
266 
267  self thread ‪siegebot_player_aimUpdate();
268 
269  while( 1 )
270  {
271  if( driver attackButtonPressed() )
272  {
273  self FireWeapon( 2 );
274  wait fireTime;
275  }
276  else
277  {
279  }
280  }
281 }
282 
284 {
285  self endon( "death" );
286  self endon( "exit_vehicle" );
287 
288  while( 1 )
289  {
290  self SetGunnerTargetVec( self GetGunnerTargetVec( 0 ), 1 );
292  }
293 }
294 // State: scripted ----------------------------------
295 
296 // ----------------------------------------------
297 // State: emped
298 // ----------------------------------------------
299 function ‪emped_enter( params )
300 {
301  if ( !isdefined( self.abnormal_status ) )
302  {
303  self.abnormal_status = spawnStruct();
304  }
305 
306  self.abnormal_status.emped = true;
307  self.abnormal_status.attacker = params.notify_param[1];
308  self.abnormal_status.inflictor = params.notify_param[2];
309 
310  self ‪vehicle::toggle_emp_fx( true );
311 }
312 
313 function ‪emped_update( params )
314 {
315  self endon( "death" );
316  self endon( "change_state" );
317 
319 
320  if ( self.vehicletype === "spawner_enemy_boss_siegebot_zombietron" )
321  {
322  self ASMSetAnimationRate( 1.0 );
323  }
324 
325  asmState = "damage_2@pain";
326  self ASMRequestSubstate( asmState );
327  self ‪vehicle_ai::waittill_asm_complete( asmState, 3 );
328 
329  self SetBrake( 0 );
330 
332 }
333 
334 function ‪emped_exit( params )
335 {
336 }
337 
338 function ‪emped_reenter( params )
339 {
340  return false;
341 }
342 // State: emped ----------------------------------
343 
344 // ----------------------------------------------
345 // State: pain
346 // ----------------------------------------------
347 function ‪pain_toggle( enabled )
348 {
349  self._enablePain = enabled;
350 }
351 
352 function ‪pain_update( params )
353 {
354  self endon( "death" );
355  self endon( "change_state" );
356 
358 
359  if ( self.vehicletype === "spawner_enemy_boss_siegebot_zombietron" )
360  {
361  self ASMSetAnimationRate( 1.0 );
362  }
363 
364  if ( self.newDamageLevel == 3 )
365  {
366  asmState = "damage_2@pain";
367  }
368  else
369  {
370  asmState = "damage_1@pain";
371  }
372 
373  self ASMRequestSubstate( asmState );
374  self ‪vehicle_ai::waittill_asm_complete( asmState, 1.5 );
375 
376  self SetBrake( 0 );
377 
379 }
380 // State: pain ----------------------------------
381 
382 // ----------------------------------------------
383 // State: unaware
384 // ----------------------------------------------
385 function ‪state_unaware_update( params )
386 {
387  self endon( "death" );
388  self endon( "change_state" );
389 
390  self SetTurretTargetRelativeAngles( (0,90,0), 1 );
391  self SetTurretTargetRelativeAngles( (0,90,0), 2 );
392 
393  self thread ‪Movement_Thread_Unaware();
394 
395  while ( true )
396  {
398  wait 1;
399  }
400 }
401 
403 {
404  self endon( "death" );
405  self endon( "change_state" );
406  self notify( "end_movement_thread" );
407  self endon( "end_movement_thread" );
408 
409  while( true )
410  {
411  self.current_pathto_pos = self ‪GetNextMovePosition_unaware();
412 
413  foundpath = self SetVehGoalPos( self.current_pathto_pos, false, true );
414 
415  if ( foundPath )
416  {
418  self thread ‪path_update_interrupt();
420  self notify( "near_goal" ); // kill path_update_interrupt thread
421  self CancelAIMove();
422  self ClearVehGoalPos();
423 
424  ‪Scan();
425  }
426  else
427  {
428  wait 1;
429  }
430 
432  }
433 }
434 
436 {
437  if( self.goalforced )
438  {
439  return self.goalpos;
440  }
441 
442  minSearchRadius = 500;
443  maxSearchRadius = 1500;
444  halfHeight = 400;
445  spacing = 80;
446 
447  queryResult = PositionQuery_Source_Navigation( self.origin, minSearchRadius, maxSearchRadius, halfHeight, spacing, self, spacing );
448  PositionQuery_Filter_DistanceToGoal( queryResult, self );
450 
451  forward = AnglesToForward( self.angles );
452  foreach ( point in queryResult.data )
453  {
454  ADD_POINT_SCORE( point, "random", randomFloatRange( 0, 30 ) );
455 
456  pointDirection = VectorNormalize( point.origin - self.origin );
457  factor = VectorDot( pointDirection, forward );
458  if ( factor > 0.7 )
459  {
460  ADD_POINT_SCORE( point, "directionDiff", 600 );
461  }
462  else if ( factor > 0 )
463  {
464  ADD_POINT_SCORE( point, "directionDiff", 0 );
465  }
466  else if ( factor > -0.5 )
467  {
468  ADD_POINT_SCORE( point, "directionDiff", -600 );
469  }
470  else
471  {
472  ADD_POINT_SCORE( point, "directionDiff", -1200 );
473  }
474  }
475 
477  self ‪vehicle_ai::PositionQuery_DebugScores( queryResult );
478 
479  if( queryResult.data.size == 0 )
480  return self.origin;
481 
482  return queryResult.data[0].origin;
483 }
484 
485 // ----------------------------------------------
486 // State: jump
487 // ----------------------------------------------
489 {
490  if ( isdefined( self.jump ) && isDefined(self.jump.linkEnt) )
491  {
492  self.jump.linkEnt Delete();
493  }
494 }
495 function ‪clean_up_spawnedOnDeath(entToWatch)
496 {
497  self endon("death");
498  entToWatch waittill("death");
499  self delete();
500 }
501 
502 
504 {
505  if ( isdefined( self.jump ) )
506  {
507  self Unlink();
508  self.jump.linkEnt Delete();
509  self.jump Delete();
510  }
511 
512  self.jump = spawnstruct();
513  self.jump.linkEnt = ‪Spawn( "script_origin", self.origin );
514  self.jump.linkEnt thread ‪clean_up_spawnedOnDeath(self);
515  self.jump.in_air = false;
516  self.jump.highgrounds = ‪struct::get_array( "balcony_point" );
517  self.jump.groundpoints = ‪struct::get_array( "ground_point" );
518 
519  //assert( self.jump.highgrounds.size > 0 );
520  //assert( self.jump.groundpoints.size > 0 );
521 }
522 
523 function ‪state_jump_can_enter( from_state, to_state, connection )
524 {
525  if(‪IS_TRUE(self.noJumping))
526  return false;
527 
528  return ( self.vehicletype === "spawner_enemy_boss_siegebot_zombietron" );
529 }
530 
531 function ‪state_jump_enter( params )
532 {
533  goal = params.jumpgoal;
534 
535  ‪trace = PhysicsTrace( goal + ( 0, 0, 500 ), goal - ( 0, 0, 10000 ), ( -10, -10, -10 ), ( 10, 10, 10 ), self, ‪PHYSICS_TRACE_MASK_VEHICLE );
536  if ( ‪DEBUG_ON )
537  {
538  /#debugstar( goal, 60000, (0,1,0) ); #/
539  /#debugstar( ‪trace[ "position" ], 60000, (0,1,0) ); #/
540  /#line(goal, ‪trace[ "position" ], (0,1,0), 1, false, 60000 ); #/
541  }
542  if ( ‪trace[ "fraction" ] < 1 )
543  {
544  goal = ‪trace[ "position" ];
545  }
546 
547  self.jump.goal = goal;
548 
549  params.scaleForward = 40;
550  params.gravityForce = (0, 0, -6);
551  params.upByHeight = 50;
552  params.landingState = "land@jump";
553 
554  self ‪pain_toggle( false );
555 
557 }
558 
559 function ‪state_jump_update( params )
560 {
561  self endon( "change_state" );
562  self endon( "death" );
563 
564  goal = self.jump.goal;
565 
566  self ‪face_target( goal );
567 
568  self.jump.linkEnt.origin = self.origin;
569  self.jump.linkEnt.angles = self.angles;
570 
572 
573  self LinkTo( self.jump.linkEnt );
574 
575  self.jump.in_air = true;
576 
577  if ( ‪DEBUG_ON )
578  {
579  /#debugstar( goal, 60000, (0,1,0) ); #/
580  /#debugstar( goal + (0,0,100), 60000, (0,1,0) ); #/
581  /#line(goal, goal + (0,0,100), (0,1,0), 1, false, 60000 ); #/
582  }
583 
584  // calculate distance and forces
585  totalDistance = Distance2D(goal, self.jump.linkEnt.origin);
586  forward = ‪FLAT_ORIGIN( ((goal - self.jump.linkEnt.origin) / totalDistance) );
587  upByDistance = MapFloat( 500, 2000, 46, 52, totalDistance );
588  antiGravityByDistance = 0;//MapFloat( 500, 2000, 0, 0.5, totalDistance );
589 
590  initVelocityUp = (0,0,1) * ( upByDistance + params.upByHeight );
591  initVelocityForward = forward * params.scaleForward * MapFloat( 500, 2000, 0.8, 1, totalDistance );
592  velocity = initVelocityUp + initVelocityForward;
593 
594  // start jumping
595  if ( self.vehicletype === "spawner_enemy_boss_siegebot_zombietron" )
596  {
597  self ASMSetAnimationRate( 1.0 );
598  }
599 
600  self ASMRequestSubstate( "inair@jump" );
601  self waittill( "engine_startup" );
602  self ‪vehicle::impact_fx( self.settings.startupfx1 );
603  self waittill( "leave_ground" );
604  self ‪vehicle::impact_fx( self.settings.takeofffx1 );
605 
606  while( true )
607  {
608  distanceToGoal = Distance2D(self.jump.linkEnt.origin, goal);
609 
610  antiGravityScaleUp = 1.0;//MapFloat( 0, 0.5, 0.6, 0, abs( 0.5 - distanceToGoal / totalDistance ) );
611  antiGravityScale = 1.0;//MapFloat( (self.radius * 1.0), (self.radius * 3), 0, 1, distanceToGoal );
612  antiGravity = (0,0,0);//antiGravityScale * antiGravityScaleUp * (-params.gravityForce) + (0,0,antiGravityByDistance);
613  if ( ‪DEBUG_ON ) /#line(self.jump.linkEnt.origin, self.jump.linkEnt.origin + antiGravity, (0,1,0), 1, false, 60000 ); #/
614 
615  velocityForwardScale = MapFloat( (self.radius * 1), (self.radius * 4), 0.2, 1, distanceToGoal );
616  velocityForward = initVelocityForward * velocityForwardScale;
617  if ( ‪DEBUG_ON ) /#line(self.jump.linkEnt.origin, self.jump.linkEnt.origin + velocityForward, (0,1,0), 1, false, 60000 ); #/
618 
619  oldVerticleSpeed = velocity[2];
620  velocity = (0,0, velocity[2]);
621  velocity += velocityForward + params.gravityForce + antiGravity;
622 
623  if ( oldVerticleSpeed > 0 && velocity[2] < 0 )
624  {
625  self ASMRequestSubstate( "fall@jump" );
626  }
627 
628  if ( velocity[2] < 0 && self.jump.linkEnt.origin[2] + velocity[2] < goal[2] )
629  {
630  break;
631  }
632 
633  heightThreshold = goal[2] + 110;
634  oldHeight = self.jump.linkEnt.origin[2];
635  self.jump.linkEnt.origin += velocity;
636 
637  if ( self.jump.linkEnt.origin[2] < heightThreshold && ( oldHeight > heightThreshold || ( oldVerticleSpeed > 0 && velocity[2] < 0 ) ) )
638  {
639  self notify( "start_landing" );
640  self ASMRequestSubstate( params.landingState );
641  }
642 
643  if ( ‪DEBUG_ON ) /#debugstar( self.jump.linkEnt.origin, 60000, (1,0,0) ); #/
645  }
646 
647  // landed
648  self.jump.linkEnt.origin = ‪FLAT_ORIGIN( self.jump.linkEnt.origin ) + ( 0, 0, goal[2] );
649  self notify( "land_crush" );
650 
651  // don't damage player, but crush player vehicle
652  foreach( player in level.players )
653  {
654  player._takedamage_old = player.takedamage;
655  player.takedamage = false;
656  }
657  self RadiusDamage( self.origin + ( 0,0,15 ), self.radiusdamageradius, self.radiusdamagemax, self.radiusdamagemin, self, "MOD_EXPLOSIVE" );
658 
659  foreach( player in level.players )
660  {
661  player.takedamage = player._takedamage_old;
662  player._takedamage_old = undefined;
663 
664  if ( Distance2DSquared( self.origin, player.origin ) < ‪SQR( 200 ) )
665  {
666  direction = ‪FLAT_ORIGIN( ( player.origin - self.origin ) );
667  if ( Abs( direction[0] ) < 0.01 && Abs( direction[1] ) < 0.01 )
668  {
669  direction = ( RandomFloatRange( 1, 2 ), RandomFloatRange( 1, 2 ), 0 );
670  }
671  direction = VectorNormalize( direction );
672  strength = 700;
673  player SetVelocity( player GetVelocity() + direction * strength );
674 
675  if ( player.health > 80 )
676  {
677  player DoDamage( player.health - 70, self.origin, self );
678  }
679  }
680  }
681 
682  self ‪vehicle::impact_fx( self.settings.landingfx1 );
684 
685  //rumble for landing from jump
686  //self clientfield::increment( "sarah_rumble_on_landing" );
687 
688  wait 0.3;
689 
690  self Unlink();
691 
693 
694  self.jump.in_air = false;
695 
696  self notify ( "jump_finished" );
697 
699 
700  self ‪vehicle_ai::waittill_asm_complete( params.landingState, 3 );
701 
703 }
704 
705 function ‪state_jump_exit( params )
706 {
707 }
708 
709 // ----------------------------------------------
710 // State: combat
711 // ----------------------------------------------
712 function ‪state_combat_update( params )
713 {
714  self endon( "death" );
715  self endon( "change_state" );
716 
717  self thread ‪Movement_Thread();
718  self thread ‪Attack_Thread_machinegun();
719  self thread ‪Attack_Thread_rocket();
720 }
721 
722 function ‪state_combat_exit( params )
723 {
724  self ClearTurretTarget();
725  self SetTurretSpinning( false );
726 }
727 
729 {
730  if( self.vehicletype === "spawner_enemy_boss_siegebot_zombietron" )
731  {
732  self ASMSetAnimationRate( 0.5 );
733  }
734 
735  self ASMRequestSubstate( "locomotion@movement" );
736 }
737 
739 {
740  if( self.goalforced )
741  {
742  return self.goalpos;
743  }
744 
745  maxSearchRadius = 800;
746  halfHeight = 400;
747  innerSpacing = 50;
748  outerSpacing = 60;
749 
750  queryResult = PositionQuery_Source_Navigation( self.origin, 0, maxSearchRadius, halfHeight, innerSpacing, self, outerSpacing );
751  PositionQuery_Filter_DistanceToGoal( queryResult, self );
753 
754  if( isdefined( self.enemy ) )
755  {
756  PositionQuery_Filter_Sight( queryResult, self.enemy.origin, self GetEye() - self.origin, self, 0, self.enemy );
757  self ‪vehicle_ai::PositionQuery_Filter_EngagementDist( queryResult, self.enemy, self.settings.engagementDistMin, self.settings.engagementDistMax );
758  }
759 
760  foreach ( point in queryResult.data )
761  {
762  ADD_POINT_SCORE( point, "random", randomFloatRange( 0, 30 ) );
763 
764  if( point.disttoorigin2d < 120 )
765  {
766  ADD_POINT_SCORE( point, "tooCloseToSelf", (120 - point.disttoorigin2d) * -1.5 );
767  }
768 
769  if( isdefined( self.enemy ) )
770  {
771  ADD_POINT_SCORE( point, "engagementDist", -point.distAwayFromEngagementArea );
772 
773  if ( !point.visibility )
774  {
775  ADD_POINT_SCORE( point, "visibility", -600 );
776  }
777  }
778  }
779 
781  self ‪vehicle_ai::PositionQuery_DebugScores( queryResult );
782 
783  if( queryResult.data.size == 0 )
784  return self.origin;
785 
786  return queryResult.data[0].origin;
787 }
788 
790 {
791  self endon( "death" );
792  self endon( "change_state" );
793  self endon( "near_goal" );
794  self endon( "reached_end_node" );
795 
796  canSeeEnemyCount = 0;
797 
798  old_enemy = self.enemy;
799 
800  startPath = GetTime(); // assume we just started a new path
801  old_origin = self.origin;
802  move_dist = 300;
803 
804  wait 1.5;
805 
806  while( 1 )
807  {
808  self SetMaxSpeedScale( 1 );
809  self SetMaxAccelerationScale( 1 );
810  self SetSpeed( self.settings.defaultMoveSpeed );
811 
812  if ( isdefined( self.enemy ) )
813  {
814  selfDistToTarget = Distance2D( self.origin, self.enemy.origin );
815 
816  farEngagementDist = self.settings.engagementDistMax + 150;
817  closeEngagementDist = self.settings.engagementDistMin - 150;
818 
819  if( self VehCanSee( self.enemy ) )
820  {
821  self SetLookAtEnt( self.enemy ); // try to keep the basic orientation towards the enemy
822  self SetTurretTargetEnt( self.enemy );
823 
824  // check the distance so we don't trigger a new path when we are already moving
825  if( selfDistToTarget < farEngagementDist && selfDistToTarget > closeEngagementDist )
826  {
827  canSeeEnemyCount++;
828 
829  // Stop if we can see our enemy for a bit
830  if( canSeeEnemyCount > 3 && ( ‪vehicle_ai::TimeSince( startPath ) > 5 || Distance2DSquared( old_origin, self.origin ) > ‪SQR( move_dist ) ) )
831  {
832  self notify( "near_goal" );
833  }
834  }
835  else
836  {
837  // too far go fast
838  self SetMaxSpeedScale( 2.5 );
839  self SetMaxAccelerationScale( 3 );
840  self SetSpeed( self.settings.defaultMoveSpeed * 2 );
841  }
842  }
843  else if( (!self VehSeenRecently( self.enemy, 1.5 ) && self VehSeenRecently( self.enemy, 15 )) || selfDistToTarget > farEngagementDist ) // move fast if we just lost sight of our target or we are too far
844  {
845  self SetMaxSpeedScale( 1.8 );
846  self SetMaxAccelerationScale( 2 );
847  self SetSpeed( self.settings.defaultMoveSpeed * 1.5 );
848  }
849  }
850  else
851  {
852  canSeeEnemyCount = 0;
853  }
854 
855  if ( isdefined( self.enemy ) )
856  {
857  if( !isdefined( old_enemy ) )
858  {
859  self notify( "near_goal" ); // new enemy
860  }
861  else if( self.enemy != old_enemy )
862  {
863  self notify( "near_goal" ); // new enemy
864  }
865 
866  if( self VehCanSee( self.enemy ) && distance2dSquared( self.origin, self.enemy.origin ) < ‪SQR( 150 ) && Distance2DSquared( old_origin, self.enemy.origin ) > ‪SQR( 151 ) ) // don't walk pass the player
867  {
868  self notify( "near_goal" );
869  }
870  }
871 
872  wait 0.2;
873  }
874 }
875 
876 function ‪weapon_doors_state( isOpen, waittime = 0 )
877 {
878  self endon( "death" );
879  self notify( "weapon_doors_state" );
880  self endon( "weapon_doors_state" );
881 
882  if ( isdefined( waittime ) && waittime > 0 )
883  {
884  wait waittime;
885  }
886 
887  self ‪vehicle::toggle_ambient_anim_group( 1, isOpen );
888 }
889 
891 {
892  self endon( "death" );
893  self endon( "change_state" );
894  self notify( "end_movement_thread" );
895  self endon( "end_movement_thread" );
896 
897  while ( 1 )
898  {
899  self.current_pathto_pos = self ‪GetNextMovePosition_tactical();
900 
901  if( self.vehicletype === "spawner_enemy_boss_siegebot_zombietron" )
902  {
903  if ( ‪vehicle_ai::IsCooldownReady( "jump" ) )
904  {
905  params = SpawnStruct();
906  params.jumpgoal = self.current_pathto_pos;
908  wait 0.5;
909  self ‪vehicle_ai::evaluate_connections( undefined, params );
910  wait 0.5;
911  }
912  }
913 
914  foundpath = self SetVehGoalPos( self.current_pathto_pos, false, true );
915 
916  if ( foundPath )
917  {
918  if ( isdefined( self.enemy ) && self VehSeenRecently( self.enemy, 1 ) )
919  {
920  self SetLookAtEnt( self.enemy );
921  self SetTurretTargetEnt( self.enemy );
922  }
924  self thread ‪path_update_interrupt();
926  self notify( "near_goal" ); // kill path_update_interrupt thread
927  self CancelAIMove();
928  self ClearVehGoalPos();
929  if ( isdefined( self.enemy ) && self VehSeenRecently( self.enemy, 2 ) )
930  {
931  self ‪face_target( self.enemy.origin );
932  }
933  }
934 
935  wait 1;
936 
937  startAdditionalWaiting = GetTime();
938  while ( isdefined( self.enemy ) && self VehCanSee( self.enemy ) && ‪vehicle_ai::TimeSince( startAdditionalWaiting ) < 1.5 )
939  {
940  wait 0.4;
941  }
942  }
943 }
944 
946 {
947  self notify( "end_movement_thread" );
948  self notify( "near_goal" );
949  self CancelAIMove();
950  self ClearVehGoalPos();
951  self ClearTurretTarget();
952  self ClearLookAtEnt();
953  self SetBrake( 1 );
954 }
955 
956 function ‪face_target( position, targetAngleDiff )
957 {
958  if ( !isdefined( targetAngleDiff ) )
959  {
960  targetAngleDiff = 30;
961  }
962 
963  v_to_enemy = ‪FLAT_ORIGIN( (position - self.origin) );
964  v_to_enemy = VectorNormalize( v_to_enemy );
965  goalAngles = VectortoAngles( v_to_enemy );
966 
967  angleDiff = AbsAngleClamp180( self.angles[1] - goalAngles[1] );
968  if ( angleDiff <= targetAngleDiff )
969  {
970  return;
971  }
972 
973  self SetLookAtOrigin( position );
974  self SetTurretTargetVec( position );
975  self ‪locomotion_start();
976 
977  angleAdjustingStart = GetTime();
978  while( angleDiff > targetAngleDiff && ‪vehicle_ai::TimeSince( angleAdjustingStart ) < 4 )
979  {
980  angleDiff = AbsAngleClamp180( self.angles[1] - goalAngles[1] );
982  }
983 
984  self ClearVehGoalPos();
985  self ClearLookAtEnt();
986  self ClearTurretTarget();
987  self CancelAIMove();
988 }
989 
990 function ‪Scan()
991 {
992  angles = self GetTagAngles( "tag_barrel" );
993  angles = (0,angles[1],0); // get rid of pitch
994 
995  rotate = 360;
996 
997  while( rotate > 0 )
998  {
999  angles += (0,30,0);
1000  rotate -= 30;
1001  forward = AnglesToForward( angles );
1002 
1003  aimpos = self.origin + forward * 1000;
1004  self SetTurretTargetVec( aimpos );
1005  msg = self ‪util::waittill_any_timeout( 0.5, "turret_on_target" );
1006  wait 0.1;
1007 
1008  if( isdefined( self.enemy ) && self VehCanSee( self.enemy ) ) // use VehCanSee, if recently attacked this will return true and not use FOV check
1009  {
1010  self SetTurretTargetEnt( self.enemy );
1011  self SetLookAtEnt( self.enemy );
1012  self ‪face_target( self.enemy );
1013  return;
1014  }
1015  }
1016 
1017  // return the turret to forward
1018  forward = AnglesToForward( self.angles );
1019 
1020  aimpos = self.origin + forward * 1000;
1021  self SetTurretTargetVec( aimpos );
1022  msg = self ‪util::waittill_any_timeout( 3.0, "turret_on_target" );
1023  self ClearTurretTarget();
1024 }
1025 
1027 {
1028  self endon( "death" );
1029  self endon( "change_state" );
1030  self endon( "end_attack_thread" );
1031  self notify( "end_machinegun_attack_thread" );
1032  self endon( "end_machinegun_attack_thread" );
1033 
1034  self.turretrotscale = 1 * self.difficulty_scale_up;
1035 
1036  spinning = false;
1037 
1038  while( 1 )
1039  {
1040  if( isdefined( self.enemy ) && self VehCanSee( self.enemy ) )
1041  {
1042  self SetLookAtEnt( self.enemy );
1043  self SetTurretTargetEnt( self.enemy );
1044 
1045  if ( !spinning )
1046  {
1047  spinning = true;
1048  self SetTurretSpinning( true );
1049  wait 0.5;
1050  continue;
1051  }
1052 
1053  self SetGunnerTargetEnt( self.enemy, (0,0,0), 0 );
1054  self SetGunnerTargetEnt( self.enemy, (0,0,0), 1 );
1055 
1056  self ‪vehicle_ai::fire_for_time( RandomFloatRange( 0.75, 1.5 ) * self.difficulty_scale_up, 1 );
1057 
1058  if( isdefined( self.enemy ) && IsAI( self.enemy ) )
1059  {
1060  wait( RandomFloatRange( 0.1, 0.2 ) );
1061  }
1062  else
1063  {
1064  wait( RandomFloatRange( 0.2, 0.3 ) ) * self.difficulty_scale_down;
1065  }
1066  }
1067  else
1068  {
1069  spinning = false;
1070  self SetTurretSpinning( false );
1071  self ClearGunnerTarget( 0 );
1072  self ClearGunnerTarget( 1 );
1073  wait 0.4;
1074  }
1075  }
1076 }
1077 
1078 function ‪Attack_Rocket( target )
1079 {
1080  if ( isdefined( target ) )
1081  {
1082  self SetTurretTargetEnt( target );
1083  self SetGunnerTargetEnt( target, (0,0,-10), 2 );
1084  msg = self ‪util::waittill_any_timeout( 1, "turret_on_target" );
1085  self FireWeapon( 2, target, (0,0,-10) );
1086  self ClearGunnerTarget( 1 );
1087  }
1088 }
1089 
1091 {
1092  self endon( "death" );
1093  self endon( "change_state" );
1094  self endon( "end_attack_thread" );
1095  self notify( "end_rocket_attack_thread" );
1096  self endon( "end_rocket_attack_thread" );
1097 
1098  ‪vehicle_ai::Cooldown( "rocket", 3 );
1099 
1100  while( 1 )
1101  {
1102  if ( isdefined( self.enemy ) && self VehSeenRecently( self.enemy, 3 ) && ( ‪vehicle_ai::IsCooldownReady( "rocket", 1.5 ) ) )
1103  {
1104  self SetGunnerTargetEnt( self.enemy, (0,0,0), 0 );
1105  self SetGunnerTargetEnt( self.enemy, (0,0,-10), 2 );
1106 
1107  self thread ‪weapon_doors_state( true );
1108  wait 1.5;
1109  if ( isdefined( self.enemy ) && self VehSeenRecently( self.enemy, 1 ) )
1110  {
1111  ‪vehicle_ai::Cooldown( "rocket", 5 );
1112  ‪Attack_Rocket( self.enemy );
1113  wait 1;
1114  if ( isdefined( self.enemy ) )
1115  {
1116  ‪Attack_Rocket( self.enemy );
1117  }
1118  self thread ‪weapon_doors_state( false, 1 );
1119  }
1120  else
1121  {
1122  self thread ‪weapon_doors_state( false );
1123  }
1124  }
1125  else
1126  {
1127  self ClearGunnerTarget( 0 );
1128  self ClearGunnerTarget( 1 );
1129  wait 0.4;
1130  }
1131  }
1132 }
1133 
1134 function ‪siegebot_callback_damage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal )
1135 {
1136  num_players = GetPlayers().size;
1137  maxDamage = self.healthdefault * ( 0.40 - 0.02 * num_players );
1138  if ( sMeansOfDeath !== "MOD_UNKNOWN" && iDamage > maxDamage )
1139  {
1140  iDamage = maxDamage;
1141  }
1142 
1143  if ( ‪vehicle_ai::should_emp( self, weapon, sMeansOfDeath, eInflictor, eAttacker ) )
1144  {
1145  minEmpDownTime = 0.8 * self.settings.empdowntime;
1146  maxEmpDownTime = 1.2 * self.settings.empdowntime;
1147  self notify ( "emped", RandomFloatRange( minEmpDownTime, maxEmpDownTime ), eAttacker, eInflictor );
1148  }
1149 
1150  if ( !isdefined( self.damageLevel ) )
1151  {
1152  self.damageLevel = 0;
1153  self.newDamageLevel = self.damageLevel;
1154  }
1155 
1156  newDamageLevel = ‪vehicle::should_update_damage_fx_level( self.health, iDamage, self.healthdefault );
1157  if ( newDamageLevel > self.damageLevel )
1158  {
1159  self.newDamageLevel = newDamageLevel;
1160  }
1161 
1162  if ( self.newDamageLevel > self.damageLevel )
1163  {
1164  self.damageLevel = self.newDamageLevel;
1165 
1166  driver = self GetSeatOccupant( 0 );
1167  if ( !isdefined( driver ) ) // no pain for player driving version
1168  {
1169  self notify( "pain" );
1170  }
1171 
1172  ‪vehicle::set_damage_fx_level( self.damageLevel );
1173  }
1174 
1175  return iDamage;
1176 }
1177 
1178 
‪set_death_model
‪function set_death_model(sModel, fDelay)
Definition: vehicle_death_shared.gsc:258
‪Scan
‪function Scan()
Definition: _siegebot.gsc:1082
‪add_state
‪function add_state(name, enter_func, update_func, exit_func, reenter_func)
Definition: statemachine_shared.gsc:59
‪siegebot_player_fireupdate
‪function siegebot_player_fireupdate()
Definition: _siegebot.gsc:321
‪Attack_Thread_Rocket
‪function Attack_Thread_Rocket()
Definition: _siegebot.gsc:1182
‪evaluate_connections
‪function evaluate_connections(eval_func, params)
Definition: statemachine_shared.gsc:266
‪GetNextMovePosition_unaware
‪function GetNextMovePosition_unaware()
Definition: _siegebot.gsc:527
‪state_combat_exit
‪function state_combat_exit(params)
Definition: _siegebot.gsc:814
‪toggle_emp_fx
‪function toggle_emp_fx(on)
Definition: vehicle_shared.gsc:2863
‪locomotion_start
‪function locomotion_start()
Definition: _siegebot.gsc:820
‪set_damage_fx_level
‪function set_damage_fx_level(damage_level)
Definition: vehicle_shared.gsc:3012
‪IsCooldownReady
‪function IsCooldownReady(name, timeForward_seconds)
Definition: vehicle_ai_shared.gsc:1968
‪InitThreatBias
‪function InitThreatBias()
Definition: vehicle_ai_shared.gsc:60
‪siegebot_initialize
‪function siegebot_initialize()
Definition: _siegebot.gsc:86
‪state_unaware_update
‪function state_unaware_update(params)
Definition: _siegebot.gsc:477
‪clean_up_spawnedOnDeath
‪function clean_up_spawnedOnDeath(entToWatch)
Definition: _siegebot.gsc:587
‪emped_enter
‪function emped_enter(params)
Definition: _siegebot.gsc:391
‪clean_up_spawned
‪function clean_up_spawned()
Definition: _siegebot.gsc:580
‪pain_toggle
‪function pain_toggle(enabled)
Definition: _siegebot.gsc:439
‪Attack_Thread_rocket
‪function Attack_Thread_rocket()
Definition: _quadtank.gsc:959
‪get_array
‪function get_array(kvp_value, kvp_key="targetname")
Definition: struct.csc:34
‪Attack_Rocket
‪function Attack_Rocket(target)
Definition: _siegebot.gsc:1170
‪trace
‪function trace(from, to, target)
Definition: grapple.gsc:369
‪state_jump_update
‪function state_jump_update(params)
Definition: _siegebot.gsc:651
‪GetNextMovePosition_tactical
‪function GetNextMovePosition_tactical()
Definition: _siegebot.gsc:830
‪state_death_update
‪function state_death_update(params)
Definition: _siegebot.gsc:224
‪state_jump_can_enter
‪function state_jump_can_enter(from_state, to_state, connection)
Definition: _siegebot.gsc:615
‪pain_update
‪function pain_update(params)
Definition: _siegebot.gsc:444
‪state_jump_enter
‪function state_jump_enter(params)
Definition: _siegebot.gsc:623
‪waittill_any_timeout
‪function waittill_any_timeout(n_timeout, string1, string2, string3, string4, string5)
Definition: util_shared.csc:423
‪IS_TRUE
‪#define IS_TRUE(__a)
Definition: shared.gsh:251
‪Movement_Thread_Unaware
‪function Movement_Thread_Unaware()
Definition: _siegebot.gsc:494
‪SQR
‪#define SQR(__var)
Definition: shared.gsh:293
‪face_target
‪function face_target(position, targetAngleDiff)
Definition: _siegebot.gsc:1048
‪death_radius_damage
‪function death_radius_damage(meansOfDamage="MOD_EXPLOSIVE")
Definition: vehicle_death_shared.gsc:1196
‪Movement_Thread
‪function Movement_Thread()
Definition: _siegebot.gsc:982
‪weapon_doors_state
‪function weapon_doors_state(isOpen, waittime=0)
Definition: _siegebot.gsc:968
‪StartInitialState
‪function StartInitialState(defaultState="combat")
Definition: vehicle_ai_shared.gsc:866
‪path_update_interrupt
‪function path_update_interrupt()
Definition: _siegebot.gsc:881
‪impact_fx
‪function impact_fx(fxname, surfaceTypes)
Definition: vehicle_shared.gsc:2765
‪FreeWhenSafe
‪function FreeWhenSafe(time=4)
Definition: vehicle_death_shared.gsc:1756
‪siegebot_update_difficulty
‪function siegebot_update_difficulty()
Definition: _siegebot.gsc:175
‪friendly_fire_shield
‪function friendly_fire_shield()
Definition: vehicle_shared.gsc:2194
‪defaultRole
‪function defaultRole()
Definition: _siegebot.gsc:186
‪state_jump_exit
‪function state_jump_exit(params)
Definition: _siegebot.gsc:797
‪__init__
‪function __init__()
Definition: _siegebot.gsc:76
‪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
‪initJumpStruct
‪function initJumpStruct()
Definition: _siegebot.gsc:595
‪stopMovementAndSetBrake
‪function stopMovementAndSetBrake()
Definition: _siegebot.gsc:1037
‪get_general_difficulty_level
‪function get_general_difficulty_level()
Definition: gameskill_shared.gsc:2056
‪fire_for_time
‪function fire_for_time(n_time, n_index=0)
Definition: turret_shared.gsc:953
‪PositionQuery_PostProcess_SortScore
‪function PositionQuery_PostProcess_SortScore(queryResult, descending=true)
Definition: vehicle_ai_shared.gsc:2097
‪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
‪siegebot_kill_on_tilting
‪function siegebot_kill_on_tilting()
Definition: _siegebot.gsc:290
‪PHYSICS_TRACE_MASK_VEHICLE
‪#define PHYSICS_TRACE_MASK_VEHICLE
Definition: shared.gsh:131
‪Spawn
‪function Spawn(parent, onDeathCallback)
Definition: _flak_drone.gsc:427
‪siegebot_callback_damage
‪function siegebot_callback_damage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal)
Definition: _siegebot.gsc:1301
‪target_hijackers
‪function target_hijackers()
Definition: vehicle_ai_shared.gsc:2312
‪waittill_asm_complete
‪function waittill_asm_complete(substate_to_wait, timeout=10)
Definition: vehicle_ai_shared.gsc:374
‪PositionQuery_Filter_EngagementDist
‪function PositionQuery_Filter_EngagementDist(queryResult, enemy, engagementDistanceMin, engagementDistanceMax)
Definition: vehicle_ai_shared.gsc:2116
‪should_emp
‪function should_emp(vehicle, weapon, meansOfDeath, eInflictor, eAttacker)
Definition: vehicle_ai_shared.gsc:765
‪JUMP_COOLDOWN
‪#define JUMP_COOLDOWN
Definition: _siegebot.gsc:28
‪RegisterVehicleBlackBoardAttributes
‪function RegisterVehicleBlackBoardAttributes()
Definition: blackboard_vehicle.gsc:24
‪siegebot_player_aimUpdate
‪function siegebot_player_aimUpdate()
Definition: _siegebot.gsc:348
‪emped_exit
‪function emped_exit(params)
Definition: _siegebot.gsc:426
‪CreateBlackBoardForEntity
‪function CreateBlackBoardForEntity(entity)
Definition: blackboard.gsc:77
‪CleanUp
‪function CleanUp()
Definition: vehicle_death_shared.gsc:1795
‪TimeSince
‪function TimeSince(startTimeInMilliseconds)
Definition: vehicle_ai_shared.gsc:1930
‪should_update_damage_fx_level
‪function should_update_damage_fx_level(currentHealth, damage, maxHealth)
Definition: vehicle_shared.gsc:2900
‪add_utility_connection
‪function add_utility_connection(from_state_name, to_state_name, checkfunc, defaultScore)
Definition: statemachine_shared.gsc:112
‪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
‪emped_update
‪function emped_update(params)
Definition: _siegebot.gsc:405
‪siegebot_driving
‪function siegebot_driving(params)
Definition: _siegebot.gsc:280
‪Attack_Thread_machinegun
‪function Attack_Thread_machinegun()
Definition: _siegebot.gsc:1118
‪do_death_dynents
‪function do_death_dynents(special_status=1)
Definition: vehicle_shared.gsc:2874
‪DEBUG_ON
‪#define DEBUG_ON
Definition: _siegebot.gsc:29
‪emped_reenter
‪function emped_reenter(params)
Definition: _siegebot.gsc:430
‪state_combat_update
‪function state_combat_update(params)
Definition: _siegebot.gsc:804
‪toggle_ambient_anim_group
‪function toggle_ambient_anim_group(groupID, on)
Definition: vehicle_shared.gsc:2844
‪get_state_callbacks
‪function get_state_callbacks(statename)
Definition: vehicle_ai_shared.gsc:927
‪get_death_type
‪function get_death_type(params)
Definition: vehicle_ai_shared.gsc:1323
‪WAIT_SERVER_FRAME
‪#define WAIT_SERVER_FRAME
Definition: shared.gsh:265