Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
SCR_AICombatComponent.c
Go to the documentation of this file.
1 [ComponentEditorProps(category: "GameScripted/AI", description: "Component for utility AI system calculations")]
2 class SCR_AICombatComponentClass : ScriptComponentClass
3 {
4 }
5 
6 enum EAISkill
7 {
8  NONE,
9  ROOKIE = 20,
10  REGULAR = 50,
11  VETERAN = 70,
12  EXPERT = 80,
13  CYLON = 100
14 }
15 
16 // be aware it is used for bitmask
17 enum EAICombatActions
18 {
19  HOLD_FIRE = 1, // No longer/not yet used
20  BURST_FIRE = 2, // No longer used
21  SUPPRESSIVE_FIRE = 4,
22  MOVEMENT_WHEN_FIRE = 8,
23  MOVEMENT_TO_LAST_SEEN = 16,
24 }
25 
26 enum EAICombatType
27 {
28  NONE,
29  NORMAL,
30  SUPPRESSIVE,
31  RETREAT,
32  SINGLE_SHOT
33 }
34 
35 class SCR_AICombatComponent : ScriptComponent
36 {
37  // Constants
38  static const int TARGET_ENDANGERED_TIMEOUT_S = 10;
39  static const float ENDANGERING_TARGET_SCORE_MULTIPLIER = 1.05;
40 
41  // Score increments for assigned targets and endangering targets
42  protected static const float ASSIGNED_TARGETS_SCORE_INCREMENT = 30.0;
43  protected static const float ENDANGERING_TARGETS_SCORE_INCREMENT = 15.0;
44 
45  // Constants related to weapon&target selector
46  static const float TARGET_MAX_LAST_SEEN_VISIBLE = 0.5;
47  protected static const float TARGET_MAX_LAST_SEEN_DIRECT_ATTACK = 1.6;
48  static const float TARGET_MAX_LAST_SEEN_INDIRECT_ATTACK = 6.0;
49  static const float TARGET_MAX_LAST_SEEN_INDIRECT_ATTACK_MG = 11.0;
50  static const float TARGET_MAX_LAST_SEEN = 45.0;
51  protected static const float TARGET_MIN_INDIRECT_TRACE_FRACTION_MIN = 0.5;
52  protected static const float TARGET_MAX_DISTANCE_INFANTRY = 500.0;
53  protected static const float TARGET_MAX_DISTANCE_VEHICLE = 700.0;
54  protected static const float TARGET_MAX_DISTANCE_DISARMED = 0.0;
55  protected static const float TARGET_MAX_TIME_SINCE_ENDANGERED = 5.0;
56  protected static const float TARGET_SCORE_RETREAT = 75.0;
57  static const float TARGET_SCORE_HIGH_PRIORITY_ATTACK = 98.5;
58 
59  protected static ref array<EWeaponType> s_aWeaponBlacklistFragGrenades = {EWeaponType.WT_FRAGGRENADE};
60 
61  // Perception factors
62  protected const float PERCEPTION_FACTOR_SAFE = 1.0;
63  protected const float PERCEPTION_FACTOR_VIGILANT = 2.5;
64  protected const float PERCEPTION_FACTOR_ALERTED = 2.5;
65  protected const float PERCEPTION_FACTOR_THREATENED = 0.4; // We are suppressed and are bad at recognizing enemies
66 
67  protected const float PERCEPTION_FACTOR_EQUIPMENT_BINOCULARS = 3.0;
68  protected const float PERCEPTION_FACTOR_EQUIPMENT_NONE = 1.0;
69 
71  static const float LONG_RANGE_FIRE_DISTANCE = 200.0;
72 
73  protected SCR_ChimeraAIAgent m_Agent;
75  protected SCR_InventoryStorageManagerComponent m_InventoryManager;
76  protected BaseWeaponManagerComponent m_WpnManager;
77  protected SCR_CompartmentAccessComponent m_CompartmentAccess;
78  protected SCR_DamageManagerComponent m_DamageManager;
79  protected PerceptionComponent m_Perception;
80  protected SCR_AIInfoComponent m_AIInfo;
81  protected SCR_AIUtilityComponent m_Utility;
82 
83  // Cached data about current vehicle and compartment
84  protected IEntity m_CurrentVehicle;
85  protected bool m_bCurrentVehicleEvac;
86  protected SCR_BaseCompartmentManagerComponent m_CurrentVehicleCompartmentManager;
87  protected BaseCompartmentSlot m_CurrentCompartmentSlot;
88  protected TurretControllerComponent m_CurrentTurretController;
89 
90  protected EAICombatActions m_iAllowedActions;
91  protected EAICombatType m_eCombatType = EAICombatType.NORMAL;
92  protected EAICombatType m_eDefaultCombatType = EAICombatType.NORMAL;
93 
94  [Attribute("50", UIWidgets.ComboBox, "AI skill in combat", "", ParamEnumArray.FromEnum(EAISkill) )]
95  protected EAISkill m_eAISkillDefault;
96 
97  protected EAISkill m_eAISkill;
98 
99  // Belongs to friendly in aim check
100  protected bool m_bFriendlyAimLastResult;
101  #ifdef WORKBENCH
102  protected ref Shape m_FriendlyAimShape;
103  #endif
104 
105  // Weapon and target selection
106  ref AIWeaponTargetSelector m_WeaponTargetSelector = new AIWeaponTargetSelector();
107  private ref BaseTarget m_SelectedTarget;
108  protected ref BaseTarget m_SelectedRetreatTarget;
109  protected ref array<IEntity> m_aAssignedTargets = {};
111  protected EAIUnitType m_eExpectedEnemyType = EAIUnitType.UnitType_Infantry;
112  protected ResourceName m_SelectedWeaponResource;
113 
114  // Weapon selection against a specific target and its properties
115  protected BaseWeaponComponent m_SelectedWeaponComp;
116  protected BaseMagazineComponent m_SelectedMagazineComp;
117  protected int m_iSelectedMuzzle;
118  protected float m_fSelectedWeaponMinDist;
119  protected float m_fSelectedWeaponMaxDist;
120  protected bool m_bSelectedWeaponDirectDamage;
121  protected EAIUnitType m_eUnitTypesCanAttack;
122  protected BaseCompartmentSlot m_WeaponEvaluationCompartment;
123 
124  // Weapon selection updates
125  protected float m_fNextWeaponTargetEvaluation_ms = 0;
126  protected const float WEAPON_TARGET_UPDATE_PERIOD_MS = 500;
127 
128  protected SCR_AIConfigComponent m_ConfigComponent;
129 
130 
131  // Turret dismounting
132  protected float m_fDismountTurretTimer;
133  protected static const float DISMOUNT_TURRET_TARGET_LAST_SEEN_MAX_S = 100;
134  protected static const float TURRET_TARGET_EXCESS_ANGLE_THRESHOLD_DEG = 3.0;
135  protected const float DISMOUNT_TURRET_TIMER_MS = 1200;
136  protected static ref array<EVehicleType> s_aForbidDismountTurretsOfVehicleTypes = { EVehicleType.APC };
137 
138  // Perception
139  protected float m_fEquipmentPerceptionFactor = 1.0;
140  protected float m_fPerceptionFactor = 1.0;
141 
142  protected EGadgetType m_eCurrentGadgetType = -1;
143  protected bool m_bGadgetFocus = false;
144 
145  //------------------------------------------------------------------------------------------------
147  EAISkill GetAISkill()
148  {
149  return m_eAISkill;
150  }
151 
152  //------------------------------------------------------------------------------------------------
155  void SetAISkill(EAISkill skill)
156  {
157  #ifdef AI_DEBUG
158  AddDebugMessage(string.Format("SetAISkill: %1", typename.EnumToString(EAISkill, skill)));
159  #endif
160 
161  m_eAISkill = skill;
162  }
163 
164  //------------------------------------------------------------------------------------------------
170  void SetPerceptionFactor(float value)
171  {
172  if (value < 0)
173  value = 0;
174  m_fPerceptionFactor = value;
175  UpdatePerceptionFactor(m_Perception, m_Utility.m_ThreatSystem);
176  }
177 
178  //------------------------------------------------------------------------------------------------
180  void ResetAISkill()
181  {
182  #ifdef AI_DEBUG
183  AddDebugMessage("ResetAISkill");
184  #endif
185 
186  m_eAISkill = m_eAISkillDefault;
187  }
188 
189  //------------------------------------------------------------------------------------------------
191  EWeaponType GetCurrentWeaponType()
192  {
193  BaseWeaponComponent currentWeapon = null;
194  if (m_CurrentTurretController)
195  {
196  // If we are in turret, find turret weapon
197  BaseWeaponManagerComponent turretWpnMgr = m_CurrentTurretController.GetWeaponManager();
198  if (turretWpnMgr)
199  currentWeapon = turretWpnMgr.GetCurrentWeapon();
200  }
201  else if (m_WpnManager)
202  {
203  // If not in turret, use character's weapon
204  currentWeapon = m_WpnManager.GetCurrentWeapon();
205  }
206 
207  if (currentWeapon)
208  return currentWeapon.GetWeaponType();
209 
210  return EWeaponType.WT_NONE;
211  }
212 
213  //------------------------------------------------------------------------------------------------
215  BaseTarget GetCurrentTarget()
216  {
217  return m_SelectedTarget;
218  }
219 
220  //------------------------------------------------------------------------------------------------
222  BaseTarget GetRetreatTarget()
223  {
224  return m_SelectedRetreatTarget;
225  }
226 
227  //------------------------------------------------------------------------------------------------
229  BaseTarget GetLastSeenEnemy()
230  {
231  return m_Perception.GetLastSeenTarget(ETargetCategory.ENEMY, float.MAX);
232  }
233 
234  //------------------------------------------------------------------------------------------------
236  // Finds out if some of my known enemies is aimng at me.
237  BaseTarget GetEndangeringEnemy()
238  {
239  array<BaseTarget> targets = {};
240  m_Perception.GetTargetsList(targets, ETargetCategory.ENEMY);
241 
242  foreach (BaseTarget tgt : targets)
243  {
244  if (tgt.IsEndangering())
245  return tgt;
246  }
247 
248  return null;
249  }
250 
251  //------------------------------------------------------------------------------------------------
254  bool IsEnemyKnown(IEntity ent)
255  {
256  bool knownAsEnemy = m_Perception.GetTargetPerceptionObject(ent, ETargetCategory.ENEMY);
257  bool knownAsDetected = m_Perception.GetTargetPerceptionObject(ent, ETargetCategory.DETECTED);
258  return knownAsEnemy || knownAsDetected;
259  }
260 
261  //------------------------------------------------------------------------------------------------
269  void EvaluateWeaponAndTarget(out bool outWeaponEvent, out bool outSelectedTargetChanged,
270  out BaseTarget outPrevTarget, out BaseTarget outCurrentTarget,
271  out bool outRetreatTargetChanged, out bool outCompartmentChanged)
272  {
273  float worldTime = GetGame().GetWorld().GetWorldTime();
274  if (worldTime < m_fNextWeaponTargetEvaluation_ms)
275  {
276  outWeaponEvent = false;
277  outSelectedTargetChanged = false;
278  return;
279  }
280 
281  m_fNextWeaponTargetEvaluation_ms = worldTime + WEAPON_TARGET_UPDATE_PERIOD_MS;
282 
283  AIAgent myAgent = GetAiAgent();
284  AIGroup myGroup = myAgent.GetParentGroup();
285  SCR_AIGroupInfoComponent groupInfoComp;
286  if (myGroup)
287  groupInfoComp = SCR_AIGroupInfoComponent.Cast(myGroup.FindComponent(SCR_AIGroupInfoComponent));
288 
289  BaseTarget newTarget = null;
290  bool weaponEvent = false;
291  bool selectedTargetChanged = false;
292  bool retreatTargetChanged = false;
293  bool compartmentChanged = false;
294 
295  // Resolve if we want to think of throwing grenade
296  // Grenade throw is synchronized via group
297  array<EWeaponType> weaponBlacklist;
298  if (groupInfoComp)
299  {
300  if (!groupInfoComp.IsGrenadeThrowAllowed(myAgent))
301  weaponBlacklist = s_aWeaponBlacklistFragGrenades;
302  }
303 
304  bool useCompartmentWeapons = m_AIInfo.HasUnitState(EUnitState.IN_TURRET); // True when we are in a turret
305 
306  // Which assigned targets array to use?
307  array<IEntity> assignedTargets;
308  if (m_TargetClusterState && m_TargetClusterState.m_Cluster && m_TargetClusterState.m_Cluster.m_aEntities)
309  assignedTargets = m_TargetClusterState.m_Cluster.m_aEntities;
310  else
311  assignedTargets = m_aAssignedTargets;
312 
313  bool selectedWpnTarget = m_WeaponTargetSelector.SelectWeaponAndTarget(assignedTargets,
314  ASSIGNED_TARGETS_SCORE_INCREMENT, ENDANGERING_TARGETS_SCORE_INCREMENT,
315  useCompartmentWeapons, weaponTypesBlacklist: weaponBlacklist);
316 
317  m_eUnitTypesCanAttack = m_WeaponTargetSelector.GetUnitTypesCanAttack();
318  if (selectedWpnTarget)
319  {
320  BaseWeaponComponent newWeaponComp;
321  BaseMagazineComponent newMagazineComp;
322  int newMuzzleId;
323 
324  newTarget = m_WeaponTargetSelector.GetSelectedTarget();
325  m_WeaponTargetSelector.GetSelectedWeapon(newWeaponComp, newMuzzleId, newMagazineComp);
326  m_WeaponTargetSelector.GetSelectedWeaponProperties(m_fSelectedWeaponMinDist, m_fSelectedWeaponMaxDist, m_bSelectedWeaponDirectDamage);
327 
328 
329  weaponEvent = newWeaponComp != m_SelectedWeaponComp ||
330  newMuzzleId != m_iSelectedMuzzle ||
331  newMagazineComp != m_SelectedMagazineComp;
332 
333  bool weaponOrMuzzleChanged = newWeaponComp != m_SelectedWeaponComp ||
334  newMuzzleId != m_iSelectedMuzzle;
335 
336  if (weaponOrMuzzleChanged)
337  {
338  ref array<BaseMuzzleComponent> muzzles = {};
339  newWeaponComp.GetMuzzlesList(muzzles);
340  if (newMuzzleId >= muzzles.Count() || newMuzzleId < 0)
341  m_SelectedWeaponResource = m_ConfigComponent.GetTreeNameForWeaponType(newWeaponComp.GetWeaponType(),0);
342  else
343  m_SelectedWeaponResource = m_ConfigComponent.GetTreeNameForWeaponType(newWeaponComp.GetWeaponType(),muzzles[newMuzzleId].GetMuzzleType());
344 
345  if (newWeaponComp)
346  {
347  EWeaponType weaponType = newWeaponComp.GetWeaponType();
348  if (groupInfoComp && weaponType == EWeaponType.WT_FRAGGRENADE)
349  {
350  // We want to throw a grenade
351  // Notify group immediately
352  groupInfoComp.OnAgentSelectedGrenade(myAgent);
353  }
354  }
355  }
356 
357  m_SelectedWeaponComp = newWeaponComp;
358  m_iSelectedMuzzle = newMuzzleId;
359  m_SelectedMagazineComp = newMagazineComp;
360  }
361 
362  BaseTarget prevTarget = m_SelectedTarget;
363  if (newTarget != m_SelectedTarget)
364  {
365  #ifdef AI_DEBUG
366  AddDebugMessage(string.Format("Target has changed. New: %1, Previous: %2", newTarget, m_SelectedTarget));
367  #endif
368  m_SelectedTarget = newTarget;
369  selectedTargetChanged = true;
370  }
371 
372  // Check if we must retreat from some target
373  BaseTarget targetCantAttack;
374  float targetCantAttackScore;
375  m_WeaponTargetSelector.GetMostRelevantTargetCantAttack(targetCantAttack, targetCantAttackScore);
376  if (targetCantAttackScore < TARGET_SCORE_RETREAT)
377  targetCantAttack = null;
378  if (targetCantAttack != m_SelectedRetreatTarget)
379  {
380  m_SelectedRetreatTarget = targetCantAttack;
381  retreatTargetChanged = true;
382  }
383 
384  // Check if compartment has changed
385  BaseCompartmentSlot currentCompartment = m_CompartmentAccess.GetCompartment();
386  if (currentCompartment != m_WeaponEvaluationCompartment)
387  {
388  compartmentChanged = true;
389  m_WeaponEvaluationCompartment = currentCompartment;
390  }
391 
392  outWeaponEvent = weaponEvent;
393  outSelectedTargetChanged = selectedTargetChanged;
394  outRetreatTargetChanged = retreatTargetChanged;
395  outCompartmentChanged = compartmentChanged;
396  outCurrentTarget = newTarget;
397  outPrevTarget = prevTarget;
398  }
399 
400  //------------------------------------------------------------------------------------------------
401  SCR_AIInfoComponent GetAIInfoComponent()
402  {
403  return m_AIInfo;
404  }
405 
406  //------------------------------------------------------------------------------------------------
411  bool EvaluateLowAmmo(BaseWeaponComponent weaponComp, int muzzleId)
412  {
413  if (!weaponComp)
414  return false;
415  array<BaseMuzzleComponent> muzzles = {};
416  weaponComp.GetMuzzlesList(muzzles);
417  if (muzzleId >= muzzles.Count() || muzzleId < 0)
418  return false;
419 
420  BaseMuzzleComponent muzzleComp = muzzles[muzzleId];
421  if (!muzzleComp)
422  return false;
423 
424  // Ignore disposable weapons
425  if (muzzleComp.IsDisposable())
426  return false;
427 
428  int magCount = m_InventoryManager.GetMagazineCountByWeapon(weaponComp);
429 
430  int lowMagThreshold = 0;
431 
432  // Decide how many remainiing magazines is enough to complain
433  switch (weaponComp.GetWeaponType())
434  {
435  case EWeaponType.WT_RIFLE: lowMagThreshold = 3; break;
436  case EWeaponType.WT_GRENADELAUNCHER: lowMagThreshold = 3; break; // todo now it won't work when we are out of UGL ammo because weapons are not marked with WT_GRENADELAUNCHER
437  case EWeaponType.WT_SNIPERRIFLE: lowMagThreshold = 1; break;
438  case EWeaponType.WT_ROCKETLAUNCHER: lowMagThreshold = 1; break;
439  case EWeaponType.WT_MACHINEGUN: lowMagThreshold = 1; break;
440  case EWeaponType.WT_HANDGUN: lowMagThreshold = 1; break;
441  default: lowMagThreshold = 0;
442  }
443 
444  return magCount < lowMagThreshold;
445  }
446 
447  //------------------------------------------------------------------------------------------------
450  void Update(float timeSliceMs)
451  {
452  // Evaluate if we must dismount turret - only if we are already in turret
453  if (m_CurrentTurretController)
454  EvaluateDismountTurret(timeSliceMs);
455  }
456 
457  //------------------------------------------------------------------------------------------------
463  bool DismountTurretCondition(inout vector targetPos, bool targetPosProvided)
464  {
465  // False if not in turret
466  if (!m_CurrentTurretController)
467  return false;
468  TurretComponent turretComp = m_CurrentTurretController.GetTurretComponent();
469  if (!turretComp)
470  return false;
471 
472  // False if we have a valid target to attack
473  if (m_SelectedTarget)
474  return false;
475 
476  // False if we have a driver in the vehicle
477  array<BaseCompartmentSlot> compartments = {};
478  m_CurrentVehicleCompartmentManager.GetCompartments(compartments);
479  foreach (BaseCompartmentSlot slot : compartments)
480  {
481  if (PilotCompartmentSlot.Cast(slot) && slot.GetOccupant())
482  return false;
483  }
484 
485  // False if we are in a vehicle and we should not leave turret of this vehicle type
486  // Note that static turrets are not of Vehicle class.
487  Vehicle vehicle = Vehicle.Cast(m_CurrentVehicle);
488  if (vehicle && s_aForbidDismountTurretsOfVehicleTypes.Find(vehicle.m_eVehicleType) != -1)
489  return false;
490 
491  // If target pos is not provided, find a target which we are going to check against
492  if (!targetPosProvided)
493  {
494  BaseTarget target = m_Perception.GetClosestTarget(ETargetCategory.DETECTED, DISMOUNT_TURRET_TARGET_LAST_SEEN_MAX_S, DISMOUNT_TURRET_TARGET_LAST_SEEN_MAX_S);
495  if (target)
496  targetPos = target.GetLastDetectedPosition();
497  else
498  {
499  target = m_Perception.GetClosestTarget(ETargetCategory.ENEMY, DISMOUNT_TURRET_TARGET_LAST_SEEN_MAX_S, DISMOUNT_TURRET_TARGET_LAST_SEEN_MAX_S);
500  if (target)
501  targetPos = target.GetLastSeenPosition();
502  }
503 
504  // False if there is no target which would cause us to dismount
505  if (!target)
506  return false;
507  else
508  {
509  IEntity targetEntity = target.GetTargetEntity();
510  if (!targetEntity)
511  return false;
512  else
513  {
514  vector bmin, bmax;
515  targetEntity.GetBounds(bmin, bmax);
516  targetPos = targetPos + 0.5 * (bmin + bmax);
517  }
518  }
519  }
520 
521  // Check angle excess of the target's position
522  vector angleExcess = turretComp.GetAimingAngleExcess(targetPos);
523 
524  //PrintFormat("Excess angle: %1", angleExcess);
525 
526  return angleExcess.Length() > TURRET_TARGET_EXCESS_ANGLE_THRESHOLD_DEG;
527  }
528 
529  //------------------------------------------------------------------------------------------------
530  protected void EvaluateDismountTurret(float timeSliceMs)
531  {
532  vector targetPos;
533  bool mustDismount = DismountTurretCondition(targetPos, false);
534 
535  if (!mustDismount)
536  {
537  m_fDismountTurretTimer = 0;
538  }
539  else
540  {
541  // Do nothing if already requested to dismount
542  if (m_fDismountTurretTimer == -1.0)
543  return;
544 
545  m_fDismountTurretTimer += timeSliceMs;
546 
547  if (m_fDismountTurretTimer > DISMOUNT_TURRET_TIMER_MS)
548  {
549  m_fDismountTurretTimer = -1.0;
550 
551  TryAddDismountTurretActions(targetPos);
552  }
553  }
554  }
555 
556  //------------------------------------------------------------------------------------------------
562  void TryAddDismountTurretActions(vector targetPos, bool addGetOut = true, bool addInvestigate = true, bool addGetIn = true)
563  {
564  BaseCompartmentSlot compartmentSlot = m_CurrentCompartmentSlot;
565  if (!compartmentSlot)
566  return;
567 
568  if (addGetOut)
569  {
570  AIActionBase prevGetOutAction = m_Utility.FindActionOfType(SCR_AIGetOutVehicle);
571  if (prevGetOutAction)
572  return;
573 
574  SCR_AIGetOutVehicle getOutAction = new SCR_AIGetOutVehicle(m_Utility, null, compartmentSlot.GetOwner(), SCR_AIActionBase.PRIORITY_BEHAVIOR_DISMOUNT_TURRET);
575  m_Utility.AddAction(getOutAction);
576  }
577 
578  if (addInvestigate)
579  {
580  AIActionBase prevInvestigate = m_Utility.FindActionOfType(SCR_AIMoveAndInvestigateBehavior);
581  if (!prevInvestigate)
582  {
583  SCR_AIMoveAndInvestigateBehavior moveAndInvestigateAction = new SCR_AIMoveAndInvestigateBehavior(m_Utility, null, targetPos, SCR_AIActionBase.PRIORITY_BEHAVIOR_DISMOUNT_TURRET_INVESTIGATE, true);
584  m_Utility.AddAction(moveAndInvestigateAction);
585  }
586  }
587 
588  if (addGetIn)
589  {
590  AIActionBase prevGetInAction = m_Utility.FindActionOfType(SCR_AIGetInVehicle);
591  if (!prevGetInAction)
592  {
593  SCR_AIGetInVehicle getInAction = new SCR_AIGetInVehicle(m_Utility, null, compartmentSlot.GetVehicle(), ECompartmentType.Turret, SCR_AIActionBase.PRIORITY_BEHAVIOR_DISMOUNT_TURRET_GET_IN);
594  m_Utility.AddAction(getInAction);
595  }
596  }
597  }
598 
599  protected static const float DISTANCE_MAX = 22;
600  protected static const float DISTANCE_MIN = 6; // Minimal distance when movement is allowed
601  private static const float NEAR_PROXIMITY = 2;
602 
603  protected const float m_StopDistance = 30 + Math.RandomFloat(0, 10);
604  // TODO: add possibility to get cover towards custom position
605  //------------------------------------------------------------------------------------------------
608  vector FindNextCoverPosition()
609  {
610  if (!m_SelectedTarget)
611  return vector.Zero;
612 
613  vector ownerPos = GetOwner().GetOrigin();
614  vector lastSeenPos = m_SelectedTarget.GetLastSeenPosition();
615  float distanceToTarget = vector.Distance(ownerPos, lastSeenPos);
616 
617  if (m_StopDistance > distanceToTarget)
618  return vector.Zero;
619 
620  // Create randomized position
621  SCR_ChimeraAIAgent agent = GetAiAgent();
622  SCR_DefendWaypoint defendWp = SCR_DefendWaypoint.Cast(agent.m_GroupWaypoint);
623  vector direction;
624  bool standardAttack = true;
625  float nextCoverDistance;
626 
627  // If target is outside defend waypoint, run towards center of it
628  if (defendWp)
629  {
630  if (!defendWp.IsWithinCompletionRadius(lastSeenPos) &&
631  !defendWp.IsWithinCompletionRadius(ownerPos))
632  {
633  direction = vector.Direction(ownerPos, defendWp.GetOrigin()); // Direction towards center of defend wp
634 
635  if (vector.Distance(defendWp.GetOrigin(), ownerPos) < DISTANCE_MIN)
636  nextCoverDistance = 0;
637  else
638  nextCoverDistance = DISTANCE_MIN;
639 
640  standardAttack = false;
641  }
642  }
643 
644  if (standardAttack)
645  {
646  nextCoverDistance = Math.RandomFloat(DISTANCE_MIN, DISTANCE_MAX);
647 
648  // If close enough, get directly to the target
649  if (nextCoverDistance > (distanceToTarget - DISTANCE_MIN))
650  nextCoverDistance = distanceToTarget - DISTANCE_MIN;
651 
652  direction = vector.Direction(ownerPos, m_SelectedTarget.GetLastSeenPosition());
653  }
654 
655  direction.Normalize();
656  vector newPositionCenter = direction * nextCoverDistance + ownerPos, newPosition;
657  // yes possibly it could lead to end up in target position but lets ignore it for now
658 
659  newPosition = s_AIRandomGenerator.GenerateRandomPointInRadius(0, NEAR_PROXIMITY, newPositionCenter, true);
660  newPosition[1] = newPositionCenter[1];
661  return newPosition;
662  }
663 
664  //------------------------------------------------------------------------------------------------
665  protected void Event_OnInventoryChanged(IEntity item, BaseInventoryStorageComponent storageOwner)
666  {
667  // This event spams so much, especially at start, we want to process it only once
668  //ScriptCallQueue callQueue = GetGame().GetCallqueue();
669  //callQueue.Remove(Event_OnTimerAfterInventoryChanged);
670  //callQueue.CallLater(Event_OnTimerAfterInventoryChanged, 2500, false);
671  }
672  protected void Event_OnTimerAfterInventoryChanged()
673  {
674  //EvaluateAndReportOutOfAmmo();
675  }
676 
677  //------------------------------------------------------------------------------------------------
683  protected void Event_OnCompartmentEntered( IEntity vehicle, BaseCompartmentManagerComponent manager, int mgrID, int slotID )
684  {
685  m_CurrentCompartmentSlot = manager.FindCompartment(slotID, mgrID);
686  IEntity compartmentEntity = m_CurrentCompartmentSlot.GetOwner();
687  m_CurrentTurretController = TurretControllerComponent.Cast(compartmentEntity.FindComponent(TurretControllerComponent));
688  m_CurrentVehicle = m_CurrentCompartmentSlot.GetVehicle();
689  m_CurrentVehicleCompartmentManager = SCR_BaseCompartmentManagerComponent.Cast(m_CurrentVehicle.FindComponent(SCR_BaseCompartmentManagerComponent));
690  }
691 
692  //------------------------------------------------------------------------------------------------
698  protected void Event_OnCompartmentLeft( IEntity vehicle, BaseCompartmentManagerComponent manager, int mgrID, int slotID )
699  {
700  m_CurrentVehicle = null;
701  m_bCurrentVehicleEvac = false;
702  m_CurrentCompartmentSlot = null;
703  m_CurrentTurretController = null;
704  }
705 
706  //------------------------------------------------------------------------------------------------
707  protected void Event_OnGadgetStateChanged(IEntity gadget, bool isInHand, bool isOnGround)
708  {
709  if (isInHand)
710  {
711  SCR_GadgetComponent gadgetComp = SCR_GadgetComponent.Cast(gadget.FindComponent(SCR_GadgetComponent));
712  if (gadgetComp)
713  m_eCurrentGadgetType = gadgetComp.GetType();
714  else
715  m_eCurrentGadgetType = -1;
716  }
717  else
718  m_eCurrentGadgetType = -1;
719 
720  RecalculateEquipmentPerceptionFactor();
721  }
722 
723  //------------------------------------------------------------------------------------------------
724  protected void Event_OnGadgetFocusStateChanged(IEntity gadget, bool isFocused)
725  {
726  m_bGadgetFocus = isFocused;
727  RecalculateEquipmentPerceptionFactor();
728  }
729 
730  //------------------------------------------------------------------------------------------------
731  protected void Event_OnDamage(BaseDamageContext damageContext)
732  {
733  if (damageContext.damageType != EDamageType.FIRE || !m_Utility || !m_CurrentVehicle || m_bCurrentVehicleEvac)
734  return;
735 
736  // Fire damage inside a vehicle - evac vehicle
737  m_bCurrentVehicleEvac = true;
738 
739  SCR_AIGetOutVehicle behaviorGetOut = new SCR_AIGetOutVehicle(m_Utility, null, m_CurrentVehicle, SCR_AIActionBase.PRIORITY_BEHAVIOR_GET_OUT_VEHICLE_HIGH_PRIORITY);
740  m_Utility.AddAction(behaviorGetOut);
741 
742  SCR_AIMoveFromDangerBehavior behaviorMoveFromDanger = new SCR_AIMoveFromDangerBehavior(m_Utility, null, m_CurrentVehicle.GetOrigin(), m_CurrentVehicle);
743  m_Utility.AddAction(behaviorMoveFromDanger);
744  }
745 
746  //------------------------------------------------------------------------------------------------
747  protected void Event_OnDamageOverTimeAdded(EDamageType dType, float dps, HitZone hz)
748  {
749  if (dType != EDamageType.BLEEDING || !m_Utility || !m_Utility.m_AIInfo)
750  return;
751 
752  SCR_AIActionBase currentAction = SCR_AIActionBase.Cast(m_Utility.GetCurrentAction());
753  if (!currentAction)
754  return;
755  float priorityLevelClamped = currentAction.GetRestrictedPriorityLevel();
756 
757  if (m_Utility.m_AIInfo.HasRole(EUnitRole.MEDIC))
758  {
759  if (!m_Utility.HasActionOfType(SCR_AIHealBehavior))
760  {
761  // If we can heal ourselves, add Heal Behavior.
762  SCR_AIHealBehavior behavior = new SCR_AIHealBehavior(m_Utility, null, m_Utility.m_OwnerEntity, true, priorityLevel: priorityLevelClamped);
763  m_Utility.AddAction(behavior);
764  }
765  }
766  else if (m_Agent)
767  {
768  // If we immediately know that we can't heal ourselves, report to group
769  AIGroup myGroup = m_Agent.GetParentGroup();
770  if (myGroup)
771  {
772  SCR_MailboxComponent myMailbox = SCR_MailboxComponent.Cast(m_Agent.FindComponent(SCR_MailboxComponent));
773  SCR_AIMessage_Wounded msg = SCR_AIMessage_Wounded.Create(m_Utility.m_OwnerEntity);
774  myMailbox.RequestBroadcast(msg, myGroup);
775  }
776  }
777  }
778 
779  //------------------------------------------------------------------------------------------------
783  // Checks if unit is allowed to do action from the allowed actions enum
784  bool IsActionAllowed(EAICombatActions action)
785  {
786  return (m_iAllowedActions & action);
787  }
788 
789  //------------------------------------------------------------------------------------------------
791  EAICombatActions GetAllowedActions()
792  {
793  return m_iAllowedActions;
794  }
795 
796  //------------------------------------------------------------------------------------------------
797  private void SetActionAllowed(EAICombatActions action, bool isAllowed)
798  {
799  #ifdef AI_DEBUG
800  AddDebugMessage(string.Format("SetActionAllowed: %1, %2", typename.EnumToString(EAICombatActions, action), isAllowed));
801  #endif
802 
803  if ((m_iAllowedActions & action) != isAllowed)
804  {
805  if (isAllowed)
806  m_iAllowedActions = m_iAllowedActions | action;
807  else
808  m_iAllowedActions = m_iAllowedActions & ~action;
809  }
810  }
811 
812  //------------------------------------------------------------------------------------------------
814  void SetHoldFire(bool isHoldFire)
815  {
816  #ifdef AI_DEBUG
817  AddDebugMessage(string.Format("SetHoldFire: %1", isHoldFire));
818  #endif
819 
820  if (isHoldFire)
821  {
822  SetActionAllowed(EAICombatActions.HOLD_FIRE,true);
823  SetActionAllowed(EAICombatActions.BURST_FIRE,false);
824  SetActionAllowed(EAICombatActions.SUPPRESSIVE_FIRE,false);
825  }
826  else
827  {
828  SetCombatType(m_eCombatType);
829  }
830  }
831 
832  //------------------------------------------------------------------------------------------------
834  EAICombatType GetCombatType()
835  {
836  return m_eCombatType;
837  }
838 
839  // For current AI combat type can be changed during the behaviors
840  // If you want AI to come bac to your state you have to set also default
841  //------------------------------------------------------------------------------------------------
843  void SetCombatType(EAICombatType combatType)
844  {
845  #ifdef AI_DEBUG
846  AddDebugMessage(string.Format("SetCombatType: %1", typename.EnumToString(EAICombatType, combatType)));
847  #endif
848 
849  switch (combatType)
850  {
851  case EAICombatType.NONE:
852  {
853  SetActionAllowed(EAICombatActions.HOLD_FIRE,true);
854  SetActionAllowed(EAICombatActions.MOVEMENT_WHEN_FIRE,false);
855  SetActionAllowed(EAICombatActions.SUPPRESSIVE_FIRE,false);
856  SetActionAllowed(EAICombatActions.MOVEMENT_TO_LAST_SEEN,false);
857  break;
858  }
859  case EAICombatType.NORMAL:
860  {
861  SetActionAllowed(EAICombatActions.HOLD_FIRE,false);
862  SetActionAllowed(EAICombatActions.MOVEMENT_WHEN_FIRE,true);
863  SetActionAllowed(EAICombatActions.SUPPRESSIVE_FIRE,false);
864  SetActionAllowed(EAICombatActions.MOVEMENT_TO_LAST_SEEN,true);
865  break;
866  }
867  case EAICombatType.SUPPRESSIVE:
868  {
869  SetActionAllowed(EAICombatActions.HOLD_FIRE,false);
870  SetActionAllowed(EAICombatActions.MOVEMENT_WHEN_FIRE,false);
871  SetActionAllowed(EAICombatActions.SUPPRESSIVE_FIRE,true);
872  SetActionAllowed(EAICombatActions.MOVEMENT_TO_LAST_SEEN,true);
873  break;
874  }
875  case EAICombatType.RETREAT:
876  {
877  SetActionAllowed(EAICombatActions.HOLD_FIRE,false);
878  SetActionAllowed(EAICombatActions.MOVEMENT_WHEN_FIRE,true);
879  SetActionAllowed(EAICombatActions.SUPPRESSIVE_FIRE,false);
880  SetActionAllowed(EAICombatActions.MOVEMENT_TO_LAST_SEEN,false);
881  break;
882  }
883  case EAICombatType.SINGLE_SHOT:
884  {
885  SetActionAllowed(EAICombatActions.HOLD_FIRE,false);
886  SetActionAllowed(EAICombatActions.MOVEMENT_WHEN_FIRE,false);
887  SetActionAllowed(EAICombatActions.SUPPRESSIVE_FIRE,false);
888  SetActionAllowed(EAICombatActions.MOVEMENT_TO_LAST_SEEN,false);
889  break;
890  }
891  }
892  m_eCombatType = combatType;
893 #ifdef WORKBENCH
894  SCR_AIDebugVisualization.VisualizeMessage(GetOwner(), typename.EnumToString(EAICombatType,m_eCombatType), EAIDebugCategory.COMBAT, 5);
895 #endif
896  }
897 
898  //------------------------------------------------------------------------------------------------
902  void SetDefaultCombatType(EAICombatType combatType)
903  {
904  #ifdef AI_DEBUG
905  AddDebugMessage(string.Format("SetDefaultCombatType: %1", typename.EnumToString(EAICombatType, combatType)));
906  #endif
907 
908  m_eDefaultCombatType = combatType;
909  }
910 
911  //------------------------------------------------------------------------------------------------
913  void ResetCombatType()
914  {
915  #ifdef AI_DEBUG
916  AddDebugMessage("ResetCombatType");
917  #endif
918 
919  SetCombatType(m_eDefaultCombatType);
920  }
921 
922  //------------------------------------------------------------------------------------------------
924  bool IsFriendlyInAim()
925  {
926  IEntity friendlyEntInAim = m_Perception.GetFriendlyInLineOfFire();
927 #ifdef WORKBENCH
928  if (friendlyEntInAim && DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_AI_SHOW_FRIENDLY_IN_AIM))
929  m_FriendlyAimShape = Shape.CreateSphere(COLOR_RED, ShapeFlags.NOOUTLINE|ShapeFlags.NOZBUFFER|ShapeFlags.TRANSP, friendlyEntInAim.GetOrigin() + Vector(0, 2, 0), 0.1);
930  else
931  m_FriendlyAimShape = null;
932 #endif
933  m_bFriendlyAimLastResult = friendlyEntInAim != null;
934 
935  return m_bFriendlyAimLastResult;
936  }
937 
938  //------------------------------------------------------------------------------------------------
942  bool IsTargetVisible(notnull BaseTarget target)
943  {
944  // When m_lastSeenMax value is lower than perception component update interval,
945  // which might be large at higher LOD levels, the decorator might periodically return false,
946  // even when target is still visible.
947  // Therefore we must prevent the threshold from being smaller than update interval of perception component.
948  float lastSeenMax = Math.Max(TARGET_MAX_LAST_SEEN_VISIBLE, m_Perception.GetUpdateInterval()) + 0.02;
949  bool visible = target.GetTimeSinceSeen() < lastSeenMax;
950  return visible;
951  }
952 
953  //------------------------------------------------------------------------------------------------
957  void SetAssignedTargets(array<IEntity> assignedTargets, SCR_AITargetClusterState clusterState)
958  {
959  m_aAssignedTargets.Clear();
960 
961  if (assignedTargets)
962  m_aAssignedTargets.Copy(assignedTargets);
963  else if (clusterState)
964  m_TargetClusterState = clusterState;
965  }
966 
967  //------------------------------------------------------------------------------------------------
969  void ResetAssignedTargets()
970  {
971  m_aAssignedTargets.Clear();
972  m_TargetClusterState = null;
973  }
974 
975  //------------------------------------------------------------------------------------------------
977  void SetExpectedEnemyType(EAIUnitType expectedEnemyType)
978  {
979  m_eExpectedEnemyType = expectedEnemyType;
980  }
981 
982  //------------------------------------------------------------------------------------------------
984  void ResetExpectedEnemyType()
985  {
986  m_eExpectedEnemyType = EAIUnitType.UnitType_Infantry;
987  }
988 
989  //------------------------------------------------------------------------------------------------
996  void GetSelectedWeaponAndMagazine(out BaseWeaponComponent outWeaponComp, out int outMuzzleId, out BaseMagazineComponent outMagazineComp)
997  {
998  if (m_SelectedWeaponComp)
999  {
1000  outWeaponComp = m_SelectedWeaponComp;
1001  outMagazineComp = m_SelectedMagazineComp;
1002  outMuzzleId = m_iSelectedMuzzle;
1003  }
1004  else
1005  {
1006  outWeaponComp = null;
1007  outMuzzleId = -1;
1008  outMagazineComp = null;
1009  }
1010  }
1011 
1012  //------------------------------------------------------------------------------------------------
1015  void GetSelectedWeapon(out BaseWeaponComponent outWeaponComp, out int outMuzzleId)
1016  {
1017  if (m_SelectedWeaponComp)
1018  {
1019  outWeaponComp = m_SelectedWeaponComp;
1020  outMuzzleId = m_iSelectedMuzzle;
1021  }
1022  else
1023  {
1024  outWeaponComp = null;
1025  outMuzzleId = -1;
1026  }
1027  }
1028 
1029  //------------------------------------------------------------------------------------------------
1031  EWeaponType GetSelectedWeaponType()
1032  {
1033  if (m_SelectedWeaponComp)
1034  return m_SelectedWeaponComp.GetWeaponType();
1035  else
1036  return EWeaponType.WT_NONE;
1037  }
1038 
1039  //------------------------------------------------------------------------------------------------
1043  void GetSelectedWeaponProperties(out float outMinDistance, out float outMaxDistance, out bool outDirectDamage)
1044  {
1045  outMinDistance = m_fSelectedWeaponMinDist;
1046  outMaxDistance = m_fSelectedWeaponMaxDist;
1047  outDirectDamage = m_bSelectedWeaponDirectDamage;
1048  }
1049 
1050  //------------------------------------------------------------------------------------------------
1052  bool GetSelectedWeaponDirectDamage()
1053  {
1054  return m_bSelectedWeaponDirectDamage;
1055  }
1056 
1057  //------------------------------------------------------------------------------------------------
1059  float GetSelectedWeaponMinDist()
1060  {
1061  return m_fSelectedWeaponMinDist;
1062  }
1063 
1064  //------------------------------------------------------------------------------------------------
1066  float GetSelectedWeaponMaxDist()
1067  {
1068  return m_fSelectedWeaponMaxDist;
1069  }
1070 
1071  //------------------------------------------------------------------------------------------------
1073  ResourceName GetSelectedWeaponResource()
1074  {
1075  return m_SelectedWeaponResource;
1076  }
1077 
1078  //------------------------------------------------------------------------------------------------
1080  EAIUnitType GetUnitTypesCanAttack()
1081  {
1082  return m_eUnitTypesCanAttack;
1083  }
1084 
1085  //------------------------------------------------------------------------------------------------
1091  void EvaluateExpectedWeapon(out BaseWeaponComponent outWeaponComp, out int outMuzzleId, out BaseMagazineComponent outMagazineComp)
1092  {
1093  bool useCompartmentWeapons = m_AIInfo.HasUnitState(EUnitState.IN_TURRET);
1094  bool success = m_WeaponTargetSelector.SelectWeaponAgainstUnitType(m_eExpectedEnemyType, useCompartmentWeapons);
1095 
1096  if (success)
1097  {
1098  BaseWeaponComponent weaponComp;
1099  int muzzleId;
1100  BaseMagazineComponent magazineComp;
1101 
1102  m_WeaponTargetSelector.GetSelectedWeapon(weaponComp, muzzleId, magazineComp);
1103 
1104  outWeaponComp = weaponComp;
1105  outMuzzleId = muzzleId;
1106  outMagazineComp = magazineComp;
1107  }
1108  else
1109  {
1110  outWeaponComp = null;
1111  outMuzzleId = null;
1112  outMagazineComp = null;
1113  }
1114  }
1115 
1116  //------------------------------------------------------------------------------------------------
1119  bool HasWeaponOfType(EWeaponType weaponType)
1120  {
1121  return m_WeaponTargetSelector.HasWeaponOfType(weaponType, false);
1122  }
1123 
1124  //------------------------------------------------------------------------------------------------
1128  BaseWeaponComponent FindWeaponOfType(EWeaponType weaponType)
1129  {
1130  return m_WeaponTargetSelector.FindWeaponOfType(weaponType, false);
1131  }
1132 
1133  //------------------------------------------------------------------------------------------------
1137  int GetMagazineCount(typename magazineWell, bool countMagazineInWeapon = false)
1138  {
1139  int count = m_WeaponTargetSelector.GetMagazineCount(magazineWell, false);
1140  return count - 1 + countMagazineInWeapon;
1141  }
1142 
1143  //------------------------------------------------------------------------------------------------
1144  override void OnPostInit(IEntity owner)
1145  {
1146  super.OnPostInit(owner);
1147  SetEventMask(owner, EntityEvent.INIT);
1148  }
1149 
1150  //------------------------------------------------------------------------------------------------
1151  override void EOnInit(IEntity owner)
1152  {
1153  m_eAISkill = m_eAISkillDefault;
1154 
1155  ChimeraCharacter character = ChimeraCharacter.Cast(owner);
1156  if (character)
1157  {
1158  m_CharacterController = SCR_CharacterControllerComponent.Cast(character.GetCharacterController());
1160  {
1161  m_CharacterController.m_OnGadgetStateChangedInvoker.Insert(Event_OnGadgetStateChanged);
1162  m_CharacterController.m_OnGadgetFocusStateChangedInvoker.Insert(Event_OnGadgetFocusStateChanged);
1163  }
1164 
1165  m_WpnManager = m_CharacterController.GetWeaponManagerComponent();
1166 
1167  m_InventoryManager = SCR_InventoryStorageManagerComponent.Cast(m_CharacterController.GetInventoryStorageManager());
1168  if (m_InventoryManager)
1169  {
1170  m_InventoryManager.m_OnItemAddedInvoker.Insert(Event_OnInventoryChanged);
1171  m_InventoryManager.m_OnItemRemovedInvoker.Insert(Event_OnInventoryChanged);
1172  }
1173 
1174  m_CompartmentAccess = SCR_CompartmentAccessComponent.Cast(character.GetCompartmentAccessComponent());
1175  if (m_CompartmentAccess)
1176  {
1177  m_CompartmentAccess.GetOnCompartmentEntered().Insert(Event_OnCompartmentEntered);
1178  m_CompartmentAccess.GetOnCompartmentLeft().Insert(Event_OnCompartmentLeft);
1179  }
1180  }
1181 
1182  m_Perception = PerceptionComponent.Cast(owner.FindComponent(PerceptionComponent));
1183 
1184  BaseWorld world = GetGame().GetWorld();
1185  if (world)
1186  {
1187  float worldTime = world.GetWorldTime();
1188  m_fNextWeaponTargetEvaluation_ms = worldTime + Math.RandomFloat(0, WEAPON_TARGET_UPDATE_PERIOD_MS);
1189  }
1190 
1191  SetCombatType(m_eDefaultCombatType);
1192 
1193  if (owner)
1194  {
1195  InitWeaponTargetSelector(owner);
1196  }
1197 
1198  m_DamageManager = SCR_DamageManagerComponent.Cast(owner.FindComponent(SCR_DamageManagerComponent));
1199  if (m_DamageManager)
1200  {
1201  m_DamageManager.GetOnDamageOverTimeAdded().Insert(Event_OnDamageOverTimeAdded);
1202  m_DamageManager.GetOnDamage().Insert(Event_OnDamage);
1203  }
1204 
1205  AIControlComponent ctrl = AIControlComponent.Cast(owner.FindComponent(AIControlComponent));
1206  if (ctrl)
1207  {
1208  SCR_ChimeraAIAgent agent = SCR_ChimeraAIAgent.Cast(ctrl.GetAIAgent());
1209  if (agent)
1210  {
1211  m_AIInfo = agent.m_InfoComponent;
1212  m_ConfigComponent = SCR_AIConfigComponent.Cast(agent.FindComponent(SCR_AIConfigComponent));
1213  m_Utility = SCR_AIUtilityComponent.Cast(agent.FindComponent(SCR_AIUtilityComponent));
1214  }
1215  }
1216  }
1217 
1218  //------------------------------------------------------------------------------------------------
1219  override void OnDelete(IEntity owner)
1220  {
1221  if (m_CompartmentAccess)
1222  {
1223  m_CompartmentAccess.GetOnCompartmentEntered().Remove(Event_OnCompartmentEntered);
1224  m_CompartmentAccess.GetOnCompartmentLeft().Remove(Event_OnCompartmentLeft);
1225  }
1226 
1228  {
1229  m_CharacterController.m_OnGadgetStateChangedInvoker.Remove(Event_OnGadgetStateChanged);
1230  m_CharacterController.m_OnGadgetFocusStateChangedInvoker.Remove(Event_OnGadgetFocusStateChanged);
1231  }
1232 
1233  if (m_DamageManager)
1234  {
1235  m_DamageManager.GetOnDamageOverTimeAdded().Remove(Event_OnDamageOverTimeAdded);
1236  m_DamageManager.GetOnDamage().Remove(Event_OnDamage);
1237  }
1238  }
1239 
1240  //------------------------------------------------------------------------------------------------
1241  protected void InitWeaponTargetSelector(IEntity owner)
1242  {
1243  m_WeaponTargetSelector.Init(owner);
1244 
1245  // maxLastSeenIndirect must be consistent with conditions in ShouldAttackEndForTarget, therefore we use TARGET_INVISIBLE_TIME here
1246  m_WeaponTargetSelector.SetSelectionProperties(TARGET_MAX_LAST_SEEN_DIRECT_ATTACK, TARGET_MAX_LAST_SEEN_INDIRECT_ATTACK, TARGET_MAX_LAST_SEEN, TARGET_MIN_INDIRECT_TRACE_FRACTION_MIN,
1247  TARGET_MAX_DISTANCE_INFANTRY, TARGET_MAX_DISTANCE_VEHICLE, TARGET_MAX_TIME_SINCE_ENDANGERED, TARGET_MAX_DISTANCE_DISARMED);
1248 
1249  m_WeaponTargetSelector.SetTargetScoreConstants(EAIUnitType.UnitType_Infantry, 100.0, -0.1); // At short range we prefer to shoot enemies in vehicle
1250  m_WeaponTargetSelector.SetTargetScoreConstants(EAIUnitType.UnitType_VehicleUnarmored, 99.0, -0.08);
1251  m_WeaponTargetSelector.SetTargetScoreConstants(EAIUnitType.UnitType_VehicleMedium, 150.0, -0.15);
1252  m_WeaponTargetSelector.SetTargetScoreConstants(EAIUnitType.UnitType_VehicleHeavy, 200.0, -0.15);
1253  m_WeaponTargetSelector.SetTargetScoreConstants(EAIUnitType.UnitType_Aircraft, 90.0, -0.015);
1254  m_WeaponTargetSelector.SetTargetScoreConstants(EAIUnitType.UnitType_Fortification, 40.0, -0.1); // Fortifications are not used ATM
1255  }
1256 
1257  //------------------------------------------------------------------------------------------------
1261  void UpdatePerceptionFactor(PerceptionComponent perceptionComp, SCR_AIThreatSystem threatSystem)
1262  {
1263  EAIThreatState threatState = threatSystem.GetState();
1264  float perceptionFactor;
1265  switch (threatState)
1266  {
1267  case EAIThreatState.SAFE:
1268  perceptionFactor = PERCEPTION_FACTOR_SAFE; break;
1269  case EAIThreatState.VIGILANT:
1270  perceptionFactor = PERCEPTION_FACTOR_VIGILANT; break;
1271  case EAIThreatState.ALERTED:
1272  perceptionFactor = PERCEPTION_FACTOR_ALERTED; break;
1273  case EAIThreatState.THREATENED:
1274  perceptionFactor = PERCEPTION_FACTOR_THREATENED; break;
1275  }
1276 
1277  perceptionFactor *= m_fEquipmentPerceptionFactor;
1278  perceptionFactor *= m_fPerceptionFactor;
1279 
1280  perceptionComp.SetPerceptionFactor(perceptionFactor);
1281  }
1282 
1283  //------------------------------------------------------------------------------------------------
1284  protected void RecalculateEquipmentPerceptionFactor()
1285  {
1286  if (m_eCurrentGadgetType == EGadgetType.BINOCULARS && m_bGadgetFocus)
1287  m_fEquipmentPerceptionFactor = PERCEPTION_FACTOR_EQUIPMENT_BINOCULARS;
1288  else
1289  m_fEquipmentPerceptionFactor = PERCEPTION_FACTOR_EQUIPMENT_NONE;
1290  }
1291 
1292  //------------------------------------------------------------------------------------------------
1293  // destructor
1294  void ~SCR_AICombatComponent()
1295  {
1296  GetGame().GetCallqueue().Remove(Event_OnTimerAfterInventoryChanged);
1297  }
1298 
1299  //------------------------------------------------------------------------------------------------
1301  void DebugPrintToWidget(TextWidget w)
1302  {
1303  string str = string.Format("\n%1", m_SelectedTarget.ToString());
1304  if (m_SelectedTarget)
1305  str = str + string.Format("\n%1", m_SelectedTarget.GetTimeSinceSeen());
1306  else
1307  str = str + "\n";
1308  w.SetText(str);
1309  }
1310 
1311  //------------------------------------------------------------------------------------------------
1313  SCR_ChimeraAIAgent GetAiAgent()
1314  {
1315  if (m_Agent)
1316  return m_Agent;
1317 
1318  AIControlComponent controlComp = AIControlComponent.Cast(GetOwner().FindComponent(AIControlComponent));
1319  m_Agent = SCR_ChimeraAIAgent.Cast(controlComp.GetAIAgent());
1320  return m_Agent;
1321  }
1322 
1323  //------------------------------------------------------------------------------------------------
1327  BaseTarget FindTargetByEntity(IEntity ent)
1328  {
1329  BaseTarget tgt = m_Perception.FindTargetPerceptionObject(ent);
1330  if (tgt)
1331  return tgt;
1332 
1333  #ifdef AI_DEBUG
1334  AddDebugMessage(string.Format("FindTargetByEntity: did not find target: %1", ent), LogLevel.WARNING);
1335  Print(string.Format("FindTargetByEntity: did not find target: %1", ent), LogLevel.WARNING);
1336  #endif
1337  return null;
1338  }
1339 
1340  //------------------------------------------------------------------------------------------------
1344  void UpdateLastSeenPosition(IEntity entity, notnull SCR_AITargetInfo targetInfo)
1345  {
1346  BaseTarget tgt = m_Perception.FindTargetPerceptionObject(entity);
1347  if (!tgt)
1348  return;
1349 
1350  if (targetInfo.m_fTimestamp > tgt.GetTimeLastSeen())
1351  tgt.UpdateLastSeenPosition(targetInfo.m_vWorldPos, targetInfo.m_fTimestamp);
1352  }
1353 
1354  //------------------------------------------------------------------------------------------------
1358  void UpdateLastSeenPosition(notnull BaseTarget tgt, notnull SCR_AITargetInfo targetInfo)
1359  {
1360  if (targetInfo.m_fTimestamp > tgt.GetTimeLastSeen())
1361  tgt.UpdateLastSeenPosition(targetInfo.m_vWorldPos, targetInfo.m_fTimestamp);
1362  }
1363 
1364  #ifdef AI_DEBUG
1365  //------------------------------------------------------------------------------------------------
1366  protected void AddDebugMessage(string str, LogLevel logLevel = LogLevel.NORMAL)
1367  {
1368  AIControlComponent controlComp = AIControlComponent.Cast(GetOwner().FindComponent(AIControlComponent));
1369  AIAgent agent = controlComp.GetAIAgent();
1370  if (!agent)
1371  return;
1372  SCR_AIInfoBaseComponent infoComp = SCR_AIInfoBaseComponent.Cast(agent.FindComponent(SCR_AIInfoBaseComponent));
1373  infoComp.AddDebugMessage(str, msgType: EAIDebugMsgType.COMBAT, logLevel);
1374  }
1375  #endif
1376 }
ComponentEditorProps
SCR_FragmentEntityClass ComponentEditorProps
SCR_AIDebugVisualization
Definition: SCR_AIDebugVisualization.c:9
direction
vector direction
Definition: SCR_DestructibleTreeV2.c:31
BaseDamageContext
Definition: BaseDamageContext.c:12
SCR_CompartmentAccessComponent
Definition: SCR_CompartmentAccessComponent.c:15
EAIDebugMsgType
EAIDebugMsgType
Definition: SCR_AIDebugMessage.c:1
m_Agent
SCR_ChimeraAIAgent m_Agent
Definition: SCR_AIActivitySmokeCoverFeature.c:42
SCR_AICombatComponentClass
Definition: SCR_AICombatComponent.c:2
SCR_AIActionBase
Definition: SCR_AIAction.c:1
ScriptComponent
SCR_SiteSlotEntityClass ScriptComponent
HitZone
Definition: HitZone.c:12
AIWeaponTargetSelector
Definition: AIWeaponTargetSelector.c:12
EXPERT
SCR_AICombatComponentClass EXPERT
NORMAL
@ NORMAL
Definition: SCR_VehicleDamageManagerComponent.c:135
GetGame
ArmaReforgerScripted GetGame()
Definition: game.c:1424
ETargetCategory
ETargetCategory
Definition: ETargetCategory.c:12
OnDelete
override void OnDelete(IEntity owner)
Definition: SCR_CampaignBuildingCompositionComponent.c:538
SCR_DefendWaypoint
Definition: SCR_DefendWaypoint.c:18
ECompartmentType
ECompartmentType
Definition: ECompartmentType.c:7
m_Perception
ref SCR_AIGroupPerception m_Perception
Definition: SCR_AIGroupUtilityComponent.c:33
PilotCompartmentSlot
Definition: PilotCompartmentSlot.c:12
m_InventoryManager
SCR_InventoryStorageManagerComponent m_InventoryManager
Definition: SCR_AttachementAction.c:15
m_CharacterController
SCR_CharacterPerceivableComponentClass m_CharacterController
BaseTarget
Definition: BaseTarget.c:12
SCR_CharacterControllerComponent
Definition: SCR_CharacterControllerComponent.c:35
AIActionBase
Definition: AIActionBase.c:12
ROOKIE
SCR_AICombatComponentClass ROOKIE
SCR_AIMessage_Wounded
Definition: SCR_AIMessage.c:202
RETREAT
@ RETREAT
Definition: SCR_AIMessage.c:34
EAIDebugCategory
EAIDebugCategory
Definition: SCR_AIWorld.c:11
SCR_AIGetOutVehicle
Definition: SCR_AIVehicleBehavior.c:118
Attribute
typedef Attribute
Post-process effect of scripted camera.
SCR_ChimeraAIAgent
Definition: SCR_ChimeraAIAgent.c:5
BaseWeaponComponent
Definition: BaseWeaponComponent.c:12
Update
override void Update(float timeSlice)
Definition: SCR_CampaignBuildingGadgetToolComponent.c:28
SCR_AIHealBehavior
Definition: SCR_AIHealingBehavior.c:4
OnPostInit
override void OnPostInit(IEntity owner)
Called on PostInit when all components are added.
Definition: SCR_AIConfigComponent.c:72
EAIUnitType
EAIUnitType
Definition: EAIUnitType.c:12
SetPerceptionFactor
proto external void SetPerceptionFactor(float value)
Sets perception factor - how good this AI can recognize enemy, independent of enemy state....
GetOwner
IEntity GetOwner()
Owner entity of the fuel tank.
Definition: SCR_FuelNode.c:128
NONE
SCR_AICombatComponentClass NONE
REGULAR
SCR_AICombatComponentClass REGULAR
EOnInit
override void EOnInit(IEntity owner)
Definition: SCR_AIConfigComponent.c:79
SCR_AIMoveFromDangerBehavior
Definition: SCR_AIMoveFromDanger.c:4
m_TargetClusterState
SCR_AITargetClusterState m_TargetClusterState
Definition: SCR_AIMessage.c:2
TurretControllerComponent
Definition: TurretControllerComponent.c:12
m_ConfigComponent
SCR_AIConfigComponent m_ConfigComponent
Definition: SCR_AIGroupUtilityComponent.c:13
m_fPerceptionFactor
float m_fPerceptionFactor
Definition: SCR_ScenarioFrameworkSlotAI.c:42
EDamageType
EDamageType
Definition: EDamageType.c:12
EWeaponType
EWeaponType
Definition: EWeaponType.c:12
m_eAISkill
EAISkill m_eAISkill
Definition: SCR_ScenarioFrameworkSlotAI.c:36
m_AIInfo
SCR_AIInfoComponent m_AIInfo
Definition: SCR_AIUtilityComponent.c:11
SCR_AIGetInVehicle
Definition: SCR_AIVehicleBehavior.c:37
BaseMuzzleComponent
Definition: BaseMuzzleComponent.c:12
m_DamageManager
DamageManagerComponent m_DamageManager
Definition: SCR_AITargetInfo.c:19
SCR_DebugMenuID
SCR_DebugMenuID
This enum contains all IDs for DiagMenu entries added in script.
Definition: DebugMenuID.c:3
SCR_AITargetClusterState
void SCR_AITargetClusterState(SCR_AIGroupTargetCluster cluster)
Definition: SCR_AITargetClusterState.c:38
SCR_AIMoveAndInvestigateBehavior
Definition: SCR_AIMoveBehavior.c:53
SCR_AIThreatSystem
Definition: SCR_AIThreatSystem.c:17
VETERAN
SCR_AICombatComponentClass VETERAN
category
params category
Definition: SCR_VehicleDamageManagerComponent.c:180