Dayz Explorer  1.24.157551 (v105080)
Dayz Code Explorer by Zeroy
trigger.c
Go to the documentation of this file.
1 class TriggerInsider
3 {
4  ref OLinkT insider; // DEPRECATED
5 
7  protected Object m_Object;
8 
10  int timeStamp;
11 
13  float timeEntered;
14 
16  float lastUpdated;
17 
18  void TriggerInsider(Object obj)
19  {
20  insider = new OLinkT(obj);
21  m_Object = obj;
22  }
23 
24  void ~TriggerInsider()
25  {
26  }
27 
28  Object GetObject()
29  {
30  return m_Object;
31  }
32 };
33 
34 #ifdef DIAG_DEVELOPER
35 typedef Param7<vector, vector, vector, vector, float, string, array<ref TriggerInsider>> DebugTriggerInfo;
36 #endif
37 
39 class Trigger : TriggerEvents
40 {
42  const int TIMEOUT = 1000;
44  ref array<ref TriggerInsider> m_insiders;
45 
46  #ifdef DIAG_DEVELOPER
47  bool m_Local;//is this trigger spawning on client only ?
48  string m_DebugAreaType;
49  ref array<ref TriggerInsider> m_dbgInsiders;
50  #endif
51 
53  private void Trigger()
54  {
55  SetEventMask(EntityEvent.INIT /*| EntityEvent.TOUCH*/ | EntityEvent.FRAME | EntityEvent.ENTER | EntityEvent.LEAVE );
56  SetFlags(EntityFlags.TRIGGER, false);
57 
58  m_insiders = new array<ref TriggerInsider>;
59  }
60 
62  private void ~Trigger()
63  {
64  #ifdef DIAG_DEVELOPER
65  CleanupDebugShapes(dbgTargets);
66  #endif
67  }
68 
73  override void EOnInit(IEntity other, int extra)
75  {
76  SetExtents("-2 -4 -2", "2 4 2");
77  }
78 
80  /*override void EOnTouch(IEntity other, int extra)
81  {
82  Object obj;
83  if (Class.CastTo(obj, other) && CanAddObjectAsInsider(obj))
84  AddInsider(obj);
85  }*/
86 
88  override void EOnFrame(IEntity other, float timeSlice)
89  {
90  UpdateInsiders(TIMEOUT);
91  }
92 
94  override void EOnEnter(IEntity other, int extra)
95  {
96  Object obj;
97  if (Class.CastTo(obj, other) && CanAddObjectAsInsider(obj))
98  AddInsider(obj);
99  }
100 
102  override void EOnLeave(IEntity other, int extra)
103  {
104  Object obj;
105  if (Class.CastTo(obj, other))
106  RemoveInsiderByObject(obj);
107  }
109 
110 
115  void SetExtents(vector mins, vector maxs)
117  {
118  SetCollisionBox(mins, maxs);
119  }
120 
122  float GetRadius(vector min, vector max)
123  {
124  return GetCollisionRadius();
125  }
126 
128  array<ref TriggerInsider> GetInsiders()
129  {
130  return m_insiders;
131  }
132 
134  TriggerInsider GetInsiderForObject(Object object)
135  {
136  TriggerInsider ins;
137 
138  for ( int n = 0; n < m_insiders.Count(); ++n )
139  {
140  ins = m_insiders[n];
141  if (ins.GetObject() == object)
142  return ins;
143  }
144 
145  return null;
146  }
147 
149  int GetInsiderIndexForObject(Object object)
150  {
151  TriggerInsider ins;
152 
153  for ( int n = 0; n < m_insiders.Count(); ++n )
154  {
155  ins = m_insiders[n];
156  if (ins.GetObject() == object)
157  return n;
158  }
159 
160  return -1;
161  }
163 
164 
169  override protected void OnEnterBeginEvent(TriggerInsider insider)
170  {
171  // Call the old event for backwards compatibility
172  OnEnter(insider.GetObject());
173  }
174 
175  override protected void OnLeaveBeginEvent(TriggerInsider insider)
176  {
177  // Call the old event for backwards compatibility
178  OnLeave(insider.GetObject());
179  }
181 
182 
187  void OnEnter(Object obj) {}
188 
189  void OnLeave(Object obj) {}
191 
192 
197  protected bool CanAddObjectAsInsider(Object object)
199  {
200  return true;
201  }
202 
204  protected bool ShouldRemoveInsider(TriggerInsider insider)
205  {
206  return false;
207  }
208 
210  protected bool ShouldRemoveInsiderNoLeave(TriggerInsider insider)
211  {
212  return false;
213  }
215 
216 
221  protected TriggerInsider CreateInsider(Object obj)
223  {
224  return new TriggerInsider(obj);
225  }
226 
228  protected void AddInsider(Object obj)
229  {
230  if ( !obj )
231  return;
232 
233  // Already in?
234  if ( GetInsiderForObject( obj ) )
235  {
236  Error(string.Format("[WARNING] :: [Trigger] :: [%1] :: Insider (%2) is already inside.", GetDebugName(this), GetDebugName(obj)));
237  return;
238  }
239 
240  // New Object entered! Fill the data.
241  TriggerInsider insider = CreateInsider(obj);
242  insider.timeStamp = g_Game.GetTime();
243  insider.timeEntered = g_Game.GetTickTime();
244  insider.lastUpdated = insider.timeEntered;
245 
246  // Don't add if it is going to be removed anyways..
247  if ( ShouldRemoveInsider(insider) || ShouldRemoveInsiderNoLeave(insider) )
248  return;
249 
250  // Keep track of the Object as long as it is inside the Trigger
251  int index = m_insiders.Insert(insider);
252 
253  // Call the enter event to signal this Object entered
254  Enter(insider);
255  obj.OnEnterTrigger(this);
256 
257  #ifdef TRIGGER_DEBUG_NORMAL
258  Debug.TriggerLog(string.Format("%1: inserted at index %2", GetDebugName(obj), index), "Trigger", "", "AddInsider", GetDebugName(this));
259  #endif
260  }
261 
263  protected void RemoveInsider(TriggerInsider insider, int index = -1)
264  {
265  Leave(insider);
266  insider.GetObject().OnLeaveTrigger(this);
267 
268  #ifdef TRIGGER_DEBUG_NORMAL
269  Debug.TriggerLog(string.Format("%1: removing at index %2", GetDebugName(insider.GetObject()), index), "Trigger", "", "RemoveInsider", GetDebugName(this));
270  #endif
271 
272  if (index >= 0)
273  m_insiders.Remove(index);
274  else
275  m_insiders.RemoveItemUnOrdered(insider);
276  }
277 
279  protected void RemoveInsiderByObject(Object object)
280  {
281  TriggerInsider ins;
282  for ( int n = 0; n < m_insiders.Count(); ++n )
283  {
284  ins = m_insiders[n];
285  if (ins.GetObject() == object)
286  {
287  RemoveInsider(ins, n);
288  return;
289  }
290  }
291 
292  // As EOnLeave can call this, it is perfectly valid that this Object is not found on Script side
293  // because of "ShouldRemoveInsider" and "ShouldRemoveInsiderNoLeave"
294  }
295 
297  protected void UpdateInsiders(int timeout)
298  {
299  #ifdef DIAG_DEVELOPER
300  DebugSendDmgTrigger();
301  #endif
302 
303  // Don't do anything if there aren't any insiders
304  if ( m_insiders.Count() == 0 )
305  return;
306 
307  // Mark the beginning of the update loop
308  StayStart(m_insiders.Count());
309 
310  // Iterate over the current insiders, backwards because we are deleting
311  for ( int n = m_insiders.Count() - 1; n >= 0 ; --n)
312  {
313  TriggerInsider insider = m_insiders.Get(n);
314  Object obj = insider.GetObject();
315 
316  // Check if the Object still exists or should be removed without calling OnLeaveEvent
317  if ( !obj || ShouldRemoveInsiderNoLeave(insider) )
318  {
319  #ifdef TRIGGER_DEBUG_BASIC
320  Debug.TriggerLog(string.Format("%1: removed with no Leave.", GetDebugName(obj)), "Trigger", "", "UpdateInsiders", GetDebugName(this));
321  #endif
322 
323  m_insiders.Remove(n);
324  continue;
325  }
326 
327  // Check if Object left the Trigger or should be removed regardless
328  if ( ShouldRemoveInsider(insider) )
329  {
330  RemoveInsider(insider, n);
331  continue;
332  }
333 
334  // Call the OnStayEvent, Object is still inside the Trigger and can be updated
335  // Pass in the time since the Object was last updated (or entered)
336  float currentTime = g_Game.GetTickTime();
337  Stay(insider, currentTime - insider.lastUpdated);
338  insider.lastUpdated = currentTime;
339  }
340 
341  // Mark the end of the update loop
342  StayFinish();
343  }
345 
350  override void OnRPC(PlayerIdentity sender, int rpc_type, ParamsReadContext ctx)
351  {
352  super.OnRPC(sender, rpc_type, ctx);
353 
354  #ifdef DIAG_DEVELOPER
355  switch (rpc_type)
356  {
357  case ERPCs.DIAG_TRIGGER_DEBUG:
358  DebugTriggerInfo data = new DebugTriggerInfo(vector.Zero, vector.Zero, vector.Zero, vector.Zero, 0, "", null);
359 
360  if (ctx.Read(data))
361  DebugDmgTrigger(data.param1, data.param2, data.param3, data.param4, data.param5, data.param6, data.param7);
362  break;
363  }
364  #endif
365  }
366 
367 #ifdef DIAG_DEVELOPER
368  void DebugSendDmgTrigger()
369  {
370  vector minmax[2];
371  GetCollisionBox(minmax);
372 
373  DebugTriggerInfo data = new DebugTriggerInfo(vector.Zero, vector.Zero, vector.Zero, vector.Zero, 0, "", null);
374  data.param1 = GetWorldPosition();
375  data.param2 = GetOrientation();
376  data.param3 = minmax[0];
377  data.param4 = minmax[1];
378  data.param5 = GetCollisionRadius();
379  data.param6 = m_DebugAreaType;
380  data.param7 = m_insiders;
381 
382  if (GetGame().IsMultiplayer() && GetGame().IsServer())
383  PluginDiagMenuServer.SendDataToSubscribersServer(this, ESubscriberSystems.TRIGGERS, ERPCs.DIAG_TRIGGER_DEBUG, data, false);
384  else if (!GetGame().IsMultiplayer() || m_Local)
385  DebugDmgTrigger(data.param1, data.param2, data.param3, data.param4, data.param5, data.param6, data.param7);
386  }
387 
388  protected ref array<Shape> dbgTargets = new array<Shape>();
389 
390  void DebugDmgTrigger( vector pos, vector orientation, vector min, vector max, float radius, string dmgType, array<ref TriggerInsider> insiders)
391  {
392  CleanupDebugShapes(dbgTargets);
393 
394  bool enableDebug = DiagMenu.GetBool(DiagMenuIDs.TRIGGER_DEBUG);
395  if (enableDebug)
396  {
397  if (GetGame().IsMultiplayer() && GetGame().IsServer())
398  {
399  return;
400  }
401 
402  vector w_pos, w_pos_sphr, w_pos_lend;
403 
404  w_pos = pos;
405  // sphere pos tweaks
406  w_pos_sphr = w_pos;
407  // line pos tweaks
408  w_pos_lend = w_pos;
409 
410  //Find way to change colour of box depending on ammoType in a more elegant fashion
411  m_DebugAreaType = dmgType;
412  Shape dbgShape;
413 
414  switch ( m_DebugAreaType )
415  {
416  case "FireDamage":
417  dbgShape = DrawDebugShape(pos, min, max, radius, COLOR_RED_A);
418  break;
419 
420  case "BarbedWireHit":
421  dbgShape = DrawDebugShape(pos, min, max, radius, COLOR_BLUE_A);
422  break;
423 
424  default:
425  dbgShape = DrawDebugShape(pos, min, max, radius, COLOR_GREEN_A);
426  break;
427  }
428 
429  if (GetGame().IsMultiplayer() || GetGame().IsServer())
430  m_dbgInsiders = insiders;
431 
432  if (m_dbgInsiders.Count() > 0)
433  {
434  //Change colour to make state clearer
435  dbgShape.SetColor(COLOR_YELLOW_A);
436 
437  for (int i = 0; i < m_dbgInsiders.Count(); i++)
438  {
439  EntityAI insider_EAI = EntityAI.Cast(m_dbgInsiders[i].GetObject());
440  if (insider_EAI)
441  {
442  vector insiderPos = insider_EAI.GetWorldPosition() + "0 0.1 0";
443  dbgTargets.Insert(Debug.DrawArrow(w_pos, insiderPos));
444  }
445  }
446  }
447  }
448  }
449 
450  protected Shape DrawDebugShape(vector pos, vector min, vector max, float radius, int color)
451  {
452  Shape dbgShape;
453 
454  switch (GetTriggerShape())
455  {
456  case TriggerShape.BOX:
457  dbgShape = Debug.DrawBoxEx(min, max, color, ShapeFlags.TRANSP|ShapeFlags.NOZWRITE);
458 
459  vector mat[4];
460  GetTransform(mat);
461  dbgShape.CreateMatrix(mat);
462  dbgShape.SetMatrix(mat);
463  break;
464  case TriggerShape.CYLINDER:
465  dbgShape = Debug.DrawCylinder(pos, radius, max[1], color, ShapeFlags.TRANSP|ShapeFlags.NOZWRITE);
466  break;
467  case TriggerShape.SPHERE:
468  dbgShape = Debug.DrawSphere(pos, radius, color, ShapeFlags.TRANSP|ShapeFlags.NOZWRITE);
469  break;
470  default:
471  ErrorEx("TriggerShape not found", ErrorExSeverity.WARNING);
472  break;
473  }
474 
475  dbgTargets.Insert(dbgShape);
476 
477  return dbgShape;
478  }
479 
480  protected void CleanupDebugShapes(array<Shape> shapes)
481  {
482  foreach (Shape shape : shapes)
483  {
484  Debug.RemoveShape(shape);
485  }
486 
487  shapes.Clear();
488  }
489 
490 #endif
491 
492 };
GetGame
proto native CGame GetGame()
OLinkT
Link< Object > OLinkT
Definition: gameplay.c:1476
Error
void Error(string err)
Messagebox with error message.
Definition: endebug.c:90
EntityFlags
EntityFlags
Entity flags.
Definition: enentity.c:114
TriggerInsider
The object which is in a trigger and its metadata.
Definition: trigger.c:2
DiagMenu
Definition: endebug.c:232
DrawDebugShape
void DrawDebugShape()
Definition: bleedingsource.c:171
TriggerEvents
Definition: triggerevents.c:3
m_Object
private Object m_Object
Definition: actiontargets.c:166
COLOR_YELLOW_A
const int COLOR_YELLOW_A
Definition: constants.c:72
SetCollisionBox
proto native void SetCollisionBox(vector mins, vector maxs)
Sets collision box for object.
COLOR_RED_A
const int COLOR_RED_A
Definition: constants.c:69
ErrorEx
enum ShapeType ErrorEx
IEntity
Definition: enentity.c:164
Serializer
Serialization general interface. Serializer API works with:
Definition: serializer.c:55
PlayerIdentity
The class that will be instanced (moddable)
Definition: gameplay.c:377
DiagMenuIDs
DiagMenuIDs
Definition: ediagmenuids.c:1
vector
Definition: enconvert.c:105
Trigger
Scripted Trigger.
Definition: hologram.c:1573
ShapeFlags
ShapeFlags
Definition: endebug.c:125
g_Game
DayZGame g_Game
Definition: dayzgame.c:3727
ErrorExSeverity
ErrorExSeverity
Definition: endebug.c:61
Object
Definition: objecttyped.c:1
COLOR_BLUE_A
const int COLOR_BLUE_A
Definition: constants.c:71
SetFlags
proto native void SetFlags(ShapeFlags flags)
array< ref TriggerInsider >
GetDebugName
override string GetDebugName()
Definition: dayzplayer.c:1126
GetObject
proto native vobject GetObject(string name)
Loads object from data, or gets it from cache. Object must be released when not used.
Debug
Definition: debug.c:13
PluginDiagMenuServer
Definition: plugindiagmenuserver.c:6
ERPCs
ERPCs
Definition: erpcs.c:1
GetTriggerShape
proto native TriggerShape GetTriggerShape()
Get the current TriggerShape.
TriggerShape
TriggerShape
Definition: scriptedentity.c:1
EntityEvent
EntityEvent
Entity events for event-mask, or throwing event from code.
Definition: enentity.c:44
Class
Super root of all classes in Enforce script.
Definition: enscript.c:10
COLOR_GREEN_A
const int COLOR_GREEN_A
Definition: constants.c:70
EntityAI
Definition: building.c:5
Shape
class DiagMenu Shape
don't call destructor directly. Use Destroy() instead
GetOrientation
vector GetOrientation()
Definition: areadamagemanager.c:306