Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_AIUtilityComponent.c
Go to the documentation of this file.
1[ComponentEditorProps(category: "GameScripted/AI", description: "Component for utility AI system calculations")]
5
6class SCR_AIUtilityComponent : SCR_AIBaseUtilityComponent
7{
10 protected FactionAffiliationComponent m_FactionComponent;
11 SCR_AIConfigComponent m_ConfigComponent;
13 SCR_AICombatComponent m_CombatComponent;
14 PerceptionComponent m_PerceptionComponent;
15 SCR_MailboxComponent m_Mailbox;
16 SCR_AICharacterSettingsComponent m_SettingsComponent;
17
23 ref SCR_AICombatMoveState m_CombatMoveState;
24 ref SCR_AIMovementDetector m_MovementDetector; // Used by GetSubformationLeaderMoving()
25
26 // CallQueue of this AI. It gets updated from EvaluateBehavior, so that it's synchronous with other AI logic.
28
31
32 protected float m_fLastUpdateTime;
33
34 protected static const float DISTANCE_HYSTERESIS_FACTOR = 0.45;
35 protected static const float NEARBY_DISTANCE_SQ = 2500;
36 protected static const float REACTION_TO_SAME_UNKNOWN_TARGET_INTERVAL_MS = 2500;
37
38 //------------------------------------------------------------------------------------------------
43 {
45 return null;
46
47 #ifdef AI_DEBUG
48 AddDebugMessage("EvaluateBehavior START");
49 if (m_bEvaluationBreakpoint)
50 {
51 Print("EvaluateBehavior breakpoint triggered", LogLevel.NORMAL);
52 debug;
53 m_bEvaluationBreakpoint = false;
54 }
55 #endif
56
57 // Update delta time and players's position
58 float time = m_OwnerEntity.GetWorld().GetWorldTime();
59 float deltaTime = time - m_fLastUpdateTime;
60 m_fLastUpdateTime = time;
61
62 // Update call queue.
63 // It must be updated before evaluation of behaviors.
64 m_Callqueue.Tick(0.001 * deltaTime);
65
66 // Create events from commands, danger events, new targets
67 m_ThreatSystem.Update(this, deltaTime);
68 m_SectorThreatFilter.Update(0.001 * deltaTime);
70
71 // Read messages
72 AIMessage msgBase = m_Mailbox.ReadMessage(true);
73 if (msgBase)
74 {
75 SCR_AIMessageGoal msgGoal = SCR_AIMessageGoal.Cast(msgBase);
76 if (msgGoal)
77 {
78 // Process goal message
79 #ifdef AI_DEBUG
80 AddDebugMessage(string.Format("PerformGoalReaction: %1, from BT: %2", msgGoal, msgGoal.m_sSentFromBt));
81 #endif
82 m_ConfigComponent.PerformGoalReaction(this, msgGoal);
83 }
84 else
85 {
86 SCR_AIMessageInfo msgInfo = SCR_AIMessageInfo.Cast(msgBase);
87 if (msgInfo)
88 {
89 // Process info message
90
91 // Try to notify actions about the message
92 bool overrideReaction = CallActionsOnMessage(msgInfo);
93
94 #ifdef AI_DEBUG
95 if (overrideReaction)
96 {
97 AddDebugMessage(string.Format("InfoMessage consumed by action: %1, from BT: %2", msgInfo, msgInfo.m_sSentFromBt));
98 }
99 #endif
100
101 // If message was not consumed by action, process it
102 if (!overrideReaction)
103 {
104 #ifdef AI_DEBUG
105 AddDebugMessage(string.Format("PerformInfoReaction: %1, from BT: %2", msgInfo, msgInfo.m_sSentFromBt));
106 #endif
107 m_ConfigComponent.PerformInfoReaction(this, msgInfo);
108 }
109 }
110 }
111 }
112
113 bool reactToUnknownTarget = false;
114 if (unknownTarget)
115 {
116 if (unknownTarget == m_UnknownTarget)
117 { // Same target
118 if (GetGame().GetWorld().GetWorldTime() - m_fReactionUnknownTargetTime_ms > REACTION_TO_SAME_UNKNOWN_TARGET_INTERVAL_MS)
119 reactToUnknownTarget = true;
120 }
121 else
122 { // Different target
123 reactToUnknownTarget = true;
124 }
125 }
126 if (reactToUnknownTarget && m_ConfigComponent.m_Reaction_UnknownTarget)
127 {
128 #ifdef AI_DEBUG
129 AddDebugMessage(string.Format("PerformReaction: Unknown Target: %1", unknownTarget));
130 #endif
131
132 m_ConfigComponent.m_Reaction_UnknownTarget.PerformReaction(this, m_ThreatSystem, unknownTarget, unknownTarget.GetLastSeenPosition());
133 m_fReactionUnknownTargetTime_ms = GetGame().GetWorld().GetWorldTime();
134 }
135 m_UnknownTarget = unknownTarget;
136
137 //------------------------------------------------------------------------------------------------
138 // Evaluate current weapon and target
139
140 bool weaponEvent;
141 bool selectedTargetChanged;
142 bool retreatTargetChanged;
143 bool compartmentChanged;
144 BaseTarget prevTarget;
145 BaseTarget selectedTarget;
146 m_CombatComponent.EvaluateWeaponAndTarget(weaponEvent, selectedTargetChanged,
147 prevTarget, selectedTarget, retreatTargetChanged, compartmentChanged);
148
149 if (selectedTargetChanged && m_ConfigComponent.m_Reaction_SelectedTargetChanged)
150 {
151 #ifdef AI_DEBUG
152 AddDebugMessage(string.Format("PerformReaction: Selected Target Changed: %1", selectedTarget));
153 #endif
154
155 m_ConfigComponent.m_Reaction_SelectedTargetChanged.PerformReaction(this, prevTarget, selectedTarget);
156 }
157
158 BaseTarget retreatTarget = m_CombatComponent.GetRetreatTarget();
159 if (retreatTarget &&
160 (compartmentChanged ||
161 (selectedTargetChanged && !selectedTarget && retreatTarget) || // Nothing to attack any more and must retreat from some target
162 (!selectedTarget && retreatTargetChanged))) // Not attacking anything and must retreat from a different target
163 {
164 if (m_ConfigComponent.m_Reaction_RetreatFromTarget)
165 {
166 #ifdef AI_DEBUG
167 AddDebugMessage(string.Format("PerformReaction: Retreat From Target: %1", retreatTarget));
168 #endif
169
170 m_ConfigComponent.m_Reaction_RetreatFromTarget.PerformReaction(this, m_ThreatSystem, retreatTarget, retreatTarget.GetLastSeenPosition());
171 }
172 }
173
174 //------------------------------------------------------------------------------------------------
175 // Update combat component
176 m_CombatComponent.Update(deltaTime);
177
178 // Evaluation: Remove completed behaviors, evaluate, set new behavior
180 AIActionBase selectedAction = EvaluateActions();
181 #ifdef AI_DEBUG
183 DebugLogActionsPriority();
184 #endif
185
186 if (selectedAction && selectedAction != m_CurrentBehavior && (!m_CurrentBehavior || m_CurrentBehavior.IsActionInterruptable()))
187 {
188 SetCurrentAction(selectedAction);
189 m_CurrentBehavior = SCR_AIBehaviorBase.Cast(selectedAction);
190#ifdef WORKBENCH
192#endif
193 }
194
195 m_CurrentBehavior.OnActionExecuted();
196
197 // Update comms handler
198 if (m_CommsHandler.m_bNeedUpdate)
199 m_CommsHandler.Update(deltaTime);
200
201 // Update combat move state
202 if (m_CombatMoveState.m_bInCover && m_CombatMoveState.GetAssignedCover())
203 m_CombatMoveState.VerifyCurrentCover(m_OwnerEntity.GetOrigin());
204
205 #ifdef AI_DEBUG
206 AddDebugMessage("EvaluateBehavior END\n");
207 #endif
208
209 return m_CurrentBehavior;
210 }
211
212 //------------------------------------------------------------------------------------------------
218
219 //------------------------------------------------------------------------------------------------
223 {
225
226 if (!leaderAgent)
227 return false;
228
229 return leaderAgent.m_UtilityComponent.m_MovementDetector.GetMoving();
230 }
231
232 //------------------------------------------------------------------------------------------------
234 {
235 vector myPos = m_OwnerEntity.GetOrigin();
236 AIAgent subformationLeaderAgent = GetSubformationLeaderAgent();
237
238 if (!subformationLeaderAgent)
239 return false;
240
241 IEntity subformationLeaderEntity = subformationLeaderAgent.GetControlledEntity();
242
243 if (!subformationLeaderEntity)
244 return false;
245
246 vector leaderPos = subformationLeaderEntity.GetOrigin();
247 float distance = vector.DistanceSq(myPos, leaderPos);
248 return distance < 20*20;
249 }
250
251 //------------------------------------------------------------------------------------------------
253 protected AIAgent GetSubformationLeaderAgent()
254 {
255 AIAgent myAgent = GetAIAgent();
256 SCR_AIGroup myGroup = SCR_AIGroup.Cast(myAgent.GetParentGroup());
257
258 // No group - no leader agent
259 if (!myGroup)
260 return null;
261
262 // Check our subformation
263 AIGroupMovementComponent movementComp = AIGroupMovementComponent.Cast(myGroup.GetMovementComponent());
264 int moveHandlerId = movementComp.GetAgentMoveHandlerId(myAgent);
265 bool formationDisplaced = movementComp.IsFormationDisplaced(moveHandlerId);
266
267 SCR_AIGroup masterGroup = myGroup.GetMaster();
268
269 if (formationDisplaced && masterGroup)
270 {
271 // This is only possible for player-led formation
272
273 int leaderId = masterGroup.GetLeaderID();
274 IEntity leaderEntity = GetGame().GetPlayerManager().GetPlayerControlledEntity(leaderId);
275 if (!leaderEntity)
276 return null;
277
278 AIControlComponent controlComp = AIControlComponent.Cast(leaderEntity.FindComponent(AIControlComponent));
279
280 if (!controlComp)
281 return null;
282
283 return controlComp.GetAIAgent();
284 }
285
286 // Formation is not displaced - get our group's leader
287 // Either moving as slave group or as master group, but it doesn't matter, either way get our leader
288 return myGroup.GetLeaderAgent();
289 }
290
291 //------------------------------------------------------------------------------------------------
294 {
295 AIAgent myAgent = GetAIAgent();
296 SCR_AIGroup myGroup = SCR_AIGroup.Cast(myAgent.GetParentGroup());
297
298 if (!myGroup)
299 return false;
300
301 AIGroupMovementComponent movementComp = AIGroupMovementComponent.Cast(myGroup.GetMovementComponent());
302
303 if (!movementComp)
304 return false;
305
306 int moveHandlerId = movementComp.GetAgentMoveHandlerId(myAgent);
307
308 bool formationDisplaced = movementComp.IsFormationDisplaced(moveHandlerId);
309
310 // If formation is displaced, then we can't be leader of it
311 if (formationDisplaced)
312 return false;
313
314 // Formation is not displaced - find our index in formation
315 array<AIAgent> agentsInHandler = {};
316 movementComp.GetAgentsInHandler(agentsInHandler, moveHandlerId);
317 int myIndexInHandler = agentsInHandler.Find(myAgent);
318
319 return myIndexInHandler == 0;
320 }
321
322 //------------------------------------------------------------------------------------------------
327 {
328 if (m_AIInfo && m_AIInfo.HasUnitState(EUnitState.IN_TURRET))
329 return false;
330
331 return true;
332 }
333
334 //------------------------------------------------------------------------------------------------
340
341 //------------------------------------------------------------------------------------------------
346
347 //------------------------------------------------------------------------------------------------
348 // when agent leaves a group, all former group-induced behaviors should fail
350 {
351 array<ref AIActionBase> actions = {};
352 GetActions(actions);
353 foreach (AIActionBase action : actions)
354 {
355 if (!action)
356 continue;
357 SCR_AIActivityBase relatedGroupActivity = SCR_AIActivityBase.Cast(action.GetRelatedGroupActivity());
358 if (relatedGroupActivity && relatedGroupActivity.m_Utility == groupUtility)
359 action.Fail();
360 }
361 }
362
363 //------------------------------------------------------------------------------------------------
366 void WrapBehaviorOutsideOfVehicle(SCR_AIActionBase action)
367 {
368
369 CompartmentAccessComponent compartmentAccess = CompartmentAccessComponent.Cast(m_OwnerEntity.FindComponent(CompartmentAccessComponent));
370 if (!compartmentAccess)
371 return;
372
373 if (!compartmentAccess.IsInCompartment())
374 return;
375
376 SCR_AIActivityBase relatedActivity;
377 SCR_AIBehaviorBase behavior = SCR_AIBehaviorBase.Cast(action);
378 if (behavior)
379 relatedActivity = SCR_AIActivityBase.Cast(behavior.GetRelatedGroupActivity());
380
381 float priority = action.GetPriority();
382 float priorityLevel = action.EvaluatePriorityLevel();
383 IEntity vehicle = compartmentAccess.GetCompartment().GetOwner();
384 ECompartmentType compartmentType = SCR_AICompartmentHandling.CompartmentClassToType(compartmentAccess.GetCompartment().Type());
385 AddAction(new SCR_AIGetOutVehicle(this, relatedActivity, vehicle, priority: priority + 100, priorityLevel: priorityLevel));
386 AddAction(new SCR_AIGetInVehicle(this, relatedActivity, vehicle, compartmentAccess.GetCompartment(), roleInVehicle: compartmentType, priority: priority, priorityLevel: priorityLevel));
387 }
388
389 //------------------------------------------------------------------------------------------------
390 override void EOnInit(IEntity owner)
391 {
392 super.EOnInit(owner);
393 AIAgent agent = GetOwner();
394 if (!agent)
395 return;
396
397 m_ConfigComponent = SCR_AIConfigComponent.Cast(agent.FindComponent(SCR_AIConfigComponent));
398
399 m_OwnerEntity = GenericEntity.Cast(agent.GetControlledEntity());
400 if (!m_OwnerEntity)
401 return;
402
404 m_AIInfo = SCR_AIInfoComponent.Cast(agent.FindComponent(SCR_AIInfoComponent));
405 m_CombatComponent = SCR_AICombatComponent.Cast(m_OwnerEntity.FindComponent(SCR_AICombatComponent));
406 m_PerceptionComponent = PerceptionComponent.Cast(m_OwnerEntity.FindComponent(PerceptionComponent));
408 m_FactionComponent = FactionAffiliationComponent.Cast(m_OwnerEntity.FindComponent(FactionAffiliationComponent));
411 m_AIInfo.InitThreatSystem(m_ThreatSystem); // let the AIInfo know about the threat system - move along with creating threat system instance!
412 m_LookAction = new SCR_AILookAction(this, false); // LookAction is not regular behavior and is evaluated separately
413 m_Mailbox = SCR_MailboxComponent.Cast(owner.FindComponent(SCR_MailboxComponent));
414 m_SettingsComponent = SCR_AICharacterSettingsComponent.Cast(owner.FindComponent(SCR_AICharacterSettingsComponent));
416 m_CombatMoveState = new SCR_AICombatMoveState();
418
419 // Subscribe to events
420 m_AIInfo.m_OnCompartmentEntered.Insert(OnCompartmentEntered);
421 m_AIInfo.m_OnCompartmentLeft.Insert(OnCompartmentLeft);
422
423 // Add default behaviors after the rest is initialized
424 m_ConfigComponent.AddDefaultBehaviors(this);
425 }
426
427 //------------------------------------------------------------------------------------------------
428 void OnCompartmentEntered (AIAgent agent, IEntity targetEntity, BaseCompartmentManagerComponent manager, int mgrID, int slotID, bool move)
429 {
430 BaseCompartmentSlot slot = manager.FindCompartment(slotID, mgrID);
431 if (PilotCompartmentSlot.Cast(slot))
432 {
433 IEntity vehicle = slot.GetVehicle();
434 if (!vehicle)
435 return;
436 auto behavior = new SCR_AIIdleBehavior_Driver(this, null, vehicle);
437 AddAction(behavior);
438 }
439 }
440
441 //------------------------------------------------------------------------------------------------
442 void OnCompartmentLeft (AIAgent agent, IEntity targetEntity, BaseCompartmentManagerComponent manager, int mgrID, int slotID, bool move)
443 {
444 BaseCompartmentSlot slot = manager.FindCompartment(slotID, mgrID);
445 if (PilotCompartmentSlot.Cast(slot))
446 {
448 behavior.Fail();
449 }
450 }
451
452 //------------------------------------------------------------------------------------------------
455 {
456 SCR_Faction f = SCR_Faction.Cast(m_FactionComponent.GetAffiliatedFaction());
457 if (!f)
458 return false;
459 return f.IsMilitary();
460 }
461
462 //------------------------------------------------------------------------------------------------
463 override void EOnDiag(IEntity owner, float timeSlice)
464 {
465 m_CommsHandler.EOnDiag(timeSlice);
466 m_SectorThreatFilter.EOnDiag(timeSlice);
467 }
468
469 //------------------------------------------------------------------------------------------------
472 {
473 return m_OwnerEntity.GetOrigin();
474 }
475
476 //------------------------------------------------------------------------------------------------
479 {
480 return m_Callqueue;
481 }
482
483 //------------------------------------------------------------------------------------------------
484 void LookAt(vector pos,float duration = 2)
485 {
486 m_LookAction.LookAt(pos, SCR_AILookAction.PRIO_COMMANDER, duration);
487 }
488
489 //------------------------------------------------------------------------------------------------
491 {
492 if (m_AIInfo)
493 {
494 m_AIInfo.m_OnCompartmentEntered.Remove(OnCompartmentEntered);
495 m_AIInfo.m_OnCompartmentLeft.Remove(OnCompartmentLeft);
496 }
497 }
498}
ECompartmentType
ArmaReforgerScripted GetGame()
Definition game.c:1398
void SCR_AIActivityBase(SCR_AIGroupUtilityComponent utility, AIWaypoint relatedWaypoint)
void DiagIncreaseCounter()
void SCR_AIBehaviorBase(SCR_AIUtilityComponent utility, SCR_AIActivityBase groupActivity)
enum EAIGroupCombatMode ComponentEditorProps(category:"GameScripted/AI", description:"Component for utility AI system for groups")
SCR_AIUtilityComponentClass m_OwnerEntity
vector GetOrigin()
ref SCR_AILookAction m_LookAction
PerceptionComponent m_PerceptionComponent
ref SCR_AISectorThreatFilter m_SectorThreatFilter
ref SCR_AIThreatSystem m_ThreatSystem
void OnCompartmentEntered(AIAgent agent, IEntity targetEntity, BaseCompartmentManagerComponent manager, int mgrID, int slotID, bool move)
SCR_AIInfoComponent m_AIInfo
float m_fLastUpdateTime
SCR_AICharacterSettingsComponent m_SettingsComponent
void OnCompartmentLeft(AIAgent agent, IEntity targetEntity, BaseCompartmentManagerComponent manager, int mgrID, int slotID, bool move)
bool IsMilitary()
Are we a military AI or not?
ref SCR_AICommsHandler m_CommsHandler
ref SCR_AIBehaviorBase m_CurrentBehavior
Used for avoiding constant casting, outside of this class use GetCurrentBehavior().
bool GetSubformationLeaderMoving()
bool CanIndependentlyMove()
SCR_CharacterControllerComponent GetCharacterController()
SCR_AIBehaviorBase GetCurrentBehavior()
ref BaseTarget m_UnknownTarget
float m_fReactionUnknownTargetTime_ms
WorldTime timestamp.
ref SCR_AICombatMoveState m_CombatMoveState
SCR_MailboxComponent m_Mailbox
AIAgent GetSubformationLeaderAgent()
Returns leader agent of subformation of this agent.
bool ShouldKeepFormation()
Returns true if we should be mindful about our formation overall.
ref SCR_AIMovementDetector m_MovementDetector
bool IsSubformationLeader()
Returns true if this agent is leader of its subformation.
FactionAffiliationComponent m_FactionComponent
ref ScriptCallQueue m_Callqueue
void LookAt(vector pos, float duration=2)
bool GetNearSubformationLeader()
SCR_AICombatComponent m_CombatComponent
void CancelAllGroupActivityBehaviors(notnull SCR_AIGroupUtilityComponent groupUtility)
SCR_CharacterControllerComponent m_OwnerController
SCR_AIBehaviorBase EvaluateBehavior(BaseTarget unknownTarget)
SCR_AIConfigComponent m_ConfigComponent
void WrapBehaviorOutsideOfVehicle(SCR_AIActionBase action)
ScriptCallQueue GetCallqueue()
Returns CallQueue of this AI. It gets updated from EvaluateBehavior, so that it's synchronous with ot...
void ~SCR_AIUtilityComponent()
EAIDebugCategory
Definition SCR_AIWorld.c:12
float distance
array< ref SCR_MenuActionPreset > GetActions()
Base class for all messages related to AI.
Definition AIMessage.c:14
proto external Managed FindComponent(typename typeName)
proto external vector GetOrigin()
Game core which persists through whole game and stores various data for AI debugging.
Definition SCR_AIDebug.c:4
static string GetBehaviorName(SCR_AIBehaviorBase behavior)
Definition SCR_AIDebug.c:49
static void VisualizeMessage(IEntity entity, string message, EAIDebugCategory category, float showTime, Color color=Color.White, float fontSize=16, bool ignoreCategory=false)
SCR_AIGroup GetMaster()
int GetLeaderID()
bool IsMilitary()
ScriptCallQueue Class provide "lazy" calls - when we don't want to execute function immediately but l...
Definition tools.c:53
proto external bool CallActionsOnMessage(AIMessage msg)
IEntity GetOwner()
Owner entity of the fuel tank.
override void EOnDiag(IEntity owner, float timeSlice)
proto external bool HasActionOfType(typename actionType)
Returns true when there is an action of exactly this type.
AIBaseUtilityComponentClass AIComponentClass EvaluateActions()
Evaluate all actions and return the highest evaluated action which is not suspended....
proto external void AddAction(AIActionBase action)
Adds an action.
override void EOnInit(IEntity owner)
proto external bool RemoveObsoleteActions()
Removes actions which are failed or completed.
proto external void SetCurrentAction(AIActionBase executed)
proto external AIActionBase FindActionOfType(typename actionType)
Finds action of exactly this type.
proto void Print(void var, LogLevel level=LogLevel.NORMAL)
Prints content of variable to console/log.
LogLevel
Enum with severity of the logging message.
Definition LogLevel.c:14