Dayz Explorer  1.24.157551 (v105080)
Dayz Code Explorer by Zeroy
effectarea.c
Go to the documentation of this file.
1 // Mostly used for better readability
3 {
4  STATIC = 1,
5  DYNAMIC = 2
6 }
7 
8 // Class used for parameter transfer, all of the params are shadows of EffectArea member variables
9 class EffectAreaParams
10 {
11  string m_ParamName = "Default setup";
12  string m_ParamTriggerType = "ContaminatedTrigger";
13  float m_ParamRadius = 100;
14  float m_ParamPosHeight = 25;
15  float m_ParamNegHeight = 10;
18  bool m_ParamOuterToggle = true;
23  /*
24  int m_ParamPartId = ParticleList.CONTAMINATED_AREA_GAS_BIGASS;
25  int m_ParamAroundPartId = ParticleList.CONTAMINATED_AREA_GAS_AROUND;
26  int m_ParamTinyPartId = ParticleList.CONTAMINATED_AREA_GAS_TINY;
27  */
28  int m_ParamPartId = 0;
31 
32  string m_ParamPpeRequesterType = "PPERequester_ContaminatedAreaTint";
33 }
34 
35 // Base class for contaminated and other "Effect" areas
37 {
38  // Area Data
39  string m_Name = "Default setup"; // The user defined name of the area
40  int m_Type = eZoneType.STATIC; // If the zone is static or dynamic
41  vector m_Position; // World position of Area
42 
43  // Trigger Data
44  float m_Radius = 100; // Radius of the Contaminated Area
45  float m_PositiveHeight = 25; // Distance between center and maximum height
46  float m_NegativeHeight = 10; // Distance between center and minimum height
47 
48  // PCG parameters
49  // Inner Particle data
50  int m_InnerRings = 1; // The amount of inner rings one wants
51  int m_InnerSpacing = 35; // Distance between two particles placed on inner rings of the area
52  // Outer particle data
53  bool m_OuterRingToggle = true; // Allow disabling outer ring if undesired
54  int m_OuterRingOffset = -5; // Distance between the outermost ring of particles and area radius
55  int m_OuterSpacing = 20; // Distance between two particles placed on the outer most ring of the area
56  // Verticality handling
57  int m_VerticalLayers = 0; // Used to add multiple layers vertically and set vertical spacing ( 0 don't do anything )
58  int m_VerticalOffset = 10; // Used to determine vertical offset between two vertical layers
59 
60  // Particles and visual effects
61  int m_ParticleID = ParticleList.CONTAMINATED_AREA_GAS_BIGASS;
62  int m_AroundParticleID = ParticleList.CONTAMINATED_AREA_GAS_AROUND;
63  int m_TinyParticleID = ParticleList.CONTAMINATED_AREA_GAS_TINY;
64  string m_PPERequesterType;
65  int m_PPERequesterIdx = -1;
66  int m_EffectsPriority; // When multiple areas overlap, only the area with the highest priority will play its effects
67 
68  // Other values and storage
69  string m_TriggerType = "ContaminatedTrigger"; // The trigger class used by this zone
70  EffectTrigger m_Trigger; // The trigger used to determine if player is inside toxic area
71 
72  ref array<Particle> m_ToxicClouds; // All static toxic clouds in ContaminatedArea
73 
74 
75  // ----------------------------------------------
76  // INITIAL SETUP
77  // ----------------------------------------------
78 
79  void EffectArea()
80  {
81  RegisterNetSyncVariableFloat("m_Radius", 0, 0, 2);
82  RegisterNetSyncVariableFloat("m_PositiveHeight", 0, 0, 2);
83  RegisterNetSyncVariableFloat("m_NegativeHeight", 0, 0, 2);
84 
85  RegisterNetSyncVariableInt("m_InnerRings");
86  RegisterNetSyncVariableInt("m_InnerSpacing");
87  RegisterNetSyncVariableInt("m_OuterRingOffset");
88  RegisterNetSyncVariableInt("m_OuterSpacing");
89  RegisterNetSyncVariableInt("m_VerticalLayers");
90  RegisterNetSyncVariableInt("m_VerticalOffset");
91 
92  RegisterNetSyncVariableInt("m_ParticleID");
93  /*
94  RegisterNetSyncVariableInt("m_AroundParticleID");
95  RegisterNetSyncVariableInt("m_TinyParticleID");
96  RegisterNetSyncVariableInt("m_PPERequesterIdx");
97  */
98  RegisterNetSyncVariableBool("m_OuterRingToggle");
99  }
100 
101  void ~EffectArea()
102  {
103 
104  }
105 
106  void SetupZoneData( EffectAreaParams params )
107  {
108  // A lot of branching, allowing to use default values on specified params
109  if ( params.m_ParamName != "" )
110  m_Name = params.m_ParamName;
111  if ( params.m_ParamTriggerType != "" )
112  m_TriggerType = params.m_ParamTriggerType;
113 
114  if ( params.m_ParamRadius > 0 )
115  m_Radius = params.m_ParamRadius;
116  if ( params.m_ParamPosHeight > -1 )
117  m_PositiveHeight = params.m_ParamPosHeight;
118  if ( params.m_ParamNegHeight > -1 )
119  m_NegativeHeight = params.m_ParamNegHeight;
120 
121  m_InnerRings = params.m_ParamInnerRings;
122  if ( params.m_ParamInnerSpace > -1 )
123  m_InnerSpacing = params.m_ParamInnerSpace;
124 
125  m_OuterRingToggle = params.m_ParamOuterToggle;
126  if ( params.m_ParamOuterSpace > -1 )
127  m_OuterSpacing = params.m_ParamOuterSpace;
128  m_OuterRingOffset = params.m_ParamOuterOffset;
129 
130  if ( params.m_ParamVertLayers > 0 )
131  m_VerticalLayers = params.m_ParamVertLayers;
132  if ( params.m_ParamVerticalOffset > 0 )
133  m_VerticalOffset = params.m_ParamVerticalOffset;
134 
135  m_ParticleID = params.m_ParamPartId;
136  m_AroundParticleID = params.m_ParamAroundPartId;
137  m_TinyParticleID = params.m_ParamTinyPartId;
138 
139  if ( params.m_ParamPpeRequesterType != "" )
140  {
141  m_PPERequesterType = params.m_ParamPpeRequesterType;
142  m_PPERequesterIdx = GetRequesterIndex(m_PPERequesterType);
143  }
144  // We get the PPE index for future usage and synchronization
145 
146 
147  // DEVELOPER NOTE :
148  // If you cannot register a new requester, add your own indexation and lookup methods to get an index and synchronize it
149  // EXAMPLE : m_PPERequesterIdx = MyLookupMethod()
150 
151  // We sync our data
152  SetSynchDirty();
153 
154  // Now that everything is ready, we finalize setup
155  InitZone();
156  }
157 
158  void Tick() {};
159 
160 
161  // Through this we will evaluate the resize of particles
162  override void OnCEUpdate()
163  {
164  super.OnCEUpdate();
165  Tick();
166  }
167 
168  void InitZone()
169  {
170  //Debug.Log("------------------------------------------");
171  //Debug.Log( "We have created the zone : " + m_Name );
172 
173  m_Position = GetWorldPosition();
174 
175  if ( !GetGame().IsDedicatedServer() )
176  {
177  InitZoneClient();
178  }
179 
180  if ( GetGame().IsServer() )
181  {
182  InitZoneServer();
183  }
184 
185  //Debug.Log("------------------------------------------");
186  }
187 
188  // The following methods are to be overriden to execute specifc logic
189  // Each method is executed where it says it will so no need to check for server or client ;)
190  void InitZoneServer() {};
191 
192  void InitZoneClient() {};
193 
194  // ----------------------------------------------
195  // INTERACTION SETUP
196  // ----------------------------------------------
197 
198  override bool CanPutInCargo( EntityAI parent )
199  {
200  return false;
201  }
202 
203  override bool CanPutIntoHands( EntityAI parent )
204  {
205  return false;
206  }
207 
208  override bool DisableVicinityIcon()
209  {
210  return true;
211  }
212 
213  override bool CanBeTargetedByAI( EntityAI ai )
214  {
215  return false;
216  }
217 
218  // ----------------------------------------------
219  // PARTICLE GENERATION
220  // ----------------------------------------------
221  // Used to position all particles procedurally
222  void PlaceParticles( vector pos, float radius, int nbRings, int innerSpacing, bool outerToggle, int outerSpacing, int outerOffset, int partId )
223  {
224 #ifdef NO_GUI
225  return; // do not place any particles if there is no GUI
226 #endif
227  if (partId == 0)
228  {
229  Error("[WARNING] :: [EffectArea PlaceParticles] :: no particle defined, skipping area particle generation" );
230  return;
231  }
232  // Determine if we snap first layer to ground
233  bool snapFirstLayer = true;
234  if ( m_Type == eZoneType.STATIC && pos[1] != GetGame().SurfaceRoadY( pos[0], pos[2] ) )
235  snapFirstLayer = false;
236 
237  // BEGINNING OF SAFETY NET
238  // We want to prevent divisions by 0
239  if ( radius == 0 )
240  {
241  // In specific case of radius, we log an error and return as it makes no sense
242  Error("[WARNING] :: [EffectArea PlaceParticles] :: Radius of contaminated zone is set to 0, this should not happen");
243  return;
244  }
245 
246  if ( outerToggle && radius == outerOffset )
247  {
248  Error("[WARNING] :: [EffectArea PlaceParticles] :: Your outerOffset is EQUAL to your Radius, this will result in division by 0");
249  return;
250  }
251 
252  // Inner spacing of 0 would cause infinite loops as no increment would happen
253  if ( innerSpacing == 0 )
254  innerSpacing = 1;
255 
256  // END OF SAFETY NET
257 
258  int partCounter = 0; // Used for debugging, allows one to know how many emitters are spawned in zone
259  int numberOfEmitters = 1; // We always have the central emitter
260 
261  //Debug.Log("We have : " + nbRings + " rings");
262  //Debug.Log("We have : " + m_VerticalLayers + " layers");
263 
264  float angle = 0; // Used in for loop to know where we are in terms of angle spacing ( RADIANS )
265 
266  ParticlePropertiesArray props = new ParticlePropertiesArray();
267 
268  // We also populate vertically, layer 0 will be snapped to ground, subsequent layers will see particles floating and relevant m_VerticalOffset
269  for ( int k = 0; k <= m_VerticalLayers; k++ )
270  {
271  vector partPos = pos;
272  // We prevent division by 0
273  // We don't want to tamper with ground layer vertical positioning
274  if ( k != 0 )
275  {
276  partPos[1] = partPos[1] + ( m_VerticalOffset * k );
277  }
278 
279  // We will want to start by placing a particle at center of area
280  props.Insert(ParticleProperties(partPos, ParticlePropertiesFlags.PLAY_ON_CREATION, null, vector.Zero, this));
281  partCounter++;
282 
283  // For each concentric ring, we place a particle emitter at a set offset
284  for ( int i = 1; i <= nbRings + outerToggle; i++ )
285  {
286  //Debug.Log("We are on iteration I : " + i );
287 
288  // We prepare the variables to use later in calculation
289  float angleIncrement; // The value added to the offset angle to place following particle
290  float ab; // Length of a side of triangle used to calculate particle positionning
291  vector temp = vector.Zero; // Vector we rotate to position next spawn point
292 
293  // The particle density is not the same on the final ring which will only happen if toggled
294  // Toggle uses bool parameter treated as int, thus i > nbRings test ( allows to limit branching )
295  if ( i > nbRings )
296  {
297  ab = radius - outerOffset; // We want to leave some space to better see area demarcation
298 
299  // We calculate the rotation angle depending on particle spacing and distance from center
300  angleIncrement = Math.Acos( 1 - ( ( outerSpacing * outerSpacing ) / ( 2 * Math.SqrInt(ab) ) ) );
301  temp[2] = temp[2] + ab;
302 
303  //Debug.Log("Radius of last circle " + i + " is : " + ab);
304  }
305  else
306  {
307  ab = ( radius / ( nbRings + 1 ) ) * i; // We add the offset from one ring to another
308 
309  // We calculate the rotation angle depending on particle spacing and distance from center
310  angleIncrement = Math.Acos( 1 - ( ( innerSpacing * innerSpacing ) / ( 2 * Math.SqrInt(ab) ) ) );
311  temp[2] = temp[2] + ab;
312 
313  //Debug.Log("Radius of inner circle " + i + " is : " + ab);
314  }
315 
316  for ( int j = 0; j <= ( Math.PI2 / angleIncrement ); j++ )
317  {
318  // Determine position of particle emitter
319  // Use offset of current ring for vector length
320  // Use accumulated angle for vector direction
321 
322  float sinAngle = Math.Sin( angle );
323  float cosAngle = Math.Cos( angle );
324 
325  partPos = vector.RotateAroundZero( temp, vector.Up, cosAngle, sinAngle );
326  partPos += pos;
327 
328  // We snap first layer to ground if specified
329  if ( k == 0 && snapFirstLayer == true )
330  partPos[1] = GetGame().SurfaceY( partPos[0], partPos[2] );
331  else if ( k == 0 && snapFirstLayer == false )
332  partPos[1] = partPos[1] - m_NegativeHeight;
333 
334  // We check the particle is indeed in the trigger to make it consistent
335  if ( partPos[1] <= pos[1] + m_PositiveHeight && partPos[1] >= pos[1] - m_NegativeHeight )
336  {
337  // Place emitter at vector end ( coord )
338  props.Insert(ParticleProperties(partPos, ParticlePropertiesFlags.PLAY_ON_CREATION, null, GetGame().GetSurfaceOrientation( partPos[0], partPos[2] ), this));
339 
340  ++partCounter;
341  }
342 
343  // Increase accumulated angle
344  angle += angleIncrement;
345  }
346 
347  angle = 0; // We reset our accumulated angle for the next ring
348  }
349  }
350 
351  m_ToxicClouds.Reserve(partCounter);
352 
353  ParticleManager gPM = ParticleManager.GetInstance();
354 
355  array<ParticleSource> createdParticles = gPM.CreateParticlesByIdArr(partId, props, partCounter);
356  if (createdParticles.Count() != partCounter)
357  {
358  if (gPM.IsFinishedAllocating())
359  {
360  ErrorEx(string.Format("Not enough particles in pool for EffectArea: %1", m_Name));
361  OnParticleAllocation(gPM, createdParticles);
362  }
363  else
364  {
365  gPM.GetEvents().Event_OnAllocation.Insert(OnParticleAllocation);
366  }
367  }
368  else
369  {
370  OnParticleAllocation(gPM, createdParticles);
371  }
372 
373  //Debug.Log("Emitter count : " + partCounter );
374  }
375 
376  void OnParticleAllocation(ParticleManager pm, array<ParticleSource> particles)
377  {
378  foreach (ParticleSource p : particles)
379  {
380  if (p.GetOwner() == this) // Safety, since it can be unrelated particles when done through event
381  m_ToxicClouds.Insert(p);
382  }
383  }
384 
385  int GetRequesterIndex(string type)
386  {
387  typename t = type.ToType();
388  if (!t)
389  return - 1;
390  PPERequesterBase req = PPERequesterBank.GetRequester(t);
391  if (req)
392  return req.GetRequesterIDX();
393  return -1;
394  }
395 
396 
397  // ----------------------------------------------
398  // TRIGGER SETUP
399  // ----------------------------------------------
400 
401  void CreateTrigger( vector pos, int radius )
402  {
403  // The trigger pos is based on lwer end, but we want to stretch downwards
404  pos[1] = pos[1] - m_NegativeHeight;
405 
406  // Create new trigger of specified type
407  if ( Class.CastTo( m_Trigger, GetGame().CreateObjectEx( m_TriggerType, pos, ECE_NONE ) ) )
408  {
409  // We finalize trigger dimension setup
410  m_Trigger.SetCollisionCylinder( radius, ( m_NegativeHeight + m_PositiveHeight ) );
411 
412  // If the trigger is lower in hierarchy and can see it's local effects customized, we pass the new parameters
413  if ( m_Trigger.IsInherited( EffectTrigger ) )
414  {
415  //Debug.Log("We override area local effects");
416  EffectTrigger.Cast( m_Trigger ).SetLocalEffects( m_AroundParticleID, m_TinyParticleID, m_PPERequesterIdx );
417  }
418  m_Trigger.Init(this, m_EffectsPriority);
419  //Debug.Log("We created the trigger at : " + m_Trigger.GetWorldPosition() );
420  }
421  }
422 
423  // ----------------------------------------------
424  // AREA DELETION
425  // ----------------------------------------------
426 
427  override void EEDelete( EntityAI parent )
428  {
429  if ( m_Trigger )
430  {
431  GetGame().ObjectDelete( m_Trigger );
432  }
433 
434  // We stop playing particles on this client when the base object is deleted ( out of range for example )
435  if ( (GetGame().IsClient() || !GetGame().IsMultiplayer()) && m_ToxicClouds )
436  {
437  foreach ( Particle p : m_ToxicClouds )
438  {
439  p.Stop();
440  }
441  }
442 
443  super.EEDelete( parent );
444  }
445 
446  void OnPlayerEnterServer(PlayerBase player, EffectTrigger trigger)
447  {
448  player.IncreaseEffectAreaCount();
449  }
450  void OnPlayerExitServer(PlayerBase player, EffectTrigger trigger)
451  {
452  player.DecreaseEffectAreaCount();
453  }
454 
455 }
eZoneType
eZoneType
Definition: effectarea.c:2
GetGame
proto native CGame GetGame()
m_ParamName
enum eZoneType m_ParamName
m_ParamPartId
int m_ParamPartId
Definition: effectarea.c:28
m_ParamVerticalOffset
int m_ParamVerticalOffset
Definition: effectarea.c:22
DYNAMIC
@ DYNAMIC
Definition: effectarea.c:5
Error
void Error(string err)
Messagebox with error message.
Definition: endebug.c:90
Particle
Legacy way of using particles in the game.
Definition: particle.c:6
STATIC
@ STATIC
Definition: effectarea.c:4
m_Type
eBleedingSourceType m_Type
Definition: bleedingsource.c:25
m_ParamRadius
float m_ParamRadius
Definition: effectarea.c:13
m_Position
protected vector m_Position
Cached world position.
Definition: effect.c:41
m_ParamPpeRequesterType
string m_ParamPpeRequesterType
Definition: effectarea.c:32
m_ParamOuterSpace
int m_ParamOuterSpace
Definition: effectarea.c:19
m_Name
string m_Name
Definition: bioslobbyservice.c:35
m_ParamInnerSpace
int m_ParamInnerSpace
Definition: effectarea.c:17
m_Radius
float m_Radius
Definition: aigroupbehaviour.c:10
m_ParamPosHeight
float m_ParamPosHeight
Definition: effectarea.c:14
m_ParamAroundPartId
int m_ParamAroundPartId
Definition: effectarea.c:29
ErrorEx
enum ShapeType ErrorEx
m_ParamInnerRings
int m_ParamInnerRings
Definition: effectarea.c:16
EffectArea
Definition: effectarea.c:36
m_ParamOuterToggle
bool m_ParamOuterToggle
Definition: effectarea.c:18
ParticleList
Definition: particlelist.c:11
PlayerBase
Definition: playerbaseclient.c:1
vector
Definition: enconvert.c:105
ECE_NONE
const int ECE_NONE
Definition: centraleconomy.c:7
m_ParamOuterOffset
int m_ParamOuterOffset
Definition: effectarea.c:20
m_ParamVertLayers
int m_ParamVertLayers
Definition: effectarea.c:21
m_ParamNegHeight
float m_ParamNegHeight
Definition: effectarea.c:15
PPERequesterBase
Definition: pperequestplatformsbase.c:2
House
Definition: crashbase.c:1
array< Particle >
ParticleSource
Entity which has the particle instance as an ObjectComponent.
Definition: particlesource.c:123
m_ParamTinyPartId
int m_ParamTinyPartId
Definition: effectarea.c:30
m_ParamTriggerType
string m_ParamTriggerType
Definition: effectarea.c:12
EffectTrigger
Definition: contaminatedtrigger.c:2
Math
Definition: enmath.c:6
ParticleManager
void ParticleManager(ParticleManagerSettings settings)
Constructor (ctor)
Definition: particlemanager.c:84
Class
Super root of all classes in Enforce script.
Definition: enscript.c:10
EntityAI
Definition: building.c:5