‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
_sentinel_drone.gsc
Go to the documentation of this file.
1 
2 #using scripts\shared\math_shared;
3 #using scripts\shared\statemachine_shared;
4 #using scripts\shared\system_shared;
5 #using scripts\shared\array_shared;
6 #using scripts\shared\util_shared;
7 
8 #using scripts\shared\vehicle_shared;
9 #using scripts\shared\vehicle_death_shared;
10 #using scripts\shared\vehicle_ai_shared;
11 #using scripts\shared\clientfield_shared;
12 
13 #using scripts\shared\ai\systems\blackboard;
14 #using scripts\shared\ai\blackboard_vehicle;
15 #using scripts\shared\ai\systems\ai_interface;
16 #using scripts\shared\animation_shared;
17 #using scripts\codescripts\struct;
18 
19 #insert scripts\shared\shared.gsh;
20 #insert scripts\shared\statemachine.gsh;
21 #insert scripts\shared\archetype_shared\archetype_shared.gsh;
22 #insert scripts\shared\ai\systems\blackboard.gsh;
23 
24 #insert scripts\shared\ai\utility.gsh;
25 #insert scripts\shared\version.gsh;
26 #insert scripts\shared\vehicles\_sentinel_drone.gsh;
27 
28 #using_animtree( "generic" );
29 
30 #namespace sentinel_drone;
31 
32 ‪REGISTER_SYSTEM( "sentinel_drone", &‪__init__, undefined )
33 
34 function ‪__init__()
35 {
36  ‪clientfield::register( "scriptmover", "sentinel_drone_beam_set_target_id", ‪VERSION_DLC3, 5, "int" );
37  ‪clientfield::register( "vehicle", "sentinel_drone_beam_set_source_to_target", ‪VERSION_DLC3, 5, "int" );
38 
39  ‪clientfield::register( "toplayer", "sentinel_drone_damage_player_fx", ‪VERSION_DLC3, 1, "counter" );
40 
41  ‪clientfield::register( "vehicle", "sentinel_drone_beam_fire1", ‪VERSION_DLC3, 1, "int" ); //left
42  ‪clientfield::register( "vehicle", "sentinel_drone_beam_fire2", ‪VERSION_DLC3, 1, "int" ); //right
43  ‪clientfield::register( "vehicle", "sentinel_drone_beam_fire3", ‪VERSION_DLC3, 1, "int" ); //top
44 
45  ‪clientfield::register( "vehicle", "sentinel_drone_arm_cut_1", ‪VERSION_DLC3, 1, "int" ); //left
46  ‪clientfield::register( "vehicle", "sentinel_drone_arm_cut_2", ‪VERSION_DLC3, 1, "int" ); //right
47  ‪clientfield::register( "vehicle", "sentinel_drone_arm_cut_3", ‪VERSION_DLC3, 1, "int" ); //top
48 
49  ‪clientfield::register( "vehicle", "sentinel_drone_face_cut", ‪VERSION_DLC3, 1, "int" ); //face
50 
51  ‪clientfield::register( "vehicle", "sentinel_drone_beam_charge", ‪VERSION_DLC3, 1, "int" );
52 
53  ‪clientfield::register( "vehicle", "sentinel_drone_camera_scanner", ‪VERSION_DLC3, 1, "int" );
54 
55  ‪clientfield::register( "vehicle", "sentinel_drone_camera_destroyed", ‪VERSION_DLC3, 1, "int" );
56 
57  ‪clientfield::register( "scriptmover", "sentinel_drone_deathfx", ‪VERSION_SHIP, 1, "int" ); //Sentinel Death Effect
58 
59  vehicle::add_main_callback( "sentinel_drone", &‪sentinel_drone_initialize );
60 
61  level._sentinel_Enemy_Detected_Taunts = [];
62  ‪ARRAY_ADD(level._sentinel_Enemy_Detected_Taunts, "vox_valk_valkyrie_detected_0");
63  ‪ARRAY_ADD(level._sentinel_Enemy_Detected_Taunts, "vox_valk_valkyrie_detected_1");
64  ‪ARRAY_ADD(level._sentinel_Enemy_Detected_Taunts, "vox_valk_valkyrie_detected_2");
65  ‪ARRAY_ADD(level._sentinel_Enemy_Detected_Taunts, "vox_valk_valkyrie_detected_3");
66  ‪ARRAY_ADD(level._sentinel_Enemy_Detected_Taunts, "vox_valk_valkyrie_detected_4");
67 
68  level._sentinel_System_Critical_Taunts = [];
69  ‪ARRAY_ADD(level._sentinel_System_Critical_Taunts, "vox_valk_valkyrie_health_low_0");
70  ‪ARRAY_ADD(level._sentinel_System_Critical_Taunts, "vox_valk_valkyrie_health_low_1");
71  ‪ARRAY_ADD(level._sentinel_System_Critical_Taunts, "vox_valk_valkyrie_health_low_2");
72  ‪ARRAY_ADD(level._sentinel_System_Critical_Taunts, "vox_valk_valkyrie_health_low_3");
73  ‪ARRAY_ADD(level._sentinel_System_Critical_Taunts, "vox_valk_valkyrie_health_low_4");
74 }
75 
76 // ----------------------------------------------
77 // Initialization
78 // ----------------------------------------------
79 
81 {
82  self UseAnimTree( #animtree );
83 
84  Target_Set( self, ( 0, 0, 0 ) );
85 
86  self.health = self.healthdefault;
87 
88  if( !isDefined( level.sentinelDroneMaxHealth ) )
89  {
90  level.sentinelDroneMaxHealth = self.health;
91  }
92 
93  self.maxHealth = level.sentinelDroneMaxHealth;
94 
95  if( !isDefined( level.sentinelDroneHealthArmLeft ))
96  {
97  level.sentinelDroneHealthArmLeft = ‪SENTINEL_DRONE_DEFAULT_HEALTH_ARM_LEFT;
98  }
99  if( !isDefined( level.sentinelDroneHealthArmRight ))
100  {
101  level.sentinelDroneHealthArmRight = ‪SENTINEL_DRONE_DEFAULT_HEALTH_ARM_RIGHT;
102  }
103  if( !isDefined( level.sentinelDroneHealthArmTop ))
104  {
105  level.sentinelDroneHealthArmTop = ‪SENTINEL_DRONE_DEFAULT_HEALTH_ARM_TOP;
106  }
107  if( !isDefined( level.sentinelDroneHealthFace ))
108  {
109  level.sentinelDroneHealthFace = ‪SENTINEL_DRONE_DEFAULT_HEALTH_FACE;
110  }
111  if( !isDefined( level.sentinelDroneHealthCamera ))
112  {
113  level.sentinelDroneHealthCamera = ‪SENTINEL_DRONE_DEFAULT_HEALTH_CAMERA;
114  }
115  if( !isDefined( level.sentinelDroneHealthCore ))
116  {
117  level.sentinelDroneHealthCore = ‪SENTINEL_DRONE_DEFAULT_HEALTH_CORE;
118  }
119 
120  self.sentinelDroneHealthArms = [];
121  self.sentinelDroneHealthArms[‪SENTINEL_DRONE_ARM_LEFT] = level.sentinelDroneHealthArmLeft;
122  self.sentinelDroneHealthArms[‪SENTINEL_DRONE_ARM_RIGHT] = level.sentinelDroneHealthArmRight;
123  self.sentinelDroneHealthArms[‪SENTINEL_DRONE_ARM_TOP] = level.sentinelDroneHealthArmTop;
124 
125  self.sentinelDroneHealthFace = level.sentinelDroneHealthFace;
126  self.sentinelDroneHealthCamera = level.sentinelDroneHealthCamera;
127  self.sentinelDroneHealthCore = level.sentinelDroneHealthCore;
128 
130 
131  //Target
132  self.beam_fire_target = ‪util::spawn_model("tag_origin", self.position, self.angles);
133 
134  if(!isdefined(level.sentinel_drone_target_id))
135  {
136  level.sentinel_drone_target_id = 0;
137  }
138 
139  level.sentinel_drone_target_id = (level.sentinel_drone_target_id + 1) % ‪SENTINEL_DRONE_MAX_INSTANCES;
140 
141  if(level.sentinel_drone_target_id == 0)
142  {
143  level.sentinel_drone_target_id = 1;
144  }
145 
146  self.drone_target_id = level.sentinel_drone_target_id;
147 
148 
153 
155 
156  self EnableAimAssist();
157  self SetNearGoalNotifyDist( ‪SENTINEL_DRONE_NEARGOAL_DIST );
158 
159  self SetVehicleAvoidance( true ); // this is ORCA avoidance
160 
161  self SetDrawInfrared( true );
162 
163  self SetHoverParams( 0, 0, 10 );
164 
165  self.no_gib = 1;
166  self.fovcosine = 0;
167  self.fovcosinebusy = 0;
168 
169  self.vehAirCraftCollisionEnabled = true;
170 
171  assert( isdefined( self.scriptbundlesettings ) );
172 
173  self.settings = ‪struct::get_script_bundle( "vehiclecustomsettings", self.scriptbundlesettings );
174  self.goalRadius = 999999;
175  self.goalHeight = 4000;
176  self SetGoal( self.origin, false, self.goalRadius, self.goalHeight );
177 
178  self.nextJukeTime = 0;
179  self.nextRollTime = 0;
180  self.arms_count = 3;
181 
182  //Set Initial Drone Speeds
183  SetDvar("Sentinel_Move_Speed", 25);
184  SetDvar("Sentinel_Evade_Speed", 40);
185 
186  self.should_buff_zombies = false;
187  self.disable_flame_fx = true;
188  self.no_widows_wine = true;
189 
190  self.targetPlayerTime = GetTime() + 1000 + RandomInt(1000);
191 
192  // necessary array creation element for weapon watcher stuff used in the electroball grenade
193  self.pers = [];
194  self.pers["team"] = self.team;
195 
196  self.overrideVehicleDamage = &‪sentinel_CallbackDamage;
197  self.overrideVehicleRadiusDamage = &‪sentinel_drone_CallbackRadiusDamage;
198 
199  if( !isdefined(level.a_sentinel_drones))
200  {
201  level.a_sentinel_drones = [];
202  }
203 
204  ‪array::add(level.a_sentinel_drones, self);
205 
206  if ( isdefined( level.func_custom_sentinel_drone_cleanup_check ) )
207  {
208  self.func_custom_cleanup_check = level.func_custom_sentinel_drone_cleanup_check;
209  }
210 
211  self thread ‪vehicle_ai::nudge_collision();
212 
214 
215  self thread ‪sentinel_InitBeamLaunchers();
216 
217  //*! \details **Description:**
218 <br/>Debug
219 /#
220  self thread ‪sentinel_DebugFX();
221  self thread ‪sentinel_DebugBehavior();
222 #/
223 
224  ‪defaultRole();
225 }
226 
228 {
229  self endon( "death" );
230 
231  if(!isdefined(self.target_initialized))
232  {
233  wait 1;
234 
235  //Send Target ID
236  self.beam_fire_target ‪clientfield::set("sentinel_drone_beam_set_target_id", self.drone_target_id);
237  wait 0.1;
238 
239  self ‪clientfield::set("sentinel_drone_beam_set_source_to_target", self.drone_target_id);
240 
241  wait 1;
242 
243  self.target_initialized = true;
244  }
245 }
246 
247 function ‪defaultRole()
248 {
250 
251  self ‪vehicle_ai::get_state_callbacks( "combat" ).update_func = &‪state_combat_update;
252  self ‪vehicle_ai::get_state_callbacks( "death" ).update_func = &‪state_death_update;
253 
255 
257 }
258 
259 // ----------------------------------------------
260 // Target Selection functions
261 // ----------------------------------------------
262 function private ‪is_target_valid( target )
263 {
264  if( !isdefined( target ) )
265  {
266  return false;
267  }
268 
269  if( !IsAlive( target ) )
270  {
271  return false;
272  }
273 
274  if( IsPlayer( target ) && target.sessionstate == "spectator" )
275  {
276  return false;
277  }
278 
279  if( IsPlayer( target ) && target.sessionstate == "intermission" )
280  {
281  return false;
282  }
283 
284  if( ‪IS_TRUE( target.ignoreme ) )
285  {
286  return false;
287  }
288 
289  if( target IsNoTarget() )
290  {
291  return false;
292  }
293 
294  if( ‪IS_TRUE(target.is_elemental_zombie) )
295  {
296  return false;
297  }
298 
299  if( isdefined(level.is_valid_player_for_sentinel_drone) )
300  {
301  if( ![[level.is_valid_player_for_sentinel_drone]](target) )
302  {
303  return false;
304  }
305  }
306 
307  if( ‪IS_TRUE(self.should_buff_zombies) && IsPlayer(target) )
308  {
309  if( isdefined(‪get_sentinel_nearest_zombie()) )
310  {
311  return false;
312  }
313  }
314 
315  return true;
316 }
317 
318 function ‪get_sentinel_nearest_zombie( b_ignore_elemental = true, b_outside_playable_area = true, radius = 2000 )
319 {
320  if (isdefined(self.sentinel_GetNearestZombie))
321  {
322  ai_zombie = [[self.sentinel_GetNearestZombie]]( self.origin, b_ignore_elemental, b_outside_playable_area, radius );
323  return ai_zombie;
324  }
325 
326  return undefined;
327 }
328 
330 {
331  sentinel_drone_targets = GetPlayers();
332  least_hunted = sentinel_drone_targets[0];
333 
334  search_distance_sq = ‪SQR(2000);
335 
336  for( i = 0; i < sentinel_drone_targets.size; i++ )
337  {
338  if ( !isdefined( sentinel_drone_targets[i].hunted_by_sentinel ) )
339  {
340  sentinel_drone_targets[i].hunted_by_sentinel = 0;
341  }
342 
343  if( !‪is_target_valid( sentinel_drone_targets[i] ) )
344  {
345  continue;
346  }
347 
348  if( !‪is_target_valid( least_hunted ) )
349  {
350  least_hunted = sentinel_drone_targets[i];
351  continue;
352  }
353 
354  //if the target is near enough we try to split the targetting
355  dist_to_target_sq = Distance2DSquared(self.origin, sentinel_drone_targets[i].origin);
356  dist_to_least_hunted_sq = Distance2DSquared(self.origin, least_hunted.origin);
357 
358  if( dist_to_least_hunted_sq >= search_distance_sq && dist_to_target_sq < search_distance_sq )
359  {
360  least_hunted = sentinel_drone_targets[i];
361  continue;
362  }
363 
364  if( sentinel_drone_targets[i].hunted_by_sentinel < least_hunted.hunted_by_sentinel )
365  {
366  least_hunted = sentinel_drone_targets[i];
367  }
368  }
369 
370  // do not return the default first player if he is invalid
371  if( !‪is_target_valid( least_hunted ) )
372  {
373  return undefined;
374  }
375  else
376  {
377  return least_hunted;
378  }
379 }
380 
382 {
383  if( isdefined( self.sentinel_droneEnemy ) )
384  {
385  if( !isdefined( self.sentinel_droneEnemy.hunted_by_sentinel ) )
386  {
387  self.sentinel_droneEnemy.hunted_by_sentinel = 0;
388  }
389 
390  if( self.sentinel_droneEnemy.hunted_by_sentinel > 0 )
391  {
392  self.sentinel_droneEnemy.hunted_by_sentinel--;
393  }
394  }
395 
396  if( !‪is_target_valid( enemy ) )
397  {
398  self.sentinel_droneEnemy = undefined;
399  self ClearLookAtEnt();
400  self ClearTurretTarget(0);
401  return;
402  }
403 
404  self.sentinel_droneEnemy = enemy;
405 
406  //Play enemy detected taunt
407  if(isdefined(self.skip_first_taunt))
408  {
409  if(IsPlayer(enemy) )
410  {
411  ‪sentinel_play_taunt( level._sentinel_Enemy_Detected_Taunts );
412  }
413  }
414  else
415  {
416  self.skip_first_taunt = true;
417  }
418 
419  if( !isdefined( self.sentinel_droneEnemy.hunted_by_sentinel ) )
420  {
421  self.sentinel_droneEnemy.hunted_by_sentinel = 0;
422  }
423  self.sentinel_droneEnemy.hunted_by_sentinel++;
424  self SetLookAtEnt( self.sentinel_droneEnemy );
425  self SetTurretTargetEnt( self.sentinel_droneEnemy );
426 }
427 
429 {
430  self endon( "change_state" );
431  self endon( "death" );
432 
433  for( ;; )
434  {
435  if ( ‪IS_TRUE( self.ignoreall ) )
436  {
437  wait 0.5;
438  continue;
439  }
440 
441  if( ‪is_target_valid( self.sentinel_droneEnemy ) )
442  {
443  wait 0.5;
444  continue;
445  }
446  //decide who the enemy should be
447 
448  if( ‪IS_TRUE(self.should_buff_zombies) )
449  {
451 
452  if( !isdefined(target) )
453  {
454  target = ‪get_sentinel_drone_enemy();
455  }
456  }
457  else
458  {
459  target = ‪get_sentinel_drone_enemy();
460  }
461 
462  ‪set_sentinel_drone_enemy( target );
463 
464  wait 0.5;
465  }
466 }
467 
468 
469 // ----------------------------------------------
470 // State: combat
471 // ----------------------------------------------
472 
473 function ‪state_combat_update( params )
474 {
475  self endon( "change_state" );
476  self endon( "death" );
477 
478  self.lastTimeTargetInSight = 0;
479  self.nextJukeTime= 0;
480 
481  wait 0.3;
482 
483  if ( IsDefined( self.owner ) && IsDefined( self.owner.enemy ) )
484  {
485  self.sentinel_droneEnemy = self.owner.enemy;
486  }
487 
491 
492  while( true )
493  {
494  if(‪IS_TRUE(self.playing_intro_anim))
495  {
496  wait 0.1;
497  }
498  else if( ‪IS_TRUE(self.is_charging_at_player) )
499  {
500  wait 0.1; //check to see if I can go to the player directly
501  }
502  else if ( !isdefined(self.forced_pos) && ‪IS_TRUE( self.shouldRoll ) )
503  {
504  if( ‪sentinel_DodgeRoll() )
505  {
507  }
508  }
509  else if ( !IsDefined( self.sentinel_droneEnemy ) )
510  {
511  //no enemy, do nothing
512  wait( 0.25 );
513  }
514  else
515  {
516  if(self.arms_count > 0)
517  {
518  if( RandomInt( 100 ) < ‪SENTINEL_DRONE_FIRE_CHANCE )
519  {
520  if( self ‪sentinel_FireLogic() )
521  {
523  }
524  }
525  }
526  }
527 
528  wait 0.1;
529  }
530 }
531 
532 
533 // ----------------------------------------------Intro Logic
534 
536 {
538  self.playing_intro_anim = true;
539  self ASMRequestSubstate( "intro@default" );
540 }
541 
543 {
544  self.playing_intro_anim = false;
545  if ( !self ‪vehicle_ai::is_instate( "scripted" ) )
546  {
547  self thread ‪sentinel_NavigateTheWorld();
548  }
549 }
550 
551 // ----------------------------------------------Roll Dodge Logic
552 
554 {
555  self endon( "change_state" );
556  self endon( "death" );
557 
558  roll_dir = AnglesToRight( self.angles );
559  roll_dir = VectorNormalize( roll_dir );
560 
561  juke_initial_pause = GetDvarFloat("sentinel_drone_juke_initial_pause_dvar", 0.2);
562  juke_speed = GetDvarInt("sentinel_drone_juke_speed_dvar", 300);
563  juke_offset = GetDvarInt("sentinel_drone_juke_offset_dvar", 20);
564  juke_distance = GetDvarInt("sentinel_drone_juke_distance_dvar", 100);
565  juke_distance_max = GetDvarInt("sentinel_drone_juke_distance_max_dvar", 250);
566  juke_min_anim_rate = GetDvarFloat("sentinel_drone_juke_min_anim_rate_dvar", 0.9);
567 
568  can_roll = false;
569 
570  if( ‪math::cointoss() )
571  {
572  roll_point = self.origin + VectorScale( roll_dir, juke_distance_max);
573  roll_asm_state = "dodge_right@attack";
574  }
575  else
576  {
577  roll_dir = VectorScale(roll_dir, -1);
578  roll_point = self.origin - VectorScale( roll_dir, -juke_distance_max);
579  roll_asm_state = "dodge_left@attack";
580  }
581 
582  ‪trace = ‪sentinel_Trace(self.origin, roll_point, self, true);
583 
584  if (isdefined(‪trace["position"]) )
585  {
586  if( !IsPointInNavVolume( ‪trace["position"], "navvolume_small" ) )
587  {
588  ‪trace["position"] = self GetClosestPointOnNavVolume( ‪trace["position"], 100 );
589  }
590 
591  if( isdefined(‪trace["position"]) )
592  {
593  if(‪trace["fraction"] == 1)
594  {
595  roll_distance = juke_distance_max - juke_offset;
596  }
597  else
598  {
599  roll_distance = juke_distance_max * ‪trace["fraction"] - juke_offset;
600  }
601 
602  if(roll_distance >= juke_distance )
603  {
604  roll_anim_rate = juke_distance / roll_distance;
605 
606  if(roll_anim_rate < juke_min_anim_rate)
607  {
608  roll_anim_rate = juke_min_anim_rate;
609  }
610 
611  roll_speed = (roll_distance / juke_distance) * juke_speed;
612  can_roll = true;
613  }
614  }
615  }
616 
617  self.shouldRoll = false;
618 
619  if(can_roll)
620  {
622  wait 0.1;
623 
624  self ‪clientfield::set("sentinel_drone_camera_scanner", 1);
625 
626  self ASMRequestSubstate( roll_asm_state );
627  self ASMSetAnimationRate( roll_anim_rate );
628 
629  wait juke_initial_pause;
630 
631  self SetSpeed(roll_speed);
632  self SetVehVelocity( VectorScale(roll_dir, roll_speed) );
633  self SetVehGoalPos( ‪trace["position"], true, false );
634 
635  /*
636  /#
637  RecordSphere(trace["position"], 10, GREEN, "script");
638  RecordLine(self.origin, trace["position"], WHITE, "script");
639 
640  Sphere(self.origin, 10, WHITE, 1, false, 10, 120);
641  Sphere(trace["position"], 10, GREEN, 1, false, 10, 120);
642  Line(self.origin, trace["position"], GREEN, 1, false, 120);
643  #/
644  */
645 
646  wait 1;
647  self ASMSetAnimationRate( 1 );
648 
650  self ‪clientfield::set("sentinel_drone_camera_scanner", 0);
651  wait 0.1;
652  }
653 
654  if( ‪math::cointoss() )
655  {
656  self ‪sentinel_FireLogic();
657  }
658 
659  return can_roll;
660 }
661 
662 // ----------------------------------------------Navigation Logic
663 
665 {
666  self endon( "change_state" );
667  self endon( "death" );
668 
669  self notify( "abort_navigation" );
670  self notify( "near_goal" );
671 
672  wait 0.05;
673 
674  if(GetDvarInt("sentinel_NavigationStandStill_new", 0) > 0)
675  {
676  self ClearVehGoalPos();
677  self SetVehVelocity( ( 0, 0, 0 ) );
678  self.vehAirCraftCollisionEnabled = true;
679 
680  /#
681  if( GetDvarInt("debug_sentinel_drone_traces") > 0 )
682  {
683  RecordSphere(self.origin, 30, ‪ORANGE);
684  }
685  #/
686 
687  return;
688  }
689 
690  if(GetDvarInt("sentinel_ClearVehGoalPos", 1) == 1)
691  {
692  self ClearVehGoalPos();
693  }
694 
695  if(GetDvarInt("sentinel_PathVariableOffsetClear", 1) == 1)
696  {
697  self PathVariableOffsetClear();
698  }
699 
700  if(GetDvarInt("sentinel_PathFixedOffsetClear", 1) == 1)
701  {
702  self PathFixedOffsetClear();
703  }
704 
705  if(GetDvarInt("sentinel_ClearSpeed", 1) == 1)
706  {
707  self SetSpeed( 0 );
708  self SetVehVelocity( ( 0, 0, 0 ) );
709  self SetPhysAcceleration( ( 0, 0, 0 ) );
710  self SetAngularVelocity( ( 0, 0, 0 ) );
711  }
712 
713  self.vehAirCraftCollisionEnabled = true;
714 
715  /#
716  if( GetDvarInt("debug_sentinel_drone_traces") > 0 )
717  {
718  RecordSphere(self.origin, 30, ‪ORANGE);
719  }
720  #/
721 }
722 
724 {
725  if( GetTime() > self.nextJukeTime )
726  {
727  return true;
728  }
729 
730  if( isdefined(self.sentinel_droneEnemy) )
731  {
732  if(isdefined(self.lastJukeTime))
733  {
734  if( (GetTime() - self.lastJukeTime) > 3000 )
735  {
736  speed = self GetSpeed();
737 
738  if(speed < 1)
739  {
740  if( !‪sentinel_IsInsideEngagementDistance( self.origin, self.sentinel_droneEnemy.origin + (0, 0, 48), true) )
741  {
742  return true;
743  }
744  }
745  }
746  }
747  }
748 
749  return false;
750 }
751 
753 {
754  self.nextJukeTime = 0;
755 }
756 
758 {
759  self endon( "change_state" );
760  self endon( "death" );
761  self endon( "abort_navigation" );
762 
763  self notify( "sentinel_NavigateTheWorld" );
764 
765  self endon( "sentinel_NavigateTheWorld" );
766 
767  lastTimeChangePosition = 0;
768  self.shouldGotoNewPosition = false;
769  self.last_failsafe_count = 0;
770 
771  Sentinel_Move_Speed = GetDvarInt("Sentinel_Move_Speed", 25);
772  Sentinel_Evade_Speed = GetDvarInt("Sentinel_Evade_Speed", 40);
773 
774  self SetSpeed( Sentinel_Move_Speed );
775 
776  //request movement animations
777  self ASMRequestSubstate( "locomotion@movement" );
778 
779  self.current_pathto_pos = undefined;
780  self.next_near_player_check = 0;
781 
782  b_use_path_finding = true;
783 
784  while(true)
785  {
786  current_pathto_pos = undefined;
787  b_in_tactical_position = false;
788 
789  if(‪IS_TRUE(self.playing_intro_anim))
790  {
791  wait 0.1;
792  }
793  else if( self.goalforced )
794  {
795  returnData = [];
796  returnData["origin"] = self GetClosestPointOnNavVolume( self.goalpos, 100 );
797  returnData["centerOnNav"] = IsPointInNavVolume( self.origin, "navvolume_small" );
798  current_pathto_pos = returnData["origin"];
799  }
800  else if( isdefined(self.forced_pos) )
801  {
802  returnData = [];
803  returnData["origin"] = self GetClosestPointOnNavVolume( self.forced_pos, 100 );
804  returnData["centerOnNav"] = IsPointInNavVolume( self.origin, "navvolume_small" );
805  current_pathto_pos = returnData["origin"];
806  }
808  {
809  if(‪IS_TRUE(self.evading_player))
810  {
811  self.evading_player = false;
812  self SetSpeed( Sentinel_Evade_Speed );
813  }
814  else
815  {
816  self SetSpeed( Sentinel_Move_Speed );
817  }
818 
819  returnData = ‪sentinel_GetNextMovePositionTactical( self.should_buff_zombies );
820  current_pathto_pos = returnData[ "origin" ];
821 
822  self.lastJukeTime = GetTime();
823  self.nextJukeTime = GetTime() + 1000 + RandomInt(4000);
824 
825  b_in_tactical_position = true;
826  }
827  else if( GetTime() > self.next_near_player_check && ‪sentinel_IsNearAnotherPlayer(self.origin, 100) )
828  {
829  self.evading_player = true;
830  self.next_near_player_check = GetTime() + 1000;
831  self.nextJukeTime = 0;
832  self notify( "near_goal" );
833  }
834 
835  is_on_nav_volume = IsPointInNavVolume(self.origin, "navvolume_small");
836 
837 /#
838  if( GetDvarInt("sentinel_DebugFX_NoMove", 0) == 1 )
839  {
840  current_pathto_pos = undefined;
841  is_on_nav_volume = true;
842  }
843 #/
844 
845  if ( isdefined( current_pathto_pos ) )
846  {
847  if( isdefined( self.stuckTime ) && ‪IS_TRUE( is_on_nav_volume ) )
848  {
849  self.stuckTime = undefined;
850  }
851 
852  /#
853  if( GetDvarInt("debug_sentinel_drone_traces") > 0 )
854  {
855  RecordSphere(current_pathto_pos, 8, ‪BLUE);
856  }
857  #/
858 
859  /#
860  if( GetDvarInt("debug_sentinel_drone_paths") > 0 )
861  {
862  if(!IsPointInNavVolume(current_pathto_pos, "navvolume_small") )
863  {
864  recordLine( current_pathto_pos, level.players[0].origin + (0, 0, 48), ‪WHITE );
865  RecordSphere(current_pathto_pos, 10, ‪WHITE);
866  PrintTopRightln("Target Fail ID: " + self GetEntityNumber(), ‪WHITE);
867  }
868 
869  if(!‪IS_TRUE(is_on_nav_volume))
870  {
871  recordLine( self.origin, level.players[0].origin + (0, 0, 48), ‪GREEN );
872  RecordSphere(self.origin, 10, ‪GREEN);
873  PrintTopRightln("Me Fail ID: " + self GetEntityNumber(), ‪GREEN);
874  }
875  }
876  #/
877 
878  if ( self SetVehGoalPos( current_pathto_pos, true, b_use_path_finding ) )
879  {
880  b_use_path_finding = true;
881 
882  self.b_in_tactical_position = b_in_tactical_position;
883 
884  self thread ‪sentinel_PathUpdateInterrupt();
886  current_pathto_pos = undefined;
887  }
888  else if( ‪IS_TRUE(is_on_nav_volume) )
889  {
890  /#
891  if( GetDvarInt("debug_sentinel_drone_paths") > 0 )
892  {
893  PrintTopRightln("FAILED TO FIND PATH ID: " + self GetEntityNumber(), ‪RED);
894 
895  recordLine( current_pathto_pos, level.players[0].origin + (0, 0, 48), ‪RED );
896  RecordSphere(current_pathto_pos, 10, ‪RED);
897 
898  recordLine( self.origin, level.players[0].origin + (0, 0, 48), (1, 0.2, 0.2) );
899  RecordSphere(self.origin, 10, ‪RED);
900  }
901  #/
902 
903  self ‪sentinel_KillMyself();
904  self.last_failsafe_time = undefined;
905  }
906  }
907 
908  if( !‪IS_TRUE(is_on_nav_volume) )
909  {
910  if(!isdefined(self.last_failsafe_time))
911  {
912  self.last_failsafe_time = GetTime();
913  }
914 
915  if( (GetTime() - self.last_failsafe_time) >= 3000)
916  {
917  self.last_failsafe_count = 0;
918  }
919  else
920  {
921  self.last_failsafe_count++;
922  }
923 
924  self.last_failsafe_time = GetTime();
925 
926  if( self.last_failsafe_count > 25 )
927  {
928  new_sentinel_pos = self GetClosestPointOnNavVolume( self.origin, 120 );
929 
930  if(isdefined(new_sentinel_pos))
931  {
932  dvar_sentinel_getback_to_volume_epsilon = GetDvarInt("dvar_sentinel_getback_to_volume_epsilon", 5);
933  if( Distance(self.origin, new_sentinel_pos) < dvar_sentinel_getback_to_volume_epsilon )
934  {
935  self.origin = new_sentinel_pos;
936 
937  /#
938  if( GetDvarInt("debug_sentinel_drone_traces") > 0 )
939  {
940  RecordSphere(new_sentinel_pos, 8, ‪RED);
941  }
942  #/
943  }
944  else
945  {
946  self.vehAirCraftCollisionEnabled = false;
947 
948  /#
949  if( GetDvarInt("debug_sentinel_drone_traces") > 0 )
950  {
951  RecordSphere(new_sentinel_pos, 8, ‪RED);
952  }
953  #/
954 
955  if( self SetVehGoalPos( new_sentinel_pos, true, false ) )
956  {
957  self thread ‪sentinel_PathUpdateInterrupt();
959  current_pathto_pos = undefined;
960  }
961 
962  self.vehAirCraftCollisionEnabled = true;
963  }
964  }
965  else if( self.last_failsafe_count > 100 )
966  {
967  self ‪sentinel_KillMyself();
968  }
969  }
970  }
971 
972  if( !‪IS_TRUE( is_on_nav_volume ) )
973  {
974  //not on navmesh, no valid goto points, kill sentinel_drone as failsafe
975  if( !isdefined( self.stuckTime ) )
976  {
977  self.stuckTime = GetTime();
978  }
979 
980  if( GetTime() - self.stuckTime > 15000 )
981  {
982  self ‪sentinel_KillMyself();
983  }
984  }
985 
986  wait 0.1;
987  }
988 }
989 
990 function ‪sentinel_GetNextMovePositionTactical( b_do_not_chase_enemy ) // has self.sentinel_droneEnemy
991 {
992  self endon( "change_state" );
993  self endon( "death" );
994 
995  // distance based multipliers
996  if(isdefined(self.sentinel_droneEnemy))
997  {
998  selfDistToTarget = Distance2D( self.origin, self.sentinel_droneEnemy.origin );
999  }
1000  else
1001  {
1002  selfDistToTarget = 0;
1003  }
1004 
1006 
1007  closeDist = 1.2 * goodDist;
1008  farDist = 3 * goodDist;
1009 
1010  queryMultiplier = MapFloat( closeDist, farDist, 1, 3, selfDistToTarget );
1011 
1012  //the preferred height range should be half the max possible difference to not exceed valid heights for points near the goalheight
1013  preferedHeightRange = 0.5 * ( ‪sentinel_GetEngagementHeightMax() + ‪sentinel_GetEngagementHeightMin() );
1014  randomness = 20;
1015 
1016  SENTINEL_DRONE_TOO_CLOSE_TO_SELF_DIST_EX = GetDvarInt("SENTINEL_DRONE_TOO_CLOSE_TO_SELF_DIST_EX", 70);
1017  SENTINEL_DRONE_MOVE_DIST_MAX_EX = GetDvarInt("SENTINEL_DRONE_MOVE_DIST_MAX_EX", 600);
1018  SENTINEL_DRONE_MOVE_SPACING = GetDvarInt("SENTINEL_DRONE_MOVE_SPACING", 25);
1019  SENTINEL_DRONE_RADIUS_EX = GetDvarInt("SENTINEL_DRONE_RADIUS_EX", 35);
1020  SENTINEL_DRONE_HIGHT_EX = GetDvarInt("SENTINEL_DRONE_HIGHT_EX", int(preferedHeightRange));
1021 
1022  spacing_multiplier = 1.5;
1023  query_min_dist = self.settings.engagementDistMin;
1024  query_max_dist = SENTINEL_DRONE_MOVE_DIST_MAX_EX;
1025 
1026  // query
1027  if(!‪IS_TRUE(b_do_not_chase_enemy) && isdefined(self.sentinel_droneEnemy) && (GetTime() > self.targetPlayerTime) )
1028  {
1029  charge_at_position = self.sentinel_droneEnemy.origin + (0, 0, 48);
1030 
1031  if(!IsPointInNavVolume( charge_at_position, "navvolume_small" ))
1032  {
1033  closest_point_on_nav_volume = GetDvarInt("closest_point_on_nav_volume", 120);
1034  charge_at_position = self GetClosestPointOnNavVolume( charge_at_position, closest_point_on_nav_volume );
1035  }
1036 
1037  if(!isdefined(charge_at_position))
1038  {
1039  queryResult = PositionQuery_Source_Navigation( self.origin, SENTINEL_DRONE_TOO_CLOSE_TO_SELF_DIST_EX, SENTINEL_DRONE_MOVE_DIST_MAX_EX * queryMultiplier, SENTINEL_DRONE_HIGHT_EX * queryMultiplier, SENTINEL_DRONE_MOVE_SPACING, "navvolume_small", SENTINEL_DRONE_MOVE_SPACING * spacing_multiplier );
1040  }
1041  else
1042  {
1044  {
1045  spacing_multiplier = 1;
1046  SENTINEL_DRONE_MOVE_SPACING = 15;
1047  query_min_dist = self.settings.engagementDistMin * GetDvarFloat("sentinel_query_min_dist", 0.2);
1048  query_max_dist = query_max_dist * 0.5;
1049  }
1050  else if(‪IS_TRUE(self.in_compact_mode) || ‪sentinel_IsEnemyIndoors())
1051  {
1052  spacing_multiplier = 1;
1053  SENTINEL_DRONE_MOVE_SPACING = 15;
1054  query_min_dist = self.settings.engagementDistMin * GetDvarFloat("sentinel_query_min_dist", 0.5);
1055  }
1056 
1057  queryResult = PositionQuery_Source_Navigation( charge_at_position, query_min_dist, query_max_dist * queryMultiplier, SENTINEL_DRONE_HIGHT_EX * queryMultiplier, SENTINEL_DRONE_MOVE_SPACING, "navvolume_small", SENTINEL_DRONE_MOVE_SPACING * spacing_multiplier );
1058  }
1059  }
1060  else
1061  {
1062  queryResult = PositionQuery_Source_Navigation( self.origin, SENTINEL_DRONE_TOO_CLOSE_TO_SELF_DIST_EX, SENTINEL_DRONE_MOVE_DIST_MAX_EX * queryMultiplier, SENTINEL_DRONE_HIGHT_EX * queryMultiplier, SENTINEL_DRONE_MOVE_SPACING, "navvolume_small", SENTINEL_DRONE_MOVE_SPACING * spacing_multiplier );
1063  }
1064 
1065  // filter
1066  PositionQuery_Filter_DistanceToGoal( queryResult, self );
1068 
1069  if(isdefined(self.sentinel_droneEnemy))
1070  {
1071  if( RandomInt(100) > 15)
1072  {
1074  }
1075 
1076  goalHeight = self.sentinel_droneEnemy.origin[2] + 0.5 * ( ‪sentinel_GetEngagementHeightMin() + ‪sentinel_GetEngagementHeightMax() );
1077  enemy_origin = self.sentinel_droneEnemy.origin + (0, 0, 48);
1078  }
1079  else
1080  {
1081  goalHeight = self.origin[2] + 0.5 * ( ‪sentinel_GetEngagementHeightMin() + ‪sentinel_GetEngagementHeightMax() );
1082  enemy_origin = self.origin;
1083  }
1084 
1085  // score points
1086  best_point = undefined;
1087  best_score = undefined;
1088  trace_count = 0;
1089  foreach ( point in queryResult.data )
1090  {
1091  if( ‪sentinel_IsInsideEngagementDistance( enemy_origin, point.origin ) )
1092  {
1093  ADD_POINT_SCORE( point, "insideEngagementDistance", 25 );
1094  }
1095 
1096  ADD_POINT_SCORE( point, "random", randomFloatRange( 0, randomness ) );
1097 
1098  if(isdefined(point.distAwayFromEngagementArea))
1099  {
1100  ADD_POINT_SCORE( point, "engagementDist", -point.distAwayFromEngagementArea );
1101  }
1102 
1103  is_near_another_sentinel = Sentinel_IsNearAnotherSentinel( point.origin, 200 ); //*! \details **Description:**
1104 <br/>ToDo ‪move to variable
1105 
1106  if(‪IS_TRUE(is_near_another_sentinel))
1107  {
1108  ADD_POINT_SCORE( point, "NearAnotherSentinel", -200 ); //*! \details **Description:**
1109 <br/>ToDo ‪move to variable
1110  }
1111 
1112  is_overlap_another_sentinel = Sentinel_IsNearAnotherSentinel( point.origin, 100 ); //*! \details **Description:**
1113 <br/>ToDo ‪move to variable
1114 
1115  if(‪IS_TRUE(is_overlap_another_sentinel))
1116  {
1117  ADD_POINT_SCORE( point, "OverlapAnotherSentinel", -2000 ); //*! \details **Description:**
1118 <br/>ToDo ‪move to variable
1119  }
1120 
1121  is_near_another_player = ‪sentinel_IsNearAnotherPlayer(point.origin, 150); //*! \details **Description:**
1122 <br/>ToDo ‪move to variable
1123 
1124  if(‪IS_TRUE(is_near_another_player))
1125  {
1126  ADD_POINT_SCORE( point, "NearAnotherPlayer", -200 ); //*! \details **Description:**
1127 <br/>ToDo ‪move to variable
1128  }
1129 
1130  // height
1131  distFromPreferredHeight = abs( point.origin[2] - goalHeight );
1132  if ( distFromPreferredHeight > preferedHeightRange )
1133  {
1134  heightScore = (distFromPreferredHeight - preferedHeightRange) * 3;// MapFloat( 0, 500, 0, 1000, distFromPreferredHeight );
1135  ADD_POINT_SCORE( point, "height", -heightScore );
1136  }
1137 
1138  if(!isdefined(best_score))
1139  {
1140  best_score = point.score;
1141  best_point = point;
1142 
1143  if( isdefined(self.sentinel_droneEnemy) )
1144  {
1145  best_point.visibile = int(BulletTracePassed(point.origin, enemy_origin, false, self, self.sentinel_droneEnemy));
1146  }
1147  else
1148  {
1149  best_point.visibile = int(BulletTracePassed(point.origin, enemy_origin, false, self));
1150  }
1151  }
1152  else
1153  {
1154  if ( point.score > best_score )
1155  {
1156  if( isdefined(self.sentinel_droneEnemy) )
1157  {
1158  point.visibile = int(BulletTracePassed(point.origin, enemy_origin, false, self, self.sentinel_droneEnemy));
1159  }
1160  else
1161  {
1162  point.visibile = int(BulletTracePassed(point.origin, enemy_origin, false, self));
1163  }
1164 
1165  if(point.visibile >= best_point.visibile)
1166  {
1167  best_score = point.score;
1168  best_point = point;
1169  }
1170  }
1171  }
1172 
1173  }
1174 
1175  //do not get too close to other sentinels
1176  if( isdefined( best_point) )
1177  {
1178  if( best_point.score < -1000)
1179  {
1180  best_point = undefined;
1181  }
1182  }
1183 
1184  self ‪vehicle_ai::PositionQuery_DebugScores( queryResult );
1185 
1186  /#
1187  if ( ‪IS_TRUE( GetDvarInt("hkai_debugPositionQuery") ) )
1188  {
1189  if(isdefined(best_point) )
1190  {
1191  recordLine( self.origin, best_point.origin, (0.3,1,0) );
1192  }
1193 
1194  if(isdefined(self.sentinel_droneEnemy))
1195  {
1196  recordLine( self.origin, self.sentinel_droneEnemy.origin, (1,0,0.4) );
1197  }
1198  }
1199 #/
1200  returnData = [];
1201  returnData[ "origin" ] = ( ( IsDefined( best_point ) ) ? best_point.origin : undefined );
1202  returnData[ "centerOnNav" ] = queryResult.centerOnNav;
1203  return returnData;
1204 }
1205 
1206 function ‪sentinel_ChargeAtPlayerNavigation( b_charge_at_player, ‪time_out, charge_at_position )
1207 {
1208  self endon( "change_state" );
1209  self endon( "death" );
1210 
1211  if( isdefined(‪time_out) )
1212  {
1213  max_charge_time = GetTime() + ‪time_out;
1214  }
1215 
1216  if( !isdefined(charge_at_position) )
1217  {
1218  if( ‪IS_TRUE(b_charge_at_player) )
1219  {
1220  charge_at_position = self.sentinel_droneEnemy.origin + (0, 0, 48);
1221  }
1222  else
1223  {
1224  sentinel_dir = AnglesToForward(self.angles);
1225  charge_at_position = self.origin + sentinel_dir * Length( self.sentinel_droneEnemy.origin - self.origin);
1226  charge_at_position = ( charge_at_position[0], charge_at_position[1], self.sentinel_droneEnemy.origin[2] );
1227  }
1228  }
1229 
1230  charge_at_dir = VectorNormalize(charge_at_position - self.origin);
1231  charge_at_position = self.origin + charge_at_dir * ‪SENTINEL_DRONE_BEAM_MAX_LENGTH;
1232 
1233  self ClearLookAtEnt();
1234  self SetVehGoalPos( charge_at_position, true, false );
1235  self SetLookAtOrigin( charge_at_position );
1236 
1237  while(true)
1238  {
1239  velocity = self GetVelocity() * 0.1;
1240  velocityMag = Length(velocity);
1241 
1242  if(velocityMag < 1)
1243  {
1244  velocityMag = 1;
1245  }
1246 
1247  predicted_pos = self.origin + velocity;
1248 
1249  offset = VectorNormalize(predicted_pos - self.origin) * ‪SENTINEL_DRONE_RADIUS;
1250 
1251  ‪trace = ‪sentinel_Trace( self.origin + offset, predicted_pos + offset, self, true);
1252 
1253  if( ‪trace["fraction"] < 1)
1254  {
1255  if( !(isdefined(‪trace["entity"]) && ‪trace["entity"].archetype === ‪ARCHETYPE_ZOMBIE && isdefined(‪trace["entity"].health) && ‪trace["entity"].health == 0) )
1256  {
1258  return;
1259  }
1260  }
1261 
1262  if( isdefined(max_charge_time) && (GetTime() > max_charge_time) )
1263  {
1265  return;
1266  }
1267 
1268  wait 0.1;
1269  }
1270 }
1271 
1273 {
1274  self endon( "death" );
1275  self endon( "change_state" );
1276  self endon( "near_goal" );
1277  self endon( "reached_end_node" );
1278 
1279  self notify( "sentinel_PathUpdateInterrupt" );
1280  self endon( "sentinel_PathUpdateInterrupt" );
1281 
1282  skip_sentinel_PathUpdateInterrupt = GetDvarInt("skip_sentinel_PathUpdateInterrupt", 1);
1283 
1284  if(skip_sentinel_PathUpdateInterrupt == 1)
1285  {
1286  return;
1287  }
1288 
1289  wait 1;
1290 
1291  while( 1 )
1292  {
1293  if( isdefined( self.current_pathto_pos ) )
1294  {
1295  if( distance2dSquared( self.origin, self.goalpos ) < ‪SQR( self.goalradius ) )
1296  {
1297  /#
1298  if( GetDvarInt("debug_sentinel_drone_traces") > 0 )
1299  {
1300  RecordSphere(self.origin, 30, ‪RED);
1301  }
1302  #/
1303 
1304  wait 0.2;
1305  self notify( "near_goal" );
1306  }
1307  }
1308  wait 0.2;
1309  }
1310 }
1311 
1312 
1314 {
1315  self endon( "death" );
1316  self endon( "change_state" );
1317 
1318  while(true)
1319  {
1320  while( ‪sentinel_IsNearAnotherPlayer(self.origin, 120) )
1321  {
1322  self playrumbleonentity("damage_heavy");
1323  wait 0.1;
1324  }
1325 
1326  wait 0.5;
1327  }
1328 }
1329 
1330 // ----------------------------------------------Beam Fire Logic
1331 
1332 function ‪sentinel_CanSeeEnemy( sentinel_origin, prev_enemy_position )
1333 {
1334  ‪result = SpawnStruct();
1335  ‪result.can_see_enemy = false;
1336  enemy_moved = false;
1337  b_still_enemy_in_pos_check = false;
1338 
1339  origin_point = sentinel_origin;
1340 
1341  if(!isdefined(prev_enemy_position) )
1342  {
1343  target_point = self.sentinel_droneEnemy.origin + (0,0,48);
1344 
1345  if( IsPlayer(self.sentinel_droneEnemy) )
1346  {
1347  enemy_stance = self.sentinel_droneEnemy GetStance();
1348 
1349  if( enemy_stance == "prone" )
1350  {
1351  target_point = self.sentinel_droneEnemy.origin + (0,0,2);
1352  }
1353  }
1354  }
1355  else
1356  {
1357  b_still_enemy_in_pos_check = true;
1358  target_point = prev_enemy_position;
1359  }
1360 
1361  forward_vect = AnglesToForward( self.angles );
1362  vect_to_enemy = target_point - origin_point;
1363 
1364  if( VectorDot(forward_vect, vect_to_enemy) <= 0 ) //player behind drone
1365  {
1366  if(!b_still_enemy_in_pos_check)
1367  {
1368  return ‪result;
1369  }
1370  else
1371  {
1372  enemy_moved = true;
1373  }
1374  }
1375 
1376  if(!‪IS_TRUE(enemy_moved))
1377  {
1378  //Check if the enemy is inside my sight rect range
1379  right_vect = AnglesToRight( self.angles );
1380  vect_to_enemy_2d = (vect_to_enemy[0], vect_to_enemy[1], 0);
1381 
1382  projected_distance = VectorDot(vect_to_enemy_2d, right_vect);
1383 
1384  if(abs(projected_distance) > 50)
1385  {
1386  if(!b_still_enemy_in_pos_check)
1387  {
1388  return ‪result;
1389  }
1390  else
1391  {
1392  enemy_moved = true;
1393  }
1394  }
1395  }
1396 
1397  //extend the ray check if the enemy moved
1398  if(b_still_enemy_in_pos_check)
1399  {
1400  beam_to_enemy_length = Distance(target_point, origin_point);
1401  beam_to_enemy_dir = target_point - origin_point;
1402  beam_to_enemy_dir = VectorNormalize(beam_to_enemy_dir);
1403  target_point = origin_point + VectorScale(beam_to_enemy_dir, ‪SENTINEL_DRONE_BEAM_MAX_LENGTH);
1404  }
1405 
1406  ‪trace = ‪sentinel_Trace(origin_point, target_point, self.sentinel_droneEnemy, false);
1407 
1408  /#
1409  if( GetDvarInt("debug_sentinel_drone_traces") > 0 )
1410  {
1411  recordLine( origin_point, target_point, ‪GREEN );
1412  RecordSphere(target_point, 8);
1413  }
1414  #/
1415 
1416  ‪result.hit_entity = ‪trace["entity"];
1417  ‪result.hit_position = ‪trace["position"];
1418 
1419  if( ( IsPlayer(‪trace["entity"]) ) || ( ‪IS_TRUE(self.should_buff_zombies) && isdefined(‪trace["entity"]) && isdefined(‪trace["entity"].archetype) && (‪trace["entity"].archetype == ‪ARCHETYPE_ZOMBIE) ) )
1420  {
1421  ‪result.can_see_enemy = true;
1422  return ‪result;
1423  }
1424 
1425  return ‪result;
1426 }
1427 
1429 {
1430  if(‪IS_TRUE(self.playing_intro_anim))
1431  {
1432  return false;
1433  }
1434 
1435  if(self.arms_count <= 0)
1436  {
1437  return false;
1438  }
1439 
1440  if(!‪IS_TRUE(self.target_initialized))
1441  {
1442  wait 0.5;
1443  return false;
1444  }
1445 
1446  if( isdefined( self.sentinel_droneEnemy ) && (!isdefined(self.nextFireTime) || (GetTime() > self.nextFireTime) ) )
1447  {
1448  if( ( ( ‪IS_TRUE(self.b_in_tactical_position) && (‪IS_TRUE(self.in_compact_mode) || ‪sentinel_IsEnemyIndoors()) ) ||
1449  (‪sentinel_IsInsideEngagementDistance(self.origin, self.sentinel_droneEnemy.origin + (0, 0, 48), true) && IsPointInNavVolume( self.origin, "navvolume_small" )) ) &&
1450  !Sentinel_IsNearAnotherSentinel( self.origin, 100 ) )
1451  {
1452  ‪result = ‪sentinel_CanSeeEnemy( self.origin );
1453 
1454  if(‪result.can_see_enemy)
1455  {
1456  self.nextFireTime = GetTime() + 2500 + RandomInt(2500);
1457 
1459  wait 0.1;
1460 
1461  if(!isdefined( self.sentinel_droneEnemy ))
1462  {
1463  return true;
1464  }
1465 
1466  enemy_pos = self.sentinel_droneEnemy.origin;
1467 
1468  if(RandomInt(100) < 70 ) //*! \details **Description:**
1469 <br/>ToDo ‪move to variable
1470  {
1471  b_succession = true;
1472  }
1473 
1474  //switch to fire animation
1475  self.beam_start_position = self.origin;
1476 
1477  if(‪IS_TRUE(b_succession))
1478  {
1479  fire_state_name = "fire_succession@attack"; //*! \details **Description:**
1480 <br/>Todo: ‪move state ‪name to variable
1481  }
1482  else
1483  {
1484  fire_state_name = "fire@attack"; //*! \details **Description:**
1485 <br/>Todo: ‪move state ‪name to variable
1486  }
1487 
1488  self ASMRequestSubstate( fire_state_name );
1489 
1490  //Start the claws charging
1491  self ‪clientfield::set("sentinel_drone_beam_charge", 1);
1492 
1493  //Look at fire direction
1494  beam_dir = ‪result.hit_position - self.origin;
1495 
1496  self.beam_fire_target.origin = ‪result.hit_position;
1497  self.beam_fire_target.angles = VectorToAngles( -beam_dir );
1498 
1499  /#
1500  if( GetDvarInt("debug_sentinel_drone_traces") > 0 )
1501  {
1502  recordLine( self.origin, ‪result.hit_position, (0.9, 0.7, 0.6) );
1503  RecordSphere(‪result.hit_position, 8, (0.9, 0.7, 0.6));
1504  }
1505  #/
1506 
1507  self clearlookatent();
1508  self.angles = VectorToAngles(beam_dir);
1509 
1510  self SetLookAtEnt( self.beam_fire_target );
1511  self setTurretTargetEnt( self.beam_fire_target );
1512 
1513  //reached the point in the animation to start firing
1514  self waittill( "fire_beam" );
1515 
1516  //Stop claws charging before firing the beam
1517  self ‪clientfield::set("sentinel_drone_beam_charge", 0);
1518 
1519  ‪result = ‪sentinel_CanSeeEnemy( self.beam_start_position, ‪result.hit_position );
1520 
1521  if(‪result.can_see_enemy)
1522  {
1523  if(!‪IS_TRUE(b_succession) && IsPlayer(‪result.hit_entity))
1524  {
1525  ‪result.hit_entity thread ‪sentinel_DamagePlayer( int(‪SENTINEL_DRONE_BEAM_DAMAGE_PER_SECOND * 0.5), self); //*! \details **Description:**
1526 <br/>ToDo ‪move ‪damage to variable
1527  }
1528 
1529  ‪sentinel_FireBeam( ‪result.hit_position, b_succession );
1530  }
1531  else
1532  {
1533  ‪sentinel_FireBeam(‪result.hit_position, b_succession);
1534  }
1535 
1536  self ‪vehicle_ai::waittill_asm_complete( fire_state_name, 5 );
1537 
1538  if( isdefined(self.sentinel_droneEnemy) )
1539  {
1540  self SetLookAtEnt( self.sentinel_droneEnemy );
1541  self setTurretTargetEnt( self.sentinel_droneEnemy );
1542  }
1543 
1544  //switch back to locomotion
1545  self ASMRequestSubstate( "locomotion@movement" ); //*! \details **Description:**
1546 <br/>Todo: ‪move state ‪name to variable
1547 
1548  //Change position
1549  if( RandomInt(100) < 40 )
1550  {
1552  }
1553 
1554  //Reset next fire time
1555  if(RandomInt(100) < 30)
1556  {
1557  self.nextFireTime = GetTime() + 2500 + RandomInt(2500);
1558  }
1559 
1560  return true;
1561  }
1562  }
1563  }
1564 
1565  return false;
1566 }
1567 
1568 
1569 
1570 function ‪sentinel_FireBeam( target_position, b_succession )
1571 {
1572  self endon( "change_state" );
1573  self endon( "disconnect" );
1574  self endon( "death" );
1575  self endon("death_state_activated");
1576 
1577  self.lastTimeFired = GetTime();
1578 
1579  //Look at fire direction
1580  beam_dir = target_position - self.origin;
1581 
1582  self.beam_fire_target.origin = target_position;
1583  self.beam_fire_target.angles = VectorToAngles( -beam_dir );
1584 
1585  //self clearlookatent();
1586  self.angles = VectorToAngles(beam_dir);
1587  //self SetLookAtEnt( self.beam_fire_target );
1588  self setTurretTargetEnt( self.beam_fire_target );
1589  /*
1590  /#
1591  forward_dir = AnglesToForward( self.angles );
1592  recordLine( self.origin, self.origin + VectorScale(forward_dir, 300), GREEN );
1593  recordLine( self.origin, self.origin + VectorScale(beam_dir, 500), RED );
1594  #/
1595  */
1596 
1597  /*
1598  /#
1599  Sphere(target_position, 15, GREEN,0.5, false, 10, 360);
1600  #/
1601  */
1602  self.is_firing_beam = true;
1603 
1604  if(!‪IS_TRUE(b_succession))
1605  {
1606  ‪sentinel_FireBeamBurst( target_position );
1607  }
1608  else
1609  {
1610  ‪sentinel_FireBeamSuccession( target_position );
1611  }
1612 
1613  self.is_firing_beam = false;
1614 }
1615 
1616 function ‪sentinel_FireBeamBurst( target_position )
1617 {
1618  self endon( "change_state" );
1619  self endon( "disconnect" );
1620  self endon( "death" );
1621  self endon("death_state_activated");
1622 
1623  for(i = 1; i <= 3; i++)
1624  {
1625  if( self.sentinelDroneHealthArms[i] <= 0 ) //no arm
1626  {
1627  continue;
1628  }
1629 
1630  self ‪clientfield::set("sentinel_drone_beam_fire" + i, 1);
1631 
1632  /*
1633  /#
1634  Sphere(self.beam_fire_start_models[i].origin, 10, WHITE,0.5, false, 10, 360);
1635  #/
1636  */
1637  }
1638 
1639  wait 0.1;
1640 
1641  start_beam_time = GetTime() + 2000;
1642  beam_damage_update = 0.1;
1643 
1644  ‪player_damage = int(‪SENTINEL_DRONE_BEAM_DAMAGE_PER_SECOND * beam_damage_update);
1645 
1646  while(GetTime() < start_beam_time || ‪IS_TRUE(self.sentinel_DebugFX_PlayAll))
1647  {
1649 
1650  wait beam_damage_update;
1651  }
1652 
1653  for(i = 1; i <= 3; i++)
1654  {
1655  if( self.sentinelDroneHealthArms[i] <= 0 ) //no arm
1656  {
1657  continue;
1658  }
1659 
1660  self ‪clientfield::set("sentinel_drone_beam_fire" + i, 0);
1661  }
1662 }
1663 
1664 function ‪sentinel_FireBeamSuccession( target_position )
1665 {
1666  self endon( "change_state" );
1667  self endon( "disconnect" );
1668  self endon( "death" );
1669  self endon("death_state_activated");
1670 
1672 
1673  arms_order = [];
1674  arms_order[0] = ‪SENTINEL_DRONE_ARM_LEFT;
1675  arms_order[1] = ‪SENTINEL_DRONE_ARM_RIGHT;
1676  arms_order[2] = ‪SENTINEL_DRONE_ARM_TOP;
1677 
1678  arms_notifies = [];
1679  arms_notifies[0] = "attack_quick_left";
1680  arms_notifies[1] = "attack_quick_right";
1681  arms_notifies[2] = "attack_quick_top";
1682 
1683  for(i = 0; i < 3; i++)
1684  {
1685  if( self.sentinelDroneHealthArms[arms_order[i]] <= 0 ) //no arm
1686  {
1687  continue;
1688  }
1689 
1690  self ‪util::waittill_any_timeout(0.3, arms_notifies[i], "change_state", "disconnect", "death", "death_state_activated" );
1691 
1692 
1693  self ‪clientfield::set("sentinel_drone_beam_fire" + arms_order[i], 1);
1694 
1695  ‪sentinel_DamageBeamTouchingEntity( ‪player_damage, target_position, true );
1696 
1697  wait 0.1;
1698 
1699  self ‪clientfield::set("sentinel_drone_beam_fire" + arms_order[i], 0);
1700  }
1701 }
1702 
1703 function ‪sentinel_DamageBeamTouchingEntity( ‪player_damage, target_position, b_succession = false )
1704 {
1705  ‪trace = ‪sentinel_Trace(self.origin, target_position, self.sentinel_droneEnemy, false);
1706  trace_entity = ‪trace["entity"];
1707 
1708  if( IsPlayer(trace_entity) )
1709  {
1710  trace_entity thread ‪sentinel_DamagePlayer( ‪player_damage, self, b_succession);
1711  }
1712  else if( isdefined(trace_entity) && isdefined(trace_entity.archetype) && trace_entity.archetype == ‪ARCHETYPE_ZOMBIE)
1713  {
1714  self thread ‪sentinel_ElectrifyZombie( trace_entity.origin, trace_entity, 80);
1715  }
1716 }
1717 
1718 
1719 //----------------------------------------------Self Destruct logic
1720 
1722 {
1723  self endon( "change_state" );
1724  self endon( "disconnect" );
1725  self endon( "death" );
1726  self endon("death_state_activated");
1727 
1728  wait time;
1729 
1730  Sentinel_KillMySelf();
1731 }
1732 
1733 // ----------------------------------------------Charge at Player Logic
1734 
1736 {
1737  if(!isdefined(self))
1738  {
1739  return;
1740  }
1741 
1742  self endon( "change_state" );
1743  self endon( "disconnect" );
1744  self endon( "death" );
1745  self endon("death_state_activated");
1746 
1747  //self sentinel_DeactivateAllEffects();
1748 
1749  charge_at_position = self.sentinel_droneEnemy.origin + (0, 0, 48);
1750 
1751  wait 0.3;
1752 
1753  self.is_charging_at_player = true;
1755 
1756  ‪sentinel_play_taunt( level._sentinel_System_Critical_Taunts );
1757 
1758  self ASMRequestSubstate( "suicide_intro@death" ); //Play charge intro anim
1759 
1760  wait 2;
1761 
1762  if( self.sentinelDroneHealthCamera <= 0 )
1763  {
1764  b_charge_at_player = false;
1765  }
1766  else
1767  {
1768  charge_at_position = undefined;
1769  b_charge_at_player = true;
1770  }
1771 
1772  self ASMRequestSubstate( "suicide_charge@death" ); //Play charge movement anim
1773 
1774  self SetSpeed( 60 ); //*! \details **Description:**
1775 <br/>ToDo: ‪move to GDT
1776 
1777  self thread ‪sentinel_ChargeAtPlayerNavigation( b_charge_at_player, ‪SENTINEL_CHARGE_AT_PLAYER_TIME_OUT, charge_at_position);
1778 
1779  detonation_distance_sq = 100 * 100; //*! \details **Description:**
1780 <br/>ToDo: ‪move to GDT
1781 
1782  while(isdefined(self) && isdefined(self.sentinel_droneEnemy))
1783  {
1784  distance_sq = DistanceSquared(self.sentinel_droneEnemy.origin + (0, 0, 48), self.origin);
1785 
1786  if( distance_sq <= detonation_distance_sq)
1787  {
1788  sentinel_killmyself();
1789  }
1790 
1791  wait 0.2;
1792  }
1793 }
1794 
1795 // ----------------------------------------------
1796 // Damage States functions
1797 // ----------------------------------------------
1798 
1799 function ‪IsLeftArm(part_name)
1800 {
1801  if(!isdefined(part_name))
1802  {
1803  return false;
1804  }
1805 
1806  return IsSubStr(part_name, "tag_arm_left");
1807 }
1808 
1809 function ‪IsRightArm(part_name)
1810 {
1811  if(!isdefined(part_name))
1812  {
1813  return false;
1814  }
1815 
1816  return IsSubStr(part_name, "tag_arm_right");
1817 }
1818 
1819 function ‪IsTopArm(part_name)
1820 {
1821  if(!isdefined(part_name))
1822  {
1823  return false;
1824  }
1825 
1826  return IsSubStr(part_name, "tag_arm_top");
1827 }
1828 
1829 function ‪IsCore(part_name)
1830 {
1831  if(!isdefined(part_name))
1832  {
1833  return false;
1834  }
1835 
1836  if( part_name == ‪SENTINEL_DRONE_FACE_TAG ||
1837  part_name == ‪SENTINEL_DRONE_CORE_TAG ||
1838  part_name == ‪SENTINEL_DRONE_CORE_TAG_2 ||
1839  part_name == ‪SENTINEL_DRONE_CORE_TAG_3 )
1840  {
1841  return true;
1842  }
1843 
1844  return false;
1845 }
1846 
1847 function ‪IsCamera(part_name)
1848 {
1849  if(!isdefined(part_name))
1850  {
1851  return false;
1852  }
1853 
1854  if( part_name == "tag_camera_dead" ||
1855  part_name == "tag_flash" ||
1856  part_name == "tag_laser" ||
1857  part_name == "tag_turret")
1858  {
1859  return true;
1860  }
1861 
1862  return false;
1863 }
1864 
1865 function ‪sentinel_GetArmNumber(part_name)
1866 {
1867  if(!isdefined(part_name))
1868  {
1869  return 0;
1870  }
1871 
1872  if( ‪IsLeftArm(part_name) )
1873  {
1875  }
1876  else if( ‪IsRightArm(part_name) )
1877  {
1879  }
1880  else if( ‪IsTopArm(part_name) )
1881  {
1883  }
1884 
1885  return 0;
1886 }
1887 
1888 function private ‪sentinel_ArmDamage( ‪damage, arm, eAttacker = undefined )
1889 {
1890  if(self.arms_count == 0)
1891  {
1892  return;
1893  }
1894 
1895  if(arm == 0 || ‪damage == 0)
1896  {
1897  return;
1898  }
1899 
1900  if(self.sentinelDroneHealthArms[arm] <= 0)
1901  {
1902  return;
1903  }
1904 
1905  self.sentinelDroneHealthArms[arm] = self.sentinelDroneHealthArms[arm] - ‪damage;
1906 
1907  if( self.sentinelDroneHealthArms[arm] <= 0 )
1908  {
1909  self.arms_count--;
1910 
1911  if ( IsPlayer( eAttacker ) ) // track whether the same player was responsible for all arms being destroyed, as that's a challenge requirement
1912  {
1913  if ( !isdefined( self.e_arms_attacker ) && self.arms_count == 2 )
1914  {
1915  self.e_arms_attacker = eAttacker;
1916  self.b_same_arms_attacker = true;
1917  }
1918  else
1919  {
1920  if ( self.e_arms_attacker !== eAttacker )
1921  {
1922  self.b_same_arms_attacker = false;
1923  }
1924  }
1925  }
1926 
1927  self ‪clientfield::set( "sentinel_drone_arm_cut_" + arm, 1 );
1928 
1929  if(arm == ‪SENTINEL_DRONE_ARM_LEFT)
1930  {
1931  self HidePart( ‪SENTINEL_DRONE_ARM_LEFT_TAG, "", true );
1932  self ShowPart( ‪SENTINEL_DRONE_ARM_LEFT_BROKEN_TAG, "", true );
1933  }
1934  else if(arm == ‪SENTINEL_DRONE_ARM_RIGHT)
1935  {
1936  self HidePart( ‪SENTINEL_DRONE_ARM_RIGHT_TAG, "", true );
1937  self ShowPart( ‪SENTINEL_DRONE_ARM_RIGHT_BROKEN_TAG, "", true );
1938  }
1939  else if(arm == ‪SENTINEL_DRONE_ARM_TOP)
1940  {
1941  self HidePart( ‪SENTINEL_DRONE_ARM_TOP_TAG, "", true );
1942  self ShowPart( ‪SENTINEL_DRONE_ARM_TOP_BROKEN_TAG, "", true );
1943  }
1944 
1945  if( self.arms_count == 0 && !‪IS_TRUE(self.disable_charge_when_no_arms) )
1946  {
1948 
1949  if ( IsPlayer( eAttacker ) ) // check to make sure attacker is defined and a player
1950  {
1951  level notify( "all_sentinel_arms_destroyed", self.b_same_arms_attacker, eAttacker ); //used by DLC3 minor EE and challenges
1952  }
1953  }
1954  }
1955 }
1956 
1957 function ‪sentinel_DestroyAllArms( b_disable_charge )
1958 {
1959  self.disable_charge_when_no_arms = ‪IS_TRUE(b_disable_charge);
1960 
1961  ‪sentinel_ArmDamage(self.sentinelDroneHealthArms[‪SENTINEL_DRONE_ARM_LEFT] + 1000, ‪SENTINEL_DRONE_ARM_LEFT);
1962  ‪sentinel_ArmDamage(self.sentinelDroneHealthArms[‪SENTINEL_DRONE_ARM_RIGHT] + 1000, ‪SENTINEL_DRONE_ARM_RIGHT);
1963  ‪sentinel_ArmDamage(self.sentinelDroneHealthArms[‪SENTINEL_DRONE_ARM_TOP] + 1000, ‪SENTINEL_DRONE_ARM_TOP);
1964 }
1965 
1967 {
1970 
1971  wait 0.1;
1972  self thread ‪sentinel_ChargeAtPlayer();
1973 }
1974 
1975 function private ‪sentinel_DestroyFace()
1976 {
1977  ‪sentinel_FaceDamage( self.sentinelDroneHealthFace + 1000, ‪SENTINEL_DRONE_FACE_TAG );
1978 }
1979 
1980 function private ‪sentinel_DestroyCore()
1981 {
1982  ‪sentinel_CoreDamage( self.sentinelDroneHealthCore + 1000, ‪SENTINEL_DRONE_CORE_TAG );
1983 }
1984 
1985 function private ‪sentinel_FaceDamage( ‪damage, partName )
1986 {
1987  if(‪damage == 0)
1988  {
1989  return;
1990  }
1991 
1992  if(self.sentinelDroneHealthFace <= 0)
1993  {
1994  return;
1995  }
1996 
1997  if(!isdefined(partName) || partName != ‪SENTINEL_DRONE_FACE_TAG)
1998  {
1999  return;
2000  }
2001 
2002  self.sentinelDroneHealthFace = self.sentinelDroneHealthFace - ‪damage;
2003 
2004  if( self.sentinelDroneHealthFace <= 0 )
2005  {
2006  self ‪clientfield::set( "sentinel_drone_face_cut", 1 );
2007 
2008  self HidePart( ‪SENTINEL_DRONE_FACE_TAG, "", true );
2009  }
2010 }
2011 
2012 function private ‪sentinel_CoreDamage( ‪damage, partName )
2013 {
2014  if(‪damage == 0)
2015  {
2016  return;
2017  }
2018 
2019  if(self.sentinelDroneHealthFace > 0)
2020  {
2021  return;
2022  }
2023 
2024  if(self.sentinelDroneHealthCore <= 0)
2025  {
2026  return;
2027  }
2028 
2029  if(!‪IsCore(partName) )
2030  {
2031  return;
2032  }
2033 
2034  self.sentinelDroneHealthCore = self.sentinelDroneHealthCore - ‪damage;
2035 
2036  if( self.sentinelDroneHealthCore <= 0 )
2037  {
2038  self HidePart( ‪SENTINEL_DRONE_CORE_BLUE_TAG, "", true );
2039  self ShowPart( ‪SENTINEL_DRONE_CORE_RED_TAG, "", true );
2040  }
2041 }
2042 
2043 function private ‪sentinel_CameraDamage( ‪damage, partName, eAttacker )
2044 {
2045  if(‪damage == 0)
2046  {
2047  return;
2048  }
2049 
2050  if(self.sentinelDroneHealthCamera <= 0)
2051  {
2052  return;
2053  }
2054 
2055  if(!‪IsCamera(partName) )
2056  {
2057  return;
2058  }
2059 
2060  self.sentinelDroneHealthCamera = self.sentinelDroneHealthCamera - ‪damage;
2061 
2062  if( self.sentinelDroneHealthCamera <= 0 )
2063  {
2064  self HidePart( ‪SENTINEL_DRONE_CAMERA_TURRET_TAG, "", true );
2065  self ShowPart( ‪SENTINEL_DRONE_CAMERA_BROKEN_TAG, "", true );
2066 
2067  self ‪clientfield::set("sentinel_drone_camera_destroyed", 1);
2068 
2071 
2072  self thread ‪sentinel_SelfDestruct( 2000 );
2073  self thread ‪sentinel_ChargeAtPlayer();
2074 
2075  if ( IsPlayer( eAttacker ) )
2076  {
2077  level notify( "sentinel_camera_destroyed", eAttacker );
2078  }
2079  }
2080 }
2081 
2082 function ‪sentinel_CallbackDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal )
2083 {
2084  //Ignore other sentinels damage
2085  if(isdefined(eAttacker) && eAttacker.archetype === ‪ARCHETYPE_SENTINEL_DRONE)
2086  {
2087  return 0;
2088  }
2089 
2090  if(isdefined(eInflictor) && eInflictor.archetype === ‪ARCHETYPE_SENTINEL_DRONE)
2091  {
2092  return 0;
2093  }
2094 
2095  //InstaKill Multiplier
2096  if( isdefined(eAttacker) && isdefined(eAttacker.team) && isdefined(level.zombie_vars) && isdefined(level.zombie_vars[eAttacker.team]) &&
2097  ‪IS_TRUE( level.zombie_vars[eAttacker.team]["zombie_insta_kill"] ) )
2098  {
2099  iDamage = iDamage * 4; //*! \details **Description:**
2100 <br/>ToDo ‪move to variable
2101  }
2102 
2103  if(self.sentinelDroneHealthFace <= 0 && ‪IsCore(partName) )
2104  {
2105  iDamage = iDamage * 2; //*! \details **Description:**
2106 <br/>ToDo ‪move to variable
2107  }
2108 
2109  if(GetTime() > self.nextRollTime)
2110  {
2111  if(‪math::cointoss())
2112  {
2113  self.shouldRoll = true;
2114  }
2115  else
2116  {
2117  self.nextRollTime = GetTime() + RandomInt( 3000 );
2118  }
2119  }
2120 
2121  // PORTIZ: passing in the attacker for challenge tracking
2122  thread ‪sentinel_ArmDamage(iDamage, ‪sentinel_GetArmNumber(partName), eAttacker );
2123  thread ‪sentinel_FaceDamage(iDamage, partName);
2124  thread ‪sentinel_CameraDamage(iDamage, partName, eAttacker);
2125 
2126  return iDamage;
2127 }
2128 
2129 function ‪sentinel_drone_CallbackRadiusDamage( eInflictor, eAttacker, iDamage, fInnerDamage, fOuterDamage, iDFlags, sMeansOfDeath, weapon, vPoint, fRadius, fConeAngleCos, vConeDir, psOffsetTime )
2130 {
2131  //Ignore other sentinels damage
2132  if(isdefined(eAttacker) && eAttacker.archetype === ‪ARCHETYPE_SENTINEL_DRONE)
2133  {
2134  return 0;
2135  }
2136 
2137  if(isdefined(eInflictor) && eInflictor.archetype === ‪ARCHETYPE_SENTINEL_DRONE)
2138  {
2139  return 0;
2140  }
2141 
2142  if(GetTime() > self.nextRollTime)
2143  {
2144  if(‪math::cointoss())
2145  {
2146  self.shouldRoll = true;
2147  }
2148  else
2149  {
2150  self.nextRollTime = GetTime() + 3000 + RandomInt( 4000 );
2151  }
2152  }
2153 
2154  return iDamage;
2155 }
2156 
2157 
2158 // ----------------------------------------------
2159 // State: death
2160 // ----------------------------------------------
2161 
2162 function ‪state_death_update( params )
2163 {
2164  self endon( "death" );
2165 
2168 
2169  self ASMRequestSubstate( "normal@death" );
2170 
2171  ‪set_sentinel_drone_enemy( undefined );
2172 
2173  //self SetPhysAcceleration( ( 0, 0, -300 ) );
2174  //self.vehcheckforpredictedcrash = true;
2175 
2176  self thread ‪vehicle_death::death_fx();
2177  //self playsound( "zmb_parasite_explo" );
2178 
2179  //self util::waittill_notify_or_timeout( "veh_predictedcollision", 4.0 );
2180 
2181  self.beam_fire_target thread ‪sentinel_DeleteDroneDeathFX( self.origin );
2182 
2183 
2185  min_distance = 110;
2186 
2187  players = GetPlayers();
2188 
2189  for( i = 0; i < players.size; i++ )
2190  {
2191  if( !‪is_target_valid( players[i] ) )
2192  {
2193  continue;
2194  }
2195 
2196  min_distance_sq = min_distance * min_distance;
2197 
2198  distance_sq = DistanceSquared( self.origin, players[i].origin + (0, 0, 48) );
2199 
2200  if(distance_sq < min_distance_sq)
2201  {
2202  players[i] ‪sentinel_DamagePlayer( 60, self);
2203  }
2204  }
2205 
2207  self ‪sentinel_ElectrifyZombie( self.origin, undefined, 100);
2208 
2209  //make sure the client gets a chance to play the second fx before deleting
2210  wait 0.1;
2211 
2212  self Delete();
2213 }
2214 
2215 function ‪sentinel_DeleteDroneDeathFX( explosion_origin )
2216 {
2217  self endon("disconnect");
2218  self endon( "death" );
2219 
2220  self.origin = explosion_origin;
2221 
2222  wait 0.1;
2223 
2224  self ‪clientfield::set( "sentinel_drone_deathfx", 1 );
2225 
2226  wait 6;
2227 
2228  self Delete();
2229 }
2230 
2231 // ----------------------------------------------
2232 // State: Utility
2233 // ----------------------------------------------
2234 
2235 function ‪sentinel_ForceGoAndStayInPosition( b_enable, position)
2236 {
2237  if( ‪IS_TRUE(b_enable) )
2238  {
2239  self.forced_pos = position;
2240  }
2241  else
2242  {
2243  self.shouldRoll = false;
2244  self.forced_pos = undefined;
2245  }
2246 }
2247 
2249 {
2250  if(!isdefined(self.v_compact_mode))
2251  {
2252  v_compact_mode = GetEnt( "sentinel_compact", "targetname" );
2253  }
2254 
2255  if(isdefined(v_compact_mode))
2256  {
2257  if ( self.sentinel_droneEnemy IsTouching( v_compact_mode ) )
2258  {
2259  return true;
2260  }
2261  }
2262 
2263  return false;
2264 }
2265 
2267 {
2268  if(!isdefined(self.sentinel_droneEnemy))
2269  {
2270  return false;
2271  }
2272 
2273  if(!isdefined(self.v_narrow_volume))
2274  {
2275  self.v_narrow_volume = GetEnt( "sentinel_narrow_nav", "targetname" );
2276  }
2277 
2278  if(isdefined(self.v_narrow_volume) && isdefined(self.sentinel_droneEnemy) )
2279  {
2280  if ( self.sentinel_droneEnemy IsTouching( self.v_narrow_volume ) )
2281  {
2282  return true;
2283  }
2284  }
2285 
2286  return false;
2287 }
2288 
2289 
2290 function ‪sentinel_SetCompactMode(b_compact)
2291 {
2292  if( ‪IS_TRUE(b_compact) )
2293  {
2294  self.in_compact_mode = true;
2296  }
2297  else
2298  {
2299  self.in_compact_mode = false;
2301  }
2302 }
2303 
2305 {
2306  self endon("disconnect");
2307  self endon( "death" );
2308 
2309  wait 0.2;
2310 
2311  self HidePart( ‪SENTINEL_DRONE_ARM_LEFT_BROKEN_TAG, "", true );
2312  self HidePart( ‪SENTINEL_DRONE_ARM_RIGHT_BROKEN_TAG, "", true );
2313  self HidePart( ‪SENTINEL_DRONE_ARM_TOP_BROKEN_TAG, "", true );
2314  self HidePart( ‪SENTINEL_DRONE_CAMERA_BROKEN_TAG, "", true );
2315  self HidePart( ‪SENTINEL_DRONE_CORE_RED_TAG, "", true );
2316 }
2317 
2319 {
2320  self DoDamage( self.health + 100, self.origin );
2321 }
2322 
2323 
2325 {
2327  {
2328  return self.settings.engagementDistMax * 0.3;
2329  }
2330  else if(‪IS_TRUE(self.in_compact_mode))
2331  {
2332  return self.settings.engagementDistMax * 0.85;
2333  }
2334 
2335  return self.settings.engagementDistMax;
2336 }
2337 
2339 {
2341  {
2342  return self.settings.engagementDistMin * 0.2;
2343  }
2344  else if(‪IS_TRUE(self.in_compact_mode))
2345  {
2346  return self.settings.engagementDistMin * 0.5;
2347  }
2348 
2349  return self.settings.engagementDistMin;
2350 }
2351 
2353 {
2354  if(‪IS_TRUE(self.in_compact_mode))
2355  {
2356  return self.settings.engagementHeightMax * 0.8;
2357  }
2358 
2359  return self.settings.engagementHeightMax;
2360 }
2361 
2363 {
2364  if(!isdefined(self.sentinel_droneEnemy))
2365  {
2366  return self.settings.engagementHeightMin * 3;
2367  }
2368 
2369  return self.settings.engagementHeightMin;
2370 }
2371 
2372 function ‪sentinel_IsInsideEngagementDistance( origin, position, b_accept_negative_height )
2373 {
2374  if( ! (Distance2DSquared( position, origin ) > ‪SQR( ‪sentinel_GetEngagementDistMin()) &&
2375  Distance2DSquared( position, origin ) < ‪SQR( ‪sentinel_GetEngagementDistMax())) )
2376  {
2377  return false;
2378  }
2379 
2380  if( ‪IS_TRUE(b_accept_negative_height) )
2381  {
2382  return (abs(origin[2] - position[2]) >= ‪sentinel_GetEngagementHeightMin()) && (abs(origin[2] - position[2]) <= ‪sentinel_GetEngagementHeightMax());
2383  }
2384  else
2385  {
2386  return ((position[2] - origin[2]) >= ‪sentinel_GetEngagementHeightMin()) && (( position[2] - origin[2]) <= ‪sentinel_GetEngagementHeightMax() );
2387  }
2388 }
2389 
2390 function ‪sentinel_Trace(start, ‪end, ignore_ent, b_physics_trace, ignore_characters)
2391 {
2392  if(‪IS_TRUE(b_physics_trace))
2393  {
2394  ‪trace = PhysicsTrace( start, ‪end, ( -10, -10, -10 ), ( 10, 10, 10 ), self, ‪PHYSICS_TRACE_MASK_PHYSICS | ‪PHYSICS_TRACE_MASK_VEHICLE );
2395 
2396  if(‪trace[ "fraction" ] < 1)
2397  {
2398  return ‪trace;
2399  }
2400  }
2401 
2402  ‪trace = BulletTrace( start, ‪end, !‪IS_TRUE(ignore_characters), self, false, false, self, true );
2403 
2404  return ‪trace;
2405 }
2406 
2407 function ‪sentinel_ElectrifyZombie( origin, zombie, radius )
2408 {
2409  self endon( "disconnect" );
2410  self endon( "death" );
2411 
2412  if(isdefined(self.‪sentinel_ElectrifyZombie))
2413  {
2414  self thread [[self.sentinel_ElectrifyZombie]]( origin, zombie, radius );
2415  }
2416 }
2417 
2419 {
2420  for(i = 1; i <= 3; i++)
2421  {
2422  self ‪clientfield::set("sentinel_drone_arm_cut_" + i, 0);
2423  }
2424 }
2425 
2426 function ‪sentinel_DamagePlayer( ‪damage, eAttacker, b_light_damage = false ) // self = player in radius
2427 {
2428  self notify( "proximityGrenadeDamageStart" );
2429  self endon( "proximityGrenadeDamageStart" );
2430  self endon( "disconnect" );
2431  self endon( "death" );
2432  eAttacker endon( "disconnect" );
2433 
2434  self DoDamage( ‪damage, eAttacker.origin, eAttacker, eAttacker );
2435 
2436  if(b_light_damage)
2437  {
2438  self playrumbleonentity("damage_heavy");
2439  }
2440  else
2441  {
2442  self playrumbleonentity("proximity_grenade");
2443  }
2444 
2445  if ( self ‪util::mayApplyScreenEffect() )
2446  {
2447  self ‪clientfield::increment_to_player("sentinel_drone_damage_player_fx");
2448 
2449  if(b_light_damage)
2450  {
2451  self shellshock( "electrocution_sentinel_drone", 0.5 );
2452  }
2453  else
2454  {
2455  self shellshock( "electrocution_sentinel_drone", 1 );
2456  }
2457  }
2458 
2459 
2460 }
2461 
2463 {
2464  if(!isdefined(level.a_sentinel_drones))
2465  {
2466  return;
2467  }
2468 
2469  for(i = 0; i < level.a_sentinel_drones.size; i++)
2470  {
2471  if( level.a_sentinel_drones[i] == self)
2472  {
2473  level.a_sentinel_drones[i] = undefined;
2474  break;
2475  }
2476  }
2477 
2478  level.a_sentinel_drones = ‪array::remove_undefined( level.a_sentinel_drones );
2479 }
2480 
2481 function ‪sentinel_IsNearAnotherSentinel( point, min_distance )
2482 {
2483  if(!isdefined(level.a_sentinel_drones))
2484  {
2485  return false;
2486  }
2487 
2488  for(i = 0; i < level.a_sentinel_drones.size; i++)
2489  {
2490  if(!isdefined(level.a_sentinel_drones[i]))
2491  {
2492  continue;
2493  }
2494 
2495  if(level.a_sentinel_drones[i] == self)
2496  continue;
2497 
2498  min_distance_sq = min_distance * min_distance;
2499 
2500  distance_sq = DistanceSquared( level.a_sentinel_drones[i].origin, point );
2501 
2502  if(distance_sq < min_distance_sq)
2503  {
2504  return true;
2505  }
2506  }
2507 
2508  return false;
2509 }
2510 
2511 function ‪sentinel_IsNearAnotherPlayer( origin, min_distance )
2512 {
2513  players = GetPlayers();
2514 
2515  for( i = 0; i < players.size; i++ )
2516  {
2517  if( !‪is_target_valid( players[i] ) )
2518  {
2519  continue;
2520  }
2521 
2522 
2523  min_distance_sq = min_distance * min_distance;
2524 
2525  distance_sq = DistanceSquared( origin, players[i].origin + (0, 0, 48) );
2526 
2527  if(distance_sq < min_distance_sq)
2528  {
2529  return true;
2530  }
2531  }
2532 
2533  return false;
2534 }
2535 
2536 function ‪sentinel_play_taunt( taunt_Arr )
2537 {
2538  if( isdefined(level._lastplayed_drone_taunt) && (GetTime() - level._lastplayed_drone_taunt) < 6000 )
2539  {
2540  return;
2541  }
2542 
2543  taunt = RandomInt(taunt_Arr.size);
2544 
2545  level._lastplayed_drone_taunt = GetTime();
2546  self PlaySound( taunt_Arr[taunt] );
2547 }
2548 
2549 // ----------------------------------------------
2550 // DEBUG
2551 // ----------------------------------------------
2552 
2553 /#
2555 {
2556  self endon("death");
2557 
2558  while(true)
2559  {
2560  radius = GetDvarInt("drone_radius2", 35);
2561  Sphere(self.origin, radius, ‪GREEN, 0.5);
2562 
2563  wait 0.01;
2564  }
2565 }
2566 
2567 
2569 {
2570  self endon("death");
2571 
2572  while(true)
2573  {
2574  if(GetDvarInt("sentinel_DebugFX_PlayAll", 0) == 1)
2575  {
2576  self.sentinel_DebugFX_PlayAll = true;
2577 
2578  forward_vector = AnglesToForward(self.angles);
2579  forward_vector = self.origin + VectorScale(forward_vector, ‪SENTINEL_DRONE_BEAM_MAX_LENGTH);
2580  thread ‪sentinel_FireBeam( forward_vector );
2581 
2582  self ‪clientfield::set("sentinel_drone_beam_charge", 1);
2583  }
2584  else if(‪IS_TRUE(self.sentinel_DebugFX_PlayAll))
2585  {
2586  self.sentinel_DebugFX_PlayAll = false;
2587 
2588  self ‪clientfield::set("sentinel_drone_beam_charge", 0);
2589  }
2590 
2591  if(GetDvarInt("sentinel_DebugFX_BeamCharge", 0) == 1)
2592  {
2593  self.sentinel_DebugFX_BeamCharge = true;
2594  }
2595  else if(‪IS_TRUE(self.sentinel_DebugFX_BeamCharge))
2596  {
2597  self.sentinel_DebugFX_BeamCharge = false;
2598 
2599  self ‪clientfield::set("sentinel_drone_beam_charge", 0);
2600  }
2601 
2602  if(GetDvarInt("sentinel_DebugFX_NoArms", 0) == 1)
2603  {
2604  if( !‪IS_TRUE(self.sentinel_DebugFX_NoArms) )
2605  {
2606  self.sentinel_DebugFX_NoArms = true;
2607 
2611  }
2612  }
2613 
2614  if(GetDvarInt("sentinel_DebugFX_NoFace", 0) == 1)
2615  {
2616  if( !‪IS_TRUE(self.sentinel_DebugFX_NoFace) )
2617  {
2618  self.sentinel_DebugFX_NoFace = true;
2620  }
2621  }
2622 
2623  wait 3;
2624  }
2625 }
2626 
2628 {
2629  self endon( "death" );
2630 
2631  while(isdefined(self))
2632  {
2633  if(GetDvarInt("sentinel_debug_buff_zombies", 0) == 1)
2634  {
2635  self.debug_should_buff_zombies = true;
2636  self.should_buff_zombies = true;
2637  }
2638  else if( isdefined(self.debug_should_buff_zombies) )
2639  {
2640  self.debug_should_buff_zombies = undefined;
2641  self.should_buff_zombies = false;
2642  }
2643 
2644  if(GetDvarInt("sentinel_debug_compact", 0) == 1)
2645  {
2646  self.debug_sentinel_debug_compact = true;
2648  }
2649  else if( isdefined(self.debug_sentinel_debug_compact) )
2650  {
2651  self.debug_sentinel_debug_compact = undefined;
2653  }
2654 
2655  wait 1;
2656  }
2657 }
2658 
2659 #/
‪call_custom_add_state_callbacks
‪function call_custom_add_state_callbacks()
Definition: vehicle_ai_shared.gsc:1152
‪sentinel_SetCompactMode
‪function sentinel_SetCompactMode(b_compact)
Definition: _sentinel_drone.gsc:2290
‪IsCamera
‪function IsCamera(part_name)
Definition: _sentinel_drone.gsc:1847
‪SENTINEL_DRONE_DEFAULT_HEALTH_ARM_TOP
‪#define SENTINEL_DRONE_DEFAULT_HEALTH_ARM_TOP
Definition: _sentinel_drone.gsh:59
‪sentinel_IsInsideEngagementDistance
‪function sentinel_IsInsideEngagementDistance(origin, position, b_accept_negative_height)
Definition: _sentinel_drone.gsc:2372
‪SENTINEL_DRONE_BEAM_DAMAGE_PER_SECOND
‪#define SENTINEL_DRONE_BEAM_DAMAGE_PER_SECOND
Definition: _sentinel_drone.gsh:24
‪SENTINEL_DRONE_ARM_TOP
‪#define SENTINEL_DRONE_ARM_TOP
Definition: _sentinel_drone.gsh:32
‪SENTINEL_DRONE_CAMERA_BROKEN_TAG
‪#define SENTINEL_DRONE_CAMERA_BROKEN_TAG
Definition: _sentinel_drone.gsh:34
‪sentinel_ShouldChangeSentinelPosition
‪function private sentinel_ShouldChangeSentinelPosition()
Definition: _sentinel_drone.gsc:723
‪sentinel_IntroCompleted
‪function sentinel_IntroCompleted()
Definition: _sentinel_drone.gsc:542
‪IsLeftArm
‪function IsLeftArm(part_name)
Definition: _sentinel_drone.gsc:1799
‪SENTINEL_DRONE_RADIUS
‪#define SENTINEL_DRONE_RADIUS
Definition: _sentinel_drone.gsh:1
‪SENTINEL_DRONE_ARM_RIGHT
‪#define SENTINEL_DRONE_ARM_RIGHT
Definition: _sentinel_drone.gsh:30
‪sentinel_drone_initialize
‪function sentinel_drone_initialize()
Definition: _sentinel_drone.gsc:80
‪nudge_collision
‪function nudge_collision()
Definition: vehicle_ai_shared.gsc:437
‪sentinel_DestroyCore
‪function private sentinel_DestroyCore()
Definition: _sentinel_drone.gsc:1980
‪VERSION_SHIP
‪#define VERSION_SHIP
Definition: version.gsh:36
‪sentinel_IsNearAnotherPlayer
‪function sentinel_IsNearAnotherPlayer(origin, min_distance)
Definition: _sentinel_drone.gsc:2511
‪cointoss
‪function cointoss()
Definition: math_shared.csc:171
‪SENTINEL_DRONE_DEFAULT_HEALTH_ARM_RIGHT
‪#define SENTINEL_DRONE_DEFAULT_HEALTH_ARM_RIGHT
Definition: _sentinel_drone.gsh:58
‪SENTINEL_DRONE_CORE_RED_TAG
‪#define SENTINEL_DRONE_CORE_RED_TAG
Definition: _sentinel_drone.gsh:55
‪sentinel_DodgeRoll
‪function sentinel_DodgeRoll()
Definition: _sentinel_drone.gsc:553
‪sentinel_NavigateTheWorld
‪function sentinel_NavigateTheWorld()
Definition: _sentinel_drone.gsc:757
‪sentinel_ChargeAtPlayerNavigation
‪function sentinel_ChargeAtPlayerNavigation(b_charge_at_player, time_out, charge_at_position)
Definition: _sentinel_drone.gsc:1206
‪trace
‪function trace(from, to, target)
Definition: grapple.gsc:369
‪IsCore
‪function IsCore(part_name)
Definition: _sentinel_drone.gsc:1829
‪sentinel_DestroyAllArms
‪function sentinel_DestroyAllArms(b_disable_charge)
Definition: _sentinel_drone.gsc:1957
‪VERSION_DLC3
‪#define VERSION_DLC3
Definition: version.gsh:95
‪SetBlackBoardAttribute
‪function SetBlackBoardAttribute(entity, attributeName, attributeValue)
Definition: blackboard.gsc:56
‪sentinel_GetEngagementHeightMax
‪function sentinel_GetEngagementHeightMax()
Definition: _sentinel_drone.gsc:2352
‪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
‪SENTINEL_DRONE_MAX_INSTANCES
‪#define SENTINEL_DRONE_MAX_INSTANCES
Definition: _sentinel_drone.gsh:22
‪sentinel_ForceGoAndStayInPosition
‪function sentinel_ForceGoAndStayInPosition(b_enable, position)
Definition: _sentinel_drone.gsc:2235
‪SQR
‪#define SQR(__var)
Definition: shared.gsh:293
‪GREEN
‪#define GREEN
Definition: shared.gsh:176
‪sentinel_drone_target_selection
‪function private sentinel_drone_target_selection()
Definition: _sentinel_drone.gsc:428
‪player_damage
‪function player_damage()
Definition: _zm_trap_electric.gsc:108
‪SENTINEL_DRONE_CORE_TAG_3
‪#define SENTINEL_DRONE_CORE_TAG_3
Definition: _sentinel_drone.gsh:52
‪add
‪function add(entity, dyingplayer, team, timeout)
Definition: _deathicons.gsc:43
‪spawn_model
‪function spawn_model(n_client, str_model, origin=(0, 0, 0), angles=(0, 0, 0))
Definition: util_shared.csc:92
‪is_instate
‪function is_instate(statename)
Definition: vehicle_ai_shared.gsc:994
‪RED
‪#define RED
Definition: shared.gsh:175
‪SENTINEL_DRONE_CORE_TAG_2
‪#define SENTINEL_DRONE_CORE_TAG_2
Definition: _sentinel_drone.gsh:51
‪SENTINEL_DRONE_BEAM_MAX_LENGTH
‪#define SENTINEL_DRONE_BEAM_MAX_LENGTH
Definition: _sentinel_drone.gsh:26
‪sentine_RumbleWhenNearPlayer
‪function sentine_RumbleWhenNearPlayer()
Definition: _sentinel_drone.gsc:1313
‪STANCE
‪#define STANCE
Definition: blackboard.gsh:36
‪get_sentinel_drone_enemy
‪function get_sentinel_drone_enemy()
Definition: _sentinel_drone.gsc:329
‪damage
‪function damage(trap)
Definition: _zm_trap_electric.gsc:116
‪STANCE_STAND
‪#define STANCE_STAND
Definition: blackboard.gsh:273
‪__init__
‪function __init__()
Definition: _sentinel_drone.gsc:34
‪sentinel_InitBeamLaunchers
‪function sentinel_InitBeamLaunchers()
Definition: _sentinel_drone.gsc:227
‪sentinel_CallbackDamage
‪function sentinel_CallbackDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal)
Definition: _sentinel_drone.gsc:2082
‪StartInitialState
‪function StartInitialState(defaultState="combat")
Definition: vehicle_ai_shared.gsc:866
‪set_sentinel_drone_enemy
‪function set_sentinel_drone_enemy(enemy)
Definition: _sentinel_drone.gsc:381
‪is_target_valid
‪function private is_target_valid(target)
Definition: _sentinel_drone.gsc:262
‪sentinel_IsEnemyInNarrowPlace
‪function sentinel_IsEnemyInNarrowPlace()
Definition: _sentinel_drone.gsc:2266
‪sentinel_DebugDrawSize
‪function sentinel_DebugDrawSize()
Definition: _sentinel_drone.gsc:2554
‪time_out
‪function time_out(victim)
Definition: _dogtags.gsc:301
‪sentinel_DeleteDroneDeathFX
‪function sentinel_DeleteDroneDeathFX(explosion_origin)
Definition: _sentinel_drone.gsc:2215
‪SENTINEL_DRONE_ARM_LEFT_TAG
‪#define SENTINEL_DRONE_ARM_LEFT_TAG
Definition: _sentinel_drone.gsh:37
‪sentinel_NavigationStandStill
‪function sentinel_NavigationStandStill()
Definition: _sentinel_drone.gsc:664
‪sentinel_KillMyself
‪function sentinel_KillMyself()
Definition: _sentinel_drone.gsc:2318
‪friendly_fire_shield
‪function friendly_fire_shield()
Definition: vehicle_shared.gsc:2194
‪sentinel_SelfDestruct
‪function sentinel_SelfDestruct(time)
Definition: _sentinel_drone.gsc:1721
‪sentinel_HideInitialBrokenParts
‪function sentinel_HideInitialBrokenParts()
Definition: _sentinel_drone.gsc:2304
‪sentinel_Intro
‪function sentinel_Intro()
Definition: _sentinel_drone.gsc:535
‪sentinel_IsNearAnotherSentinel
‪function sentinel_IsNearAnotherSentinel(point, min_distance)
Definition: _sentinel_drone.gsc:2481
‪SENTINEL_DRONE_ARM_TOP_TAG
‪#define SENTINEL_DRONE_ARM_TOP_TAG
Definition: _sentinel_drone.gsh:39
‪SENTINEL_DRONE_ARM_RIGHT_TAG
‪#define SENTINEL_DRONE_ARM_RIGHT_TAG
Definition: _sentinel_drone.gsh:38
‪SENTINEL_DRONE_DEFAULT_HEALTH_FACE
‪#define SENTINEL_DRONE_DEFAULT_HEALTH_FACE
Definition: _sentinel_drone.gsh:60
‪sentinel_FireLogic
‪function sentinel_FireLogic()
Definition: _sentinel_drone.gsc:1428
‪end
‪function end(final)
Definition: _killcam.gsc:511
‪SENTINEL_DRONE_ARM_RIGHT_BROKEN_TAG
‪#define SENTINEL_DRONE_ARM_RIGHT_BROKEN_TAG
Definition: _sentinel_drone.gsh:42
‪get_sentinel_nearest_zombie
‪function get_sentinel_nearest_zombie(b_ignore_elemental=true, b_outside_playable_area=true, radius=2000)
Definition: _sentinel_drone.gsc:318
‪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
‪SENTINEL_DRONE_NEARGOAL_DIST
‪#define SENTINEL_DRONE_NEARGOAL_DIST
Definition: _sentinel_drone.gsh:20
‪sentinel_drone_CallbackRadiusDamage
‪function sentinel_drone_CallbackRadiusDamage(eInflictor, eAttacker, iDamage, fInnerDamage, fOuterDamage, iDFlags, sMeansOfDeath, weapon, vPoint, fRadius, fConeAngleCos, vConeDir, psOffsetTime)
Definition: _sentinel_drone.gsc:2129
‪waittill_pathing_done
‪function waittill_pathing_done(maxtime=15)
Definition: vehicle_ai_shared.gsc:340
‪sentinel_IsEnemyIndoors
‪function sentinel_IsEnemyIndoors()
Definition: _sentinel_drone.gsc:2248
‪PositionQuery_DebugScores
‪function PositionQuery_DebugScores(queryResult)
Definition: vehicle_ai_shared.gsc:2010
‪increment_to_player
‪function increment_to_player(str_field_name, n_increment_count=1)
Definition: clientfield_shared.gsc:169
‪SENTINEL_DRONE_DEFAULT_HEALTH_CORE
‪#define SENTINEL_DRONE_DEFAULT_HEALTH_CORE
Definition: _sentinel_drone.gsh:62
‪SENTINEL_DRONE_CAMERA_TURRET_TAG
‪#define SENTINEL_DRONE_CAMERA_TURRET_TAG
Definition: _sentinel_drone.gsh:35
‪IsRightArm
‪function IsRightArm(part_name)
Definition: _sentinel_drone.gsc:1809
‪ARRAY_ADD
‪#define ARRAY_ADD(__array, __item)
Definition: shared.gsh:304
‪sentinel_FireBeamBurst
‪function sentinel_FireBeamBurst(target_position)
Definition: _sentinel_drone.gsc:1616
‪sentinel_DeactivateAllEffects
‪function sentinel_DeactivateAllEffects()
Definition: _sentinel_drone.gsc:2418
‪PositionQuery_Filter_OutOfGoalAnchor
‪function PositionQuery_Filter_OutOfGoalAnchor(queryResult, tolerance=1)
Definition: vehicle_ai_shared.gsc:2104
‪remove_undefined
‪function remove_undefined(array, b_keep_keys)
Definition: array_shared.csc:56
‪sentinel_FireBeamSuccession
‪function sentinel_FireBeamSuccession(target_position)
Definition: _sentinel_drone.gsc:1664
‪PHYSICS_TRACE_MASK_PHYSICS
‪#define PHYSICS_TRACE_MASK_PHYSICS
Definition: shared.gsh:130
‪sentinel_ElectrifyZombie
‪function sentinel_ElectrifyZombie(origin, zombie, radius)
Definition: _sentinel_drone.gsc:2407
‪sentinel_ArmDamage
‪function private sentinel_ArmDamage(damage, arm, eAttacker=undefined)
Definition: _sentinel_drone.gsc:1888
‪REGISTER_SYSTEM
‪#define REGISTER_SYSTEM(__sys, __func_init_preload, __reqs)
Definition: shared.gsh:204
‪sentinel_GetNextMovePositionTactical
‪function sentinel_GetNextMovePositionTactical(b_do_not_chase_enemy)
Definition: _sentinel_drone.gsc:990
‪PHYSICS_TRACE_MASK_VEHICLE
‪#define PHYSICS_TRACE_MASK_VEHICLE
Definition: shared.gsh:131
‪BLUE
‪#define BLUE
Definition: shared.gsh:177
‪sentinel_changeSentinelPosition
‪function private sentinel_changeSentinelPosition()
Definition: _sentinel_drone.gsc:752
‪SENTINEL_DRONE_FIRE_CHANCE
‪#define SENTINEL_DRONE_FIRE_CHANCE
Definition: _sentinel_drone.gsh:17
‪IsTopArm
‪function IsTopArm(part_name)
Definition: _sentinel_drone.gsc:1819
‪sentinel_ChargeAtPlayer
‪function sentinel_ChargeAtPlayer()
Definition: _sentinel_drone.gsc:1735
‪waittill_asm_complete
‪function waittill_asm_complete(substate_to_wait, timeout=10)
Definition: vehicle_ai_shared.gsc:374
‪sentinel_GetEngagementHeightMin
‪function sentinel_GetEngagementHeightMin()
Definition: _sentinel_drone.gsc:2362
‪ARCHETYPE_ZOMBIE
‪#define ARCHETYPE_ZOMBIE
Definition: archetype_shared.gsh:10
‪PositionQuery_Filter_EngagementDist
‪function PositionQuery_Filter_EngagementDist(queryResult, enemy, engagementDistanceMin, engagementDistanceMax)
Definition: vehicle_ai_shared.gsc:2116
‪sentinel_CoreDamage
‪function private sentinel_CoreDamage(damage, partName)
Definition: _sentinel_drone.gsc:2012
‪SENTINEL_DRONE_ARM_LEFT
‪#define SENTINEL_DRONE_ARM_LEFT
Definition: _sentinel_drone.gsh:31
‪SENTINEL_DRONE_DEFAULT_HEALTH_CAMERA
‪#define SENTINEL_DRONE_DEFAULT_HEALTH_CAMERA
Definition: _sentinel_drone.gsh:61
‪RegisterVehicleBlackBoardAttributes
‪function RegisterVehicleBlackBoardAttributes()
Definition: blackboard_vehicle.gsc:24
‪set
‪function set(str_field_name, n_value)
Definition: clientfield_shared.gsc:34
‪state_death_update
‪function state_death_update(params)
Definition: _sentinel_drone.gsc:2162
‪sentinel_PathUpdateInterrupt
‪function sentinel_PathUpdateInterrupt()
Definition: _sentinel_drone.gsc:1272
‪sentinel_CameraDamage
‪function private sentinel_CameraDamage(damage, partName, eAttacker)
Definition: _sentinel_drone.gsc:2043
‪sentinel_FaceDamage
‪function private sentinel_FaceDamage(damage, partName)
Definition: _sentinel_drone.gsc:1985
‪SENTINEL_CHARGE_AT_PLAYER_TIME_OUT
‪#define SENTINEL_CHARGE_AT_PLAYER_TIME_OUT
Definition: _sentinel_drone.gsh:28
‪CreateBlackBoardForEntity
‪function CreateBlackBoardForEntity(entity)
Definition: blackboard.gsc:77
‪SENTINEL_DRONE_FACE_TAG
‪#define SENTINEL_DRONE_FACE_TAG
Definition: _sentinel_drone.gsh:49
‪sentinel_GetEngagementDistMin
‪function sentinel_GetEngagementDistMin()
Definition: _sentinel_drone.gsc:2338
‪SENTINEL_DRONE_CORE_TAG
‪#define SENTINEL_DRONE_CORE_TAG
Definition: _sentinel_drone.gsh:50
‪SENTINEL_DRONE_CORE_BLUE_TAG
‪#define SENTINEL_DRONE_CORE_BLUE_TAG
Definition: _sentinel_drone.gsh:54
‪sentinel_CanSeeEnemy
‪function sentinel_CanSeeEnemy(sentinel_origin, prev_enemy_position)
Definition: _sentinel_drone.gsc:1332
‪sentinel_DamageBeamTouchingEntity
‪function sentinel_DamageBeamTouchingEntity(player_damage, target_position, b_succession=false)
Definition: _sentinel_drone.gsc:1703
‪sentinel_OnAllArmsDestroyed
‪function private sentinel_OnAllArmsDestroyed()
Definition: _sentinel_drone.gsc:1966
‪register
‪function register()
Definition: _ai_tank.gsc:126
‪sentinel_GetArmNumber
‪function sentinel_GetArmNumber(part_name)
Definition: _sentinel_drone.gsc:1865
‪state_combat_update
‪function state_combat_update(params)
Definition: _sentinel_drone.gsc:473
‪get_script_bundle
‪function get_script_bundle(str_type, str_name)
Definition: struct.csc:45
‪defaultRole
‪function defaultRole()
Definition: _sentinel_drone.gsc:247
‪sentinel_DebugBehavior
‪function sentinel_DebugBehavior()
Definition: _sentinel_drone.gsc:2627
‪STANCE_CROUCH
‪#define STANCE_CROUCH
Definition: blackboard.gsh:274
‪sentinel_Trace
‪function sentinel_Trace(start, end, ignore_ent, b_physics_trace, ignore_characters)
Definition: _sentinel_drone.gsc:2390
‪sentinel_GetEngagementDistMax
‪function sentinel_GetEngagementDistMax()
Definition: _sentinel_drone.gsc:2324
‪move
‪function move(owner, count, fire_time, main_dir, max_offset_angle)
Definition: _decoy.gsc:65
‪result
‪function result(death, attacker, mod, weapon)
Definition: _zm_aat_blast_furnace.gsc:46
‪sentinel_DamagePlayer
‪function sentinel_DamagePlayer(damage, eAttacker, b_light_damage=false)
Definition: _sentinel_drone.gsc:2426
‪ORANGE
‪#define ORANGE
Definition: shared.gsh:179
‪SENTINEL_DRONE_ARM_LEFT_BROKEN_TAG
‪#define SENTINEL_DRONE_ARM_LEFT_BROKEN_TAG
Definition: _sentinel_drone.gsh:41
‪mayApplyScreenEffect
‪function mayApplyScreenEffect()
Definition: util_shared.gsc:2613
‪name
‪class GroundFx name
‪sentinel_play_taunt
‪function sentinel_play_taunt(taunt_Arr)
Definition: _sentinel_drone.gsc:2536
‪CreateInterfaceForEntity
‪function CreateInterfaceForEntity(entity)
Definition: ai_interface.gsc:110
‪sentinel_DebugFX
‪function sentinel_DebugFX()
Definition: _sentinel_drone.gsc:2568
‪sentinel_RemoveFromLevelArray
‪function sentinel_RemoveFromLevelArray()
Definition: _sentinel_drone.gsc:2462
‪sentinel_FireBeam
‪function sentinel_FireBeam(target_position, b_succession)
Definition: _sentinel_drone.gsc:1570
‪get_state_callbacks
‪function get_state_callbacks(statename)
Definition: vehicle_ai_shared.gsc:927
‪WHITE
‪#define WHITE
Definition: shared.gsh:183
‪SENTINEL_DRONE_ARM_TOP_BROKEN_TAG
‪#define SENTINEL_DRONE_ARM_TOP_BROKEN_TAG
Definition: _sentinel_drone.gsh:43
‪SENTINEL_DRONE_DEFAULT_HEALTH_ARM_LEFT
‪#define SENTINEL_DRONE_DEFAULT_HEALTH_ARM_LEFT
Definition: _sentinel_drone.gsh:57
‪sentinel_DestroyFace
‪function private sentinel_DestroyFace()
Definition: _sentinel_drone.gsc:1975
‪ARCHETYPE_SENTINEL_DRONE
‪#define ARCHETYPE_SENTINEL_DRONE
Definition: archetype_shared.gsh:40