Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_AIVehicleCombatActivity.c
Go to the documentation of this file.
1
2class SCR_AIVehicleCombatActivity : SCR_AIActivityBase
3{
4 static const string ACTIVITY_NAME = "SCR_AIVehicleCombatActivity";
5
6 //------------------------------------------------------------------------------------
7 void SCR_AIVehicleCombatActivity(SCR_AIGroupUtilityComponent utility, AIWaypoint relatedWaypoint)
8 {
9 SetPriority(PRIORITY_ACTIVITY_COMBAT_WITH_VEHICLES);
10 }
11
12 //------------------------------------------------------------------------------------
13 override float CustomEvaluate()
14 {
15 // Do we have vehicles?
16 if (m_Utility.m_VehicleMgr.GetVehiclesCount() == 0)
17 return 0;
18
19 // Does combat mode forbit combat?
20 if (m_Utility.GetCombatModeActual() == EAIGroupCombatMode.HOLD_FIRE)
21 return 0;
22
23 // Does something threaten us too much?
24 SCR_AIGroupTargetCluster c = m_Utility.m_Perception.m_MostDangerousCluster;
25 if (!c)
26 return 0;
27
28 // Are we not a slave group?
29 if (m_Utility.m_Owner.IsSlave())
30 return 0;
31
32 // Do we have at least some non-static vehicles?
33 int countNonStatic = 0;
34 array<ref SCR_AIGroupVehicle> allVehicles = {};
35 m_Utility.m_VehicleMgr.GetAllVehicles(allVehicles);
36 foreach (SCR_AIGroupVehicle v : allVehicles)
37 {
38 if (!v.IsStatic())
39 countNonStatic++;
40 }
41
42 if (countNonStatic == 0)
43 return 0;
44
45 // Is the target cluster dangerous enough?
47 return 0;
48
49 return GetPriority();
50 }
51
52 //------------------------------------------------------------------------------------
53 override void OnActionSelected()
54 {
55 array<ref SCR_AIGroupVehicle> vehicles = {};
56 m_Utility.m_VehicleMgr.GetAllVehicles(vehicles);
57 m_Utility.m_OnAgentLifeStateChanged.Insert(OnAgentLifeStateChanged);
58
59 foreach (SCR_AIGroupVehicle v : vehicles)
60 {
61 VehicleUsageLogic(v);
62 }
63 }
64
65 //------------------------------------------------------------------------------------
66 // Checks if vehicle gunner should take over the driver seat and retreat
67 void GunnerRetreatLogic(AIAgent agent, IEntity vehicle)
68 {
69 // !!!
70 // Temporarly disabled this until retreat mechanic is available
71 // !!!
72 return;
73
74 SCR_ChimeraAIAgent chimeraAgent = SCR_ChimeraAIAgent.Cast(agent);
75 if (!chimeraAgent || !vehicle)
76 return;
77
78 if (ShouldGunnerRetreatInVehicle(chimeraAgent, vehicle))
79 {
80 AICommunicationComponent myComms = m_Utility.m_Owner.GetCommunicationComponent();
81 if (!myComms)
82 return;
83
84 // Send message to take over driver seat
85 SCR_AIMessageHandling.SendGetInMessage(agent, vehicle, EAICompartmentType.Pilot, this, myComms, ACTIVITY_NAME);
86 }
87 }
88
89 //------------------------------------------------------------------------------------
90 // Checks if vehicle gunner should take over the driver seat and retreat
91 bool ShouldGunnerRetreatInVehicle(SCR_ChimeraAIAgent chimeraAgent, IEntity vehicleEntity)
92 {
93 vector dangerPos;
94 float dangerDistance;
95
96 BaseTarget target = chimeraAgent.m_UtilityComponent.m_CombatComponent.GetCurrentTarget();
97 if (!target)
98 target = chimeraAgent.m_UtilityComponent.m_CombatComponent.GetLastSeenEnemy();
99
100 SCR_AIGroupTargetCluster cluster = m_Utility.m_Perception.m_MostDangerousCluster;
101
102 /*
103 TODO: Consider firepower difference and threat/suppression
104 cluster.m_State.m_iCountIdentified + cluster.m_State.m_iCountDetected
105 */
106
107 if (target)
108 {
109 dangerPos = target.GetLastSeenPosition();
110 dangerDistance = target.GetDistance();
111 }
112 else
113 {
114 // No targets & clusters, can safely retreat
115 if (!cluster)
116 return true;
117
118 dangerPos = cluster.m_State.GetCenterPosition();
119 dangerDistance = cluster.GetMinDistance();
120 }
121
122 // If enemy is far, don't sweat, can retreat
123 if (dangerDistance > 300)
124 return true;
125
126 // If enemy is upclose, don't retreat (agent will either shoot target or dismount and engage)
127 if (dangerDistance < 40)
128 return false;
129
130 /*
131 To consider: vehicle movement and gunner rotation capability
132
133 vector mat[3];
134 vehicleEntity.GetTransform(mat);
135 vector vehicleDir = mat[2];
136
137 vector dirToTarget = vector.Direction(vehicleEntity.GetOrigin(), dangerPos).Normalized();
138 float dangerDot = Math.AbsFloat(vector.Dot(vehicleDir, dirToTarget));
139
140 if (dangerDot < 0.6)
141 return true;
142 */
143
144 return false;
145 }
146
147 //------------------------------------------------------------------------------------
148 void VehicleUsageLogic(SCR_AIGroupVehicle vehicle)
149 {
150 AICommunicationComponent myComms = m_Utility.m_Owner.GetCommunicationComponent();
152 IEntity vehicleEntity = vehicle.GetEntity();
153
154 if (!vehicleEntity || !vehicleComp || !myComms)
155 return;
156
157 array<ref SCR_AIGroupFireteam> crewFireteams = {};
158 array<ref SCR_AIGroupFireteam> cargoFireteams = {};
159 m_Utility.m_FireteamMgr.FindFireteamsOfVehicle(crewFireteams, vehicleComp, SCR_AIGroupFireteamVehicleCrew);
160 m_Utility.m_FireteamMgr.FindFireteamsOfVehicle(cargoFireteams, vehicleComp, SCR_AIGroupFireteamVehicleCargo);
161
162 int soldierCounter = 0;
163
164 array<AIAgent> ftAgents = {};
165 if (!vehicle.HasWeapon())
166 {
167 foreach (SCR_AIGroupFireteam ft : crewFireteams)
168 {
169 ft.GetMembers(ftAgents);
170 foreach (AIAgent agent : ftAgents)
171 {
172 SCR_AIMessageHandling.SendDismountMessage(agent, vehicleEntity, soldierCounter, this, myComms, ACTIVITY_NAME);
173 ft.RemoveMember(agent);
174 soldierCounter++;
175 }
176 }
177 }
178 else // since we have a vehicle with weapon, we listen on driver's lifeStateChange and react on it
179 {
180 foreach (SCR_AIGroupFireteam ft : crewFireteams)
181 {
182 ft.GetMembers(ftAgents);
183 foreach (AIAgent agent : ftAgents)
184 {
185 if (!vehicleComp)
186 break;
187 if (!vehicleComp.CanBePiloted())
188 break;
189 if (!agent)
190 continue;
191 SCR_ChimeraAIAgent chimeraAgent = SCR_ChimeraAIAgent.Cast(agent);
192 if (!chimeraAgent)
193 continue;
194 SCR_AIInfoComponent agentInfo = chimeraAgent.m_InfoComponent;
195 if (!agentInfo)
196 continue;
197 // actual logic
198 if (agentInfo.HasUnitState(EUnitState.PILOT) && (agentInfo.HasUnitState(EUnitState.WOUNDED) || agentInfo.HasUnitState(EUnitState.UNCONSCIOUS)))
199 {
200 // driver is incap when attack starts - find someone available and use him as new driver
201 AIAgent newDriver;
202 SCR_AIGroupFireteam newDriversFireTeam;
203 if (GetAvailableAgent(cargoFireteams, newDriver, newDriversFireTeam))
204 {
205 newDriversFireTeam.RemoveMember(newDriver);
206 SCR_AIMessageHandling.SendGetInMessage(newDriver, vehicleEntity, EAICompartmentType.Pilot, this, myComms, ACTIVITY_NAME);
207 };
208 }
209 else if (agentInfo.HasUnitState(EUnitState.IN_TURRET) && ftAgents.Count() == 1)
210 {
211 // gunner is the only one in the crew fireteam
212 AIAgent newDriver;
213 SCR_AIGroupFireteam newDriversFireTeam;
214 if (GetAvailableAgent(cargoFireteams, newDriver, newDriversFireTeam))
215 {
216 newDriversFireTeam.RemoveMember(newDriver);
217 SCR_AIMessageHandling.SendGetInMessage(newDriver, vehicleEntity, EAICompartmentType.Pilot, this, myComms, ACTIVITY_NAME);
218 }
219 else
220 GunnerRetreatLogic(agent, vehicleEntity);
221 }
222 }
223 }
224 }
225
226 foreach (SCR_AIGroupFireteam ft : cargoFireteams)
227 {
228 ft.GetMembers(ftAgents);
229 foreach (AIAgent agent : ftAgents)
230 {
231 SCR_AIMessageHandling.SendDismountMessage(agent, vehicleEntity, soldierCounter, this, myComms, ACTIVITY_NAME);
232 ft.RemoveMember(agent);
233 soldierCounter++;
234 }
235 }
236 }
237
238 //------------------------------------------------------------------------------------
242 bool GetAvailableAgent(array<ref SCR_AIGroupFireteam> fireteams, out AIAgent availableAgent, out SCR_AIGroupFireteam agentsFireTeam)
243 {
244 array<AIAgent> ftAgents = {};
245 SCR_AIInfoComponent agentInfo;
246 foreach (SCR_AIGroupFireteam ft : fireteams)
247 {
248 ft.GetMembers(ftAgents);
249 foreach (AIAgent agent : ftAgents)
250 {
251 agentInfo = SCR_AIInfoComponent.Cast(agent.FindComponent(SCR_AIInfoComponent));
252 if (!agentInfo.HasUnitState(EUnitState.WOUNDED) && !agentInfo.HasUnitState(EUnitState.UNCONSCIOUS))
253 {
254 availableAgent = agent;
255 agentsFireTeam = ft;
256 return true;
257 }
258 }
259 }
260 return false;
261 }
262
263 //------------------------------------------------------------------------------------
265 {
266 // Has it not been seen for too long?
267 if (c.m_State.GetTimeSinceLastNewInformation() > 20.0)
268 return false;
269
270 // We could also check if we have a waypoint or not
271
272 // Is it too far?
273 float distThreshold;
274 if (c.m_State.m_iCountEndangering > 0)
275 distThreshold = 550.0;
276 else
277 distThreshold = 200.0;
278
279 if (c.m_State.m_fDistMin > distThreshold)
280 return false;
281
282 return true;
283 }
284
285 //-----------------------------------------------------------------------------------------
289 void OnAgentLifeStateChanged(AIAgent incapacitatedAgent, SCR_AIInfoComponent infoIncap, IEntity vehicle, ECharacterLifeState lifeState)
290 {
291 if (!incapacitatedAgent || !vehicle || lifeState == ECharacterLifeState.ALIVE || !infoIncap.HasUnitState(EUnitState.PILOT))
292 return;
293 SCR_AIGroupFireteam fireTeam = m_Utility.m_FireteamMgr.FindFireteam(incapacitatedAgent);
294 AICommunicationComponent myComms = m_Utility.m_Owner.GetCommunicationComponent();
295 if (!fireTeam || !myComms)
296 return;
298 array<AIAgent> agentsOfGroup = {};
299 m_Utility.m_Owner.GetAgents(agentsOfGroup);
300 int agentsNum = agentsOfGroup.Count();
301 if (agentsNum > 1)
302 {
303 int memberCount = fireTeam.GetMemberCount();
304 if (memberCount > 1) // we have some agent left in the same fireteam -> we use him
305 {
306 // replacing driver with either gunner or somebody else
307 array<AIAgent> agentsOfFireteam = {};
308 fireTeam.GetMembers(agentsOfFireteam);
309 AIAgent newDriverAgent, newGunnerAgent;
310 bool newDriverIsOldGunner = false;
311 foreach (AIAgent agent : agentsOfFireteam)
312 {
313 if (agent != incapacitatedAgent && memberCount == 2) // there is only incap driver and gunner
314 {
315 newDriverAgent = agent;
316 newDriverIsOldGunner = true;
317 break;
318 }
319 else if (agent != incapacitatedAgent) // there are more ft members -> we skip the gunner
320 {
321 info = SCR_AIInfoComponent.Cast(agent.FindComponent(SCR_AIInfoComponent));
322 if (!info || info.HasUnitState(EUnitState.WOUNDED) || info.HasUnitState(EUnitState.UNCONSCIOUS) || info.HasUnitState(EUnitState.IN_TURRET))
323 continue;
324 newDriverAgent = agent;
325 break;
326 }
327 }
328 // possibly replacing gunner if he is the new driver
329 if (newDriverIsOldGunner && agentsNum > 2) // we have available gunner outside of our fireteam!
330 {
331 foreach (AIAgent agent : agentsOfGroup)
332 {
333 if (!agent || agent == incapacitatedAgent || agent == newDriverAgent)
334 continue;
335 info = SCR_AIInfoComponent.Cast(agent.FindComponent(SCR_AIInfoComponent));
336 if (!info || info.HasUnitState(EUnitState.WOUNDED) || info.HasUnitState(EUnitState.UNCONSCIOUS))
337 continue;
338 newGunnerAgent = agent;
339 break;
340 }
341 }
342
343 if (newDriverAgent)
344 GunnerRetreatLogic(newDriverAgent, vehicle);
345
346 if (newGunnerAgent)
347 {
348 SCR_AIMessageHandling.SendGetInMessage(newGunnerAgent, vehicle, EAICompartmentType.Turret, this, myComms, ACTIVITY_NAME);
349 SCR_AIMessageHandling.SendMoveMessage(newDriverAgent, newGunnerAgent.GetControlledEntity(), this, myComms, ACTIVITY_NAME);
350 }
351 }
352 }
353 }
354
355
356 //-----------------------------------------------------------------------------------
357 override void OnActionDeselected()
358 {
359 super.OnActionDeselected();
360 //cleanup
361 m_Utility.m_OnAgentLifeStateChanged.Remove(OnAgentLifeStateChanged);
362 }
363}
override void OnActionSelected()
void SCR_AIActivityBase(SCR_AIGroupUtilityComponent utility, AIWaypoint relatedWaypoint)
enum SCR_EAIActivityCause m_Utility
override float CustomEvaluate()
EAICompartmentType
void GetMembers(notnull array< AIAgent > outAgents)
void RemoveMember(AIAgent agent)
This class is used for keeping track of vehicles assigned to group.
SCR_AIVehicleUsageComponent GetVehicleUsageComponent()
bool HasUnitState(EUnitState state)
bool IsClusterDangerousEnough(notnull SCR_AIGroupTargetCluster c)
void OnAgentLifeStateChanged(AIAgent incapacitatedAgent, SCR_AIInfoComponent infoIncap, IEntity vehicle, ECharacterLifeState lifeState)
bool CanBePiloted()
AI can use the pilot compartments on this vehicle.
ECharacterLifeState