Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
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 
5 enum EAIThreatState
6 {
7  SAFE,
11 }
12 
14 void SCR_AIThreatStateChangedCallback(EAIThreatState prevState, EAIThreatState newState);
15 typedef ScriptInvokerBase<SCR_AIThreatStateChangedCallback> SCR_AIThreatStateChangedInvoker;
16 
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  private static const float EXPLOSION_MAX_INCREMENT = 0.6;
28 
29  private static const float EXPLOSION_CLOSE_DISTANCE = 12;
30  static const float EXPLOSION_MAX_DISTANCE = 700;
31 
32  private static const float ENDANGERED_INCREMENT = 0.2;
33 
34  static const float VIGILANT_THRESHOLD = 0.05;
35  protected static const float ALERTED_THRESHOLD = 0.33;
36  static const float THREATENED_THRESHOLD = 0.66;
37 
40  static const float ATTACK_DELAYED_THRESHOLD = 0.001;
41 
42  //range between <0,1>
43  private float m_fThreatTotal;
44  private float m_fThreatSuppression;
45  private float m_fThreatShotsFired;
46  private float m_fThreatIsEndangered;
47  private float m_fThreatInjury;
48 
49  private SCR_AIUtilityComponent m_Utility;
50  private SCR_AIConfigComponent m_Config;
51  private SCR_AICombatComponent m_Combat;
52  private SCR_DamageManagerComponent m_DamageManager;
53 
54  private SCR_ChimeraAIAgent m_Agent;
55 
56  private EAIThreatState m_State;
57 
58  private ref SCR_AIThreatStateChangedInvoker m_OnThreatStateChanged = new SCR_AIThreatStateChangedInvoker();
59 
60  //------------------------------------------------------------------------------------------------
61  // constructor
63  void SCR_AIThreatSystem(SCR_AIUtilityComponent utility)
64  {
65  m_Utility = utility;
66  m_Config = utility.m_ConfigComponent;
67  m_Combat = utility.m_CombatComponent;
68  m_DamageManager = SCR_DamageManagerComponent.Cast(utility.m_OwnerEntity.FindComponent(SCR_DamageManagerComponent));
69  SCR_ChimeraAIAgent agent = SCR_ChimeraAIAgent.Cast(utility.GetOwner());
70  if (!agent)
71  return;
72  m_Agent = agent;
73 
74  // AI threat system is owned by Utility Component, therefore we don't unsubscribe from the event
75  if (m_DamageManager)
76  {
77  m_DamageManager.GetOnDamageOverTimeAdded().Insert(OnDamageOverTimeAdded);
78  m_DamageManager.GetOnDamageOverTimeRemoved().Insert(OnDamageOverTimeRemoved);
79  }
80 
81  m_State = EAIThreatState.SAFE;
82  }
83 
84  //------------------------------------------------------------------------------------------------
86  SCR_AIThreatStateChangedInvoker GetOnThreatStateChanged()
87  {
88  return m_OnThreatStateChanged;
89  }
90 
91  //------------------------------------------------------------------------------------------------
93  EAIThreatState GetState()
94  {
95  return m_State;
96  }
97 
98  //------------------------------------------------------------------------------------------------
100  float GetThreatMeasureWithoutInjuryFactor()
101  {
102  return m_fThreatTotal - m_fThreatInjury;
103  }
104 
105  //------------------------------------------------------------------------------------------------
107  float GetThreatMeasure()
108  {
109  return m_fThreatTotal;
110  }
111 
112 #ifdef WORKBENCH
113  //------------------------------------------------------------------------------------------------
115  void ShowDebug()
116  {
117  // Show message above AI's head
118 
119  Color color;
120 
121  switch (m_State)
122  {
123  case EAIThreatState.SAFE:
124  {
125  color = Color.FromInt(Color.GREEN);
126  break;
127  }
128  case EAIThreatState.VIGILANT:
129  {
130  color = Color.FromInt(Color.DARK_GREEN);
131  break;
132  }
133  case EAIThreatState.ALERTED:
134  {
135  color = Color.FromInt(Color.DARK_YELLOW);
136  break;
137  }
138  case EAIThreatState.THREATENED:
139  {
140  color = Color.FromInt(Color.DARK_RED);
141  break;
142  }
143  }
144 
145  SCR_AIDebugVisualization.VisualizeMessage(m_Utility.m_OwnerEntity, typename.EnumToString(EAIThreatState, m_State), EAIDebugCategory.THREAT, 1.4, color);
146  }
147 #endif // WORKBENCH
148 
149  //------------------------------------------------------------------------------------------------
150  private void StateTransition(EAIThreatState newState)
151  {
152  if (newState == m_State)
153  return;
154 
155  m_OnThreatStateChanged.Invoke(m_State, newState);
156 
157  m_State = newState;
158  }
159 
160  //------------------------------------------------------------------------------------------------
161  private void UpdateState()
162  {
163  EAIThreatState newState = EAIThreatState.SAFE;
164 
165  if (m_fThreatTotal > THREATENED_THRESHOLD)
166  newState = EAIThreatState.THREATENED;
167  else if (m_fThreatTotal > ALERTED_THRESHOLD)
168  newState = EAIThreatState.ALERTED;
169  else if (m_fThreatTotal > VIGILANT_THRESHOLD)
170  newState = EAIThreatState.VIGILANT;
171 
172  StateTransition(newState);
173  }
174 
175  //------------------------------------------------------------------------------------------------
180  void Update(SCR_AIUtilityComponent utility, float timeSlice)
181  {
182  // Threat falloff
183  m_fThreatSuppression -= m_fThreatSuppression * THREAT_SUPPRESSION_DROP_RATE * timeSlice;
184  m_fThreatShotsFired -= m_fThreatShotsFired * THREAT_SHOT_DROP_RATE * timeSlice;
185 
186  if (m_Combat)
187  {
188  if (m_Combat.GetCurrentTarget())
189  m_fThreatIsEndangered = ENDANGERED_INCREMENT;
190  else
191  m_fThreatIsEndangered -= m_fThreatIsEndangered * THREAT_ENDANGERED_DROP_RATE * timeSlice;
192  }
193 
194  // Process all danger events and clear the array
195  if (m_Agent && m_Config.m_EnableDangerEvents)
196  {
197  bool handled;
198  int i = 0;
199  for (; i < m_Agent.GetDangerEventsCount(); i++)
200  {
201  AIDangerEvent dangerEvent = m_Agent.GetDangerEvent(i);
202 
203  if (dangerEvent)
204  {
205  #ifdef AI_DEBUG
206  AddDebugMessage(string.Format("PerformDangerReaction: %1, %2", dangerEvent, typename.EnumToString(EAIDangerEventType, dangerEvent.GetDangerType())));
207  #endif
208 
209  if (m_Config.PerformDangerReaction(m_Utility, dangerEvent))
210  {
211 #ifdef WORKBENCH
212  string message = typename.EnumToString(EAIDangerEventType, dangerEvent.GetDangerType());
213  SCR_AIDebugVisualization.VisualizeMessage(m_Utility.m_OwnerEntity, message, EAIDebugCategory.DANGER, 2); // Show message above AI's head
214 #endif
215  break;
216  }
217  }
218  }
219  m_Agent.ClearDangerEvents(i+1);
220  }
221 
222  // Add threat value from current behavior
223  float threatFromBehavior = 0;
224  if (utility.m_CurrentBehavior)
225  threatFromBehavior = utility.m_CurrentBehavior.m_fThreat;
226 
227  m_fThreatTotal = Math.Clamp(threatFromBehavior + m_fThreatSuppression + m_fThreatInjury + m_fThreatShotsFired + m_fThreatIsEndangered, 0, 1);
228 
229  UpdateState();
230 #ifdef WORKBENCH
231  ShowDebug();
232 #endif
233  }
234 
235  //------------------------------------------------------------------------------------------------
236  protected void OnDamageOverTimeAdded(EDamageType dType, float dps, HitZone hz)
237  {
238  if (dType != EDamageType.BLEEDING)
239  return;
240 
241  if (m_DamageManager.IsDamagedOverTime(EDamageType.BLEEDING))
242  m_fThreatInjury = BLEEDING_FIXED_INCREMENT;
243  }
244 
245  //------------------------------------------------------------------------------------------------
246  protected void OnDamageOverTimeRemoved(EDamageType dType, HitZone hz)
247  {
248  if (dType != EDamageType.BLEEDING)
249  return;
250 
251  if (!m_DamageManager.IsDamagedOverTime(EDamageType.BLEEDING))
252  m_fThreatInjury = 0;
253  }
254 
255  //------------------------------------------------------------------------------------------------
258  void ThreatBulletImpact(int count)
259  {
260  #ifdef AI_DEBUG
261  AddDebugMessage(string.Format("ThreatBulletImpact: %1", count));
262  #endif
263 
264  m_fThreatSuppression = Math.Clamp(m_fThreatSuppression + count*SUPPRESSION_BULLET_INCREMENT, 0, 1);
265  }
266 
267  //------------------------------------------------------------------------------------------------
270  void ThreatExplosion(float distance)
271  {
272  #ifdef AI_DEBUG
273  AddDebugMessage(string.Format("ThreatExplosion: %1", distance));
274  #endif
275 
276  // Max increment is default as we assume that explosion happened cloaser than EXPLOSION_CLOSE_DISTANCE
277  float increment = EXPLOSION_MAX_INCREMENT;
278 
279  // If distance is more than EXPLOSION_CLOSE_DISTANCE perform reversed linear mapping of threat increment
280  if (distance > EXPLOSION_CLOSE_DISTANCE)
281  increment = Math.Map(distance, EXPLOSION_CLOSE_DISTANCE, EXPLOSION_MAX_DISTANCE, EXPLOSION_MAX_INCREMENT, 0);
282 
283  // Increment has to be positive or 0
284  if (increment < 0)
285  return;
286 
287  m_fThreatSuppression += increment;
288  }
289 
290  //------------------------------------------------------------------------------------------------
294  void ThreatShotFired(float distance, int count)
295  {
296  #ifdef AI_DEBUG
297  AddDebugMessage(string.Format("ThreatShotFired: %1, %2", distance, count));
298  #endif
299 
300  // google can show you the increment function if you write it in
301  m_fThreatShotsFired = Math.Clamp(m_fThreatShotsFired + count*(DISTANT_SHOT_INCREMENT + ZERO_DISTANCE_SHOT_INCREMENT/(distance + 1)), 0, THREATENED_THRESHOLD);
302  }
303 
304  //------------------------------------------------------------------------------------------------
307  void ThreatProjectileFlyby(int count)
308  {
309  #ifdef AI_DEBUG
310  AddDebugMessage(string.Format("ThreatProjectileFlyby"));
311  #endif
312 
313  m_fThreatSuppression = Math.Clamp(m_fThreatSuppression + count * SUPPRESSION_BULLET_INCREMENT, 0, 1);
314  }
315 
316  //------------------------------------------------------------------------------------------------
319  void DebugPrintToWidget(TextWidget w)
320  {
321  w.SetText(
322  typename.EnumToString(EAIThreatState, m_State) + "\n "
323  + m_fThreatTotal.ToString(1,4) + "\n "
324  + m_fThreatSuppression.ToString(1,4) + "\n "
325  + m_fThreatShotsFired.ToString(1,4) + "\n "
326  + m_fThreatInjury.ToString(1,4) + "\n "
327  + m_fThreatIsEndangered.ToString(1,4));
328  ;
329  }
330 
331  #ifdef AI_DEBUG
332  //--------------------------------------------------------------------------------------------
333  protected void AddDebugMessage(string str)
334  {
335  m_Utility.m_AIInfo.AddDebugMessage(str, msgType: EAIDebugMsgType.THREAT);
336  }
337  #endif
338 }
SCR_AIDebugVisualization
Definition: SCR_AIDebugVisualization.c:9
SCR_AIThreatStateChangedCallback
void SCR_AIThreatStateChangedCallback(EAIThreatState prevState, EAIThreatState newState)
ALERTED
@ ALERTED
Definition: SCR_AIThreatSystem.c:9
EAIDebugMsgType
EAIDebugMsgType
Definition: SCR_AIDebugMessage.c:1
m_Agent
SCR_ChimeraAIAgent m_Agent
Definition: SCR_AIActivitySmokeCoverFeature.c:42
HitZone
Definition: HitZone.c:12
func
func
Definition: SCR_AIThreatSystem.c:5
SAFE
@ SAFE
Definition: SCR_AIThreatSystem.c:7
EAIDebugCategory
EAIDebugCategory
Definition: SCR_AIWorld.c:11
SCR_ChimeraAIAgent
Definition: SCR_ChimeraAIAgent.c:5
distance
float distance
Definition: SCR_DestructibleTreeV2.c:29
THREATENED
@ THREATENED
Definition: SCR_AIThreatSystem.c:10
SCR_AIThreatStateChangedInvoker
ScriptInvokerBase< SCR_AIThreatStateChangedCallback > SCR_AIThreatStateChangedInvoker
Definition: SCR_AIThreatSystem.c:15
VIGILANT
@ VIGILANT
Definition: SCR_AIThreatSystem.c:8
m_State
private EEditableEntityState m_State
Definition: SCR_BaseEntitiesEditorUIEffect.c:3
EDamageType
EDamageType
Definition: EDamageType.c:12
m_DamageManager
DamageManagerComponent m_DamageManager
Definition: SCR_AITargetInfo.c:19
SCR_AIThreatSystem
Definition: SCR_AIThreatSystem.c:17
ShowDebug
proto external void ShowDebug(bool bEnable)
Show/ hide debug items (camera, map sizes)