Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_AIThreatSystem.c
Go to the documentation of this file.
1// TODO:
2// Better calculation of actual threat - can he see me, does he aim at me, etc.
3// Grenade landed event
4
14void SCR_AIThreatStateChangedCallback(EAIThreatState prevState, EAIThreatState newState);
15typedef ScriptInvokerBase<SCR_AIThreatStateChangedCallback> SCR_AIThreatStateChangedInvoker;
16
17class SCR_AIThreatSystem
18{
19 private static const float THREAT_SHOT_DROP_RATE = 0.11 * 0.001;
20 private static const float THREAT_SUPPRESSION_DROP_RATE = 0.1 * 0.001;
21 private static const float THREAT_ENDANGERED_DROP_RATE = 0.2 * 0.001;
22
23 private static const float BLEEDING_FIXED_INCREMENT = 0.3;
24 private static const float SUPPRESSION_BULLET_INCREMENT = 0.10;
25 private static const float ZERO_DISTANCE_SHOT_INCREMENT = 0.008;
26 private static const float DISTANT_SHOT_INCREMENT = 0.002;
27 // Decrased from 0.6 until friendly explosions can be filtered out on game code level
28 private static const float EXPLOSION_MAX_INCREMENT = 0.2;
29
30 private static const float EXPLOSION_CLOSE_DISTANCE = 12;
31
32 // Decrased from 700 until friendly explosions can be filtered out on game code level
33 static const float EXPLOSION_MAX_DISTANCE = 100;
34
35 private static const float ENDANGERED_INCREMENT = 0.2;
36
37 static const float VIGILANT_THRESHOLD = 0.05;
38 protected static const float ALERTED_THRESHOLD = 0.33;
39 static const float THREATENED_THRESHOLD = 0.66;
40
43 static const float ATTACK_DELAYED_THRESHOLD = 0.001;
44
45 //range between <0,1>
46 private float m_fThreatTotal;
47 private float m_fThreatSuppression;
48 private float m_fThreatShotsFired;
49 private float m_fThreatIsEndangered;
50 private float m_fThreatInjury;
51
52 private SCR_AIUtilityComponent m_Utility;
53 private SCR_AIConfigComponent m_Config;
54 private SCR_AICombatComponent m_Combat;
55 private SCR_ExtendedDamageManagerComponent m_DamageManager;
56
57 private SCR_ChimeraAIAgent m_Agent;
58
59 private EAIThreatState m_State;
60
61 private ref SCR_AIThreatStateChangedInvoker m_OnThreatStateChanged = new SCR_AIThreatStateChangedInvoker();
62
63 //------------------------------------------------------------------------------------------------
64 // constructor
66 void SCR_AIThreatSystem(SCR_AIUtilityComponent utility)
67 {
68 m_Utility = utility;
69 m_Config = utility.m_ConfigComponent;
70 m_Combat = utility.m_CombatComponent;
71 m_DamageManager = SCR_ExtendedDamageManagerComponent.Cast(utility.m_OwnerEntity.FindComponent(SCR_ExtendedDamageManagerComponent));
72 SCR_ChimeraAIAgent agent = SCR_ChimeraAIAgent.Cast(utility.GetOwner());
73 if (!agent)
74 return;
75 m_Agent = agent;
76
77 // AI threat system is owned by Utility Component, therefore we don't unsubscribe from the event
78 if (m_DamageManager)
79 {
80 m_DamageManager.GetOnDamageEffectAdded().Insert(OnDamageEffectAdded);
81 m_DamageManager.GetOnDamageEffectRemoved().Insert(OnDamageEffectRemoved);
82 }
83
84 m_State = EAIThreatState.SAFE;
85 }
86
87 //------------------------------------------------------------------------------------------------
89 SCR_AIThreatStateChangedInvoker GetOnThreatStateChanged()
90 {
91 return m_OnThreatStateChanged;
92 }
93
94 //------------------------------------------------------------------------------------------------
96 EAIThreatState GetState()
97 {
98 return m_State;
99 }
100
101 //------------------------------------------------------------------------------------------------
103 float GetThreatMeasureWithoutInjuryFactor()
104 {
105 return m_fThreatTotal - m_fThreatInjury;
106 }
107
108 //------------------------------------------------------------------------------------------------
110 float GetSuppressionMeasure()
111 {
112 return m_fThreatSuppression;
113 }
114
115 //------------------------------------------------------------------------------------------------
117 float GetThreatMeasure()
118 {
119 return m_fThreatTotal;
120 }
121
122#ifdef WORKBENCH
123 //------------------------------------------------------------------------------------------------
125 void ShowDebug()
126 {
127 // Show message above AI's head
128
129 Color color;
130
131 switch (m_State)
132 {
133 case EAIThreatState.SAFE:
134 {
135 color = Color.FromInt(Color.GREEN);
136 break;
137 }
138 case EAIThreatState.VIGILANT:
139 {
140 color = Color.FromInt(Color.DARK_GREEN);
141 break;
142 }
143 case EAIThreatState.ALERTED:
144 {
145 color = Color.FromInt(Color.DARK_YELLOW);
146 break;
147 }
148 case EAIThreatState.THREATENED:
149 {
150 color = Color.FromInt(Color.DARK_RED);
151 break;
152 }
153 }
154
155 SCR_AIDebugVisualization.VisualizeMessage(m_Utility.m_OwnerEntity, typename.EnumToString(EAIThreatState, m_State), EAIDebugCategory.THREAT, 1.4, color);
156 }
157#endif // WORKBENCH
158
159 //------------------------------------------------------------------------------------------------
160 private void StateTransition(EAIThreatState newState)
161 {
162 if (newState == m_State)
163 return;
164
165 m_OnThreatStateChanged.Invoke(m_State, newState);
166
167 m_State = newState;
168 }
169
170 //------------------------------------------------------------------------------------------------
171 private void UpdateState()
172 {
173 EAIThreatState newState = EAIThreatState.SAFE;
174
175 if (m_fThreatTotal > THREATENED_THRESHOLD)
176 newState = EAIThreatState.THREATENED;
177 else if (m_fThreatTotal > ALERTED_THRESHOLD)
178 newState = EAIThreatState.ALERTED;
179 else if (m_fThreatTotal > VIGILANT_THRESHOLD)
180 newState = EAIThreatState.VIGILANT;
181
182 StateTransition(newState);
183 }
184
185 //------------------------------------------------------------------------------------------------
190 void Update(SCR_AIUtilityComponent utility, float timeSlice)
191 {
192 // Threat falloff
193 m_fThreatSuppression -= m_fThreatSuppression * THREAT_SUPPRESSION_DROP_RATE * timeSlice;
194 m_fThreatShotsFired -= m_fThreatShotsFired * THREAT_SHOT_DROP_RATE * timeSlice;
195
196 if (m_Combat)
197 {
198 if (m_Combat.GetCurrentTarget())
199 m_fThreatIsEndangered = ENDANGERED_INCREMENT;
200 else
201 m_fThreatIsEndangered -= m_fThreatIsEndangered * THREAT_ENDANGERED_DROP_RATE * timeSlice;
202 }
203
204 // Process all danger events and clear the array
205 if (m_Agent && m_Config.m_EnableDangerEvents)
206 {
207 int i;
208 AIDangerEvent dangerEvent;
209
210#ifdef AI_DEBUG
211 if (m_Agent.GetDangerEventsCount() != 0)
212 AddDebugMessage(string.Format("Processing danger events: %1 in the queue", m_Agent.GetDangerEventsCount()));
213#endif
214
215 for (int max = m_Agent.GetDangerEventsCount(); i < max; i++)
216 {
217 int eventAggregationCount;
218 dangerEvent = m_Agent.GetDangerEvent(i, eventAggregationCount);
219
220
221 #ifdef AI_DEBUG
222 AddDebugMessage(string.Format("PerformDangerReaction: %1x %2", eventAggregationCount, dangerEvent));
223 #endif
224
225 if (dangerEvent)
226 {
227 if (m_Config.PerformDangerReaction(m_Utility, dangerEvent, eventAggregationCount))
228 {
229#ifdef WORKBENCH
230 string message = typename.EnumToString(EAIDangerEventType, dangerEvent.GetDangerType());
231 SCR_AIDebugVisualization.VisualizeMessage(m_Utility.m_OwnerEntity, message, EAIDebugCategory.DANGER, 2); // Show message above AI's head
232#endif
233 }
234 }
235 }
236
237 m_Agent.ClearDangerEvents(i + 1);
238 }
239
240 // Add threat value from current behavior
241 float threatFromBehavior;
242 if (utility.m_CurrentBehavior)
243 threatFromBehavior = utility.m_CurrentBehavior.m_fThreat;
244
245 m_fThreatTotal = Math.Clamp(threatFromBehavior + m_fThreatSuppression + m_fThreatInjury + m_fThreatShotsFired + m_fThreatIsEndangered, 0, 1);
246
247 UpdateState();
248#ifdef WORKBENCH
249 ShowDebug();
250#endif
251 }
252
253 //------------------------------------------------------------------------------------------------
254 protected void OnDamageEffectAdded(notnull SCR_DamageEffect dmgEffect)
255 {
256 if (dmgEffect.GetDamageType() != EDamageType.BLEEDING || !DotDamageEffect.Cast(dmgEffect))
257 return;
258
259 m_fThreatInjury = BLEEDING_FIXED_INCREMENT;
260 }
261
262 //------------------------------------------------------------------------------------------------
263 protected void OnDamageEffectRemoved(notnull SCR_DamageEffect dmgEffect)
264 {
265 if (dmgEffect.GetDamageType() != EDamageType.BLEEDING || !DotDamageEffect.Cast(dmgEffect))
266 return;
267
268 if (!m_DamageManager.GetAllPersistentEffectsOfType(SCR_BleedingDamageEffect))
269 m_fThreatInjury = 0;
270 }
271
272 //------------------------------------------------------------------------------------------------
275 void ThreatBulletImpact(int count)
276 {
277 #ifdef AI_DEBUG
278 AddDebugMessage(string.Format("ThreatBulletImpact: %1", count));
279 #endif
280
281 m_fThreatSuppression = Math.Clamp(m_fThreatSuppression + count*SUPPRESSION_BULLET_INCREMENT, 0, 1);
282 }
283
284 //------------------------------------------------------------------------------------------------
288 {
289 #ifdef AI_DEBUG
290 AddDebugMessage(string.Format("ThreatExplosion: %1", distance));
291 #endif
292
293 // Max increment is default as we assume that explosion happened cloaser than EXPLOSION_CLOSE_DISTANCE
294 float increment = EXPLOSION_MAX_INCREMENT;
295
296 // If distance is more than EXPLOSION_CLOSE_DISTANCE perform reversed linear mapping of threat increment
297 if (distance > EXPLOSION_CLOSE_DISTANCE)
298 increment = Math.Map(distance, EXPLOSION_CLOSE_DISTANCE, EXPLOSION_MAX_DISTANCE, EXPLOSION_MAX_INCREMENT, 0);
299
300 // Increment has to be positive or 0
301 if (increment < 0)
302 return;
303
304 m_fThreatSuppression += increment;
305 }
306
307 //------------------------------------------------------------------------------------------------
311 void ThreatShotFired(float distance, int count)
312 {
313 #ifdef AI_DEBUG
314 AddDebugMessage(string.Format("ThreatShotFired: %1, %2", distance, count));
315 #endif
316
317 // google can show you the increment function if you write it in
318 m_fThreatShotsFired = Math.Clamp(m_fThreatShotsFired + count*(DISTANT_SHOT_INCREMENT + ZERO_DISTANCE_SHOT_INCREMENT/(distance + 1)), 0, THREATENED_THRESHOLD);
319 }
320
321 //------------------------------------------------------------------------------------------------
324 void ThreatProjectileFlyby(int count)
325 {
326 #ifdef AI_DEBUG
327 AddDebugMessage(string.Format("ThreatProjectileFlyby"));
328 #endif
329
330 m_fThreatSuppression = Math.Clamp(m_fThreatSuppression + count * SUPPRESSION_BULLET_INCREMENT, 0, 1);
331 }
332
333 //------------------------------------------------------------------------------------------------
335 void GetThreatValues(out float suppression, out float shotsFired, out float injury, out float endangered)
336 {
337 suppression = m_fThreatSuppression;
338 shotsFired = m_fThreatShotsFired;
339 injury = m_fThreatInjury;
340 endangered = m_fThreatIsEndangered;
341 }
342
343 //------------------------------------------------------------------------------------------------
345 void SetThreatValues(float suppression, float shotsFired, float injury, float endangered)
346 {
347 m_fThreatSuppression = suppression;
348 m_fThreatShotsFired = shotsFired;
349 m_fThreatInjury = injury;
350 m_fThreatIsEndangered = endangered;
351 }
352
353 //------------------------------------------------------------------------------------------------
357 {
358 w.SetText(
359 typename.EnumToString(EAIThreatState, m_State) + "\n "
360 + m_fThreatTotal.ToString(1,4) + "\n "
361 + m_fThreatSuppression.ToString(1,4) + "\n "
362 + m_fThreatShotsFired.ToString(1,4) + "\n "
363 + m_fThreatInjury.ToString(1,4) + "\n "
364 + m_fThreatIsEndangered.ToString(1,4));
365 ;
366 }
367
368 #ifdef AI_DEBUG
369 //--------------------------------------------------------------------------------------------
370 protected void AddDebugMessage(string str)
371 {
372 m_Utility.m_AIInfo.AddDebugMessage(str, msgType: EAIDebugMsgType.THREAT);
373 }
374 #endif
375}
EAIDangerEventType
string message
enum SCR_EAIActivityCause m_Utility
@ SAFE
EAIDebugMsgType
@ THREATENED
@ ALERTED
@ VIGILANT
void SCR_AIThreatStateChangedCallback(EAIThreatState prevState, EAIThreatState newState)
ScriptInvokerBase< SCR_AIThreatStateChangedCallback > SCR_AIThreatStateChangedInvoker
EAIDebugCategory
Definition SCR_AIWorld.c:12
float distance
void ShowDebug()
Definition Math.c:13
static const float THREATENED_THRESHOLD
void ThreatExplosion(float distance)
void ThreatProjectileFlyby(int count)
static const float ALERTED_THRESHOLD
void SetThreatValues(float suppression, float shotsFired, float injury, float endangered)
Apply threat values obtained through GetThreatValues. primarily used for save/load logic.
static const float ATTACK_DELAYED_THRESHOLD
void GetThreatValues(out float suppression, out float shotsFired, out float injury, out float endangered)
Retrieve all threat values. primarily used for save/load logic.
void OnDamageEffectRemoved(notnull SCR_DamageEffect dmgEffect)
void ThreatBulletImpact(int count)
void OnDamageEffectAdded(notnull SCR_DamageEffect dmgEffect)
void ThreatShotFired(float distance, int count)
void DebugPrintToWidget(TextWidget w)
EDamageType
Definition EDamageType.c:13
proto external EParticleEffectState GetState()