Dayz Explorer  1.24.157551 (v105080)
Dayz Code Explorer by Zeroy
scriptedlightbase.c
Go to the documentation of this file.
1 /*
2 Please remember that:
3 -Lights work only on client side!
4 -Lights with Brightness or Radius of 0 (or less) are automatically deleted
5 -Lights are very performance heavy. Especially if they cast shadows. Use them carefully!
6 
7 Script author: Boris Vacula
8 */
9 
11 {
12  float m_LifetimeStart;
13  float m_LifetimeEnd = -1; // -1 makes this light permanent
14  float m_FadeOutTime = -1;
15  float m_FadeInTime = -1;
16  float m_Radius;
17  float m_RadiusTarget;
18  float m_Brightness;
19  float m_BrightnessPulse; // flicker effect
20  float m_BrightnessPulseSpeed;
21  float m_BrightnessPulseAmplitudeMax;
22  float m_BrightnessPulseAmplitudeMin;
23  float m_BrightnessTarget;
24  float m_BrightnessSpeedOfChange = 1;
25  float m_RadiusSpeedOfChange = 1;
26  float m_OptimizeShadowsRadius = 0; // Within this range between the light source and camera the shadows will be automatically disabled to save on performance
27 
28  float m_DancingShadowsAmplitude;
29  float m_DancingShadowsSpeed;
30 
31  float m_BlinkingSpeed;
32 
33  bool m_IsDebugEnabled = false;
34 
35  Object m_Parent; // Attachment parent
36  vector m_LocalPos; // Local position to my attachment parent
37  vector m_LocalOri; // Local orientation to my attachment parent
38  vector m_DancingShadowsLocalPos;
39 
40  ref Timer m_DeleteTimer;
41 
42  static ref set<ScriptedLightBase> m_NightTimeOnlyLights = new set<ScriptedLightBase>();
43 
45  void ScriptedLightBase()
46  {
47  m_LifetimeStart = GetGame().GetTime();
48  SetEnabled(true);
49  SetEventMask(EntityEvent.FRAME);
50  SetEventMask(EntityEvent.INIT);
51  }
52 
53  void ~ScriptedLightBase()
54  {
55  if (m_NightTimeOnlyLights)
56  {
57  int index = m_NightTimeOnlyLights.Find(this);
58  if (index != -1)
59  {
60  m_NightTimeOnlyLights.Remove(index);
61  }
62  }
63  }
64 
65  override void EOnInit(IEntity other, int extra)
66  {
67  if (!IsVisibleDuringDaylight())
68  {
69  PlayerBase player = PlayerBase.Cast(GetGame().GetPlayer());
70  if (player && player.m_UndergroundPresence)
71  SetVisibleDuringDaylight(true);
72  m_NightTimeOnlyLights.Insert(this);
73  }
74  }
75 
76  override bool IsScriptedLight()
77  {
78  return true;
79  }
80 
81  void UpdateMode()
82  {
83  ItemBase item = ItemBase.Cast(m_Parent);
84  if (item)
85  {
87  item.GetInventory().GetCurrentInventoryLocation( il );
88  string slotName;
89  if (il.GetType() == InventoryLocationType.GROUND)
90  {
91  slotName = "Ground";
92  }
93  else if (il.GetSlot() != -1)
94  {
95  slotName = InventorySlots.GetSlotName(il.GetSlot());
96  }
97  UpdateLightMode(slotName);
98  }
99  }
100 
101  private void UpdateLightMode(string slotName);
102 
104  private void DeleteLightWithDelay()
105  {
106  DetachFromParent(); // This is the reason for the delay
107 
108  if (GetGame())
109  {
110  if (!m_DeleteTimer)
112 
113  m_DeleteTimer.Run( 0.03 , this, "DeleteLightNow", NULL, true);
114  }
115 
116  }
117 
118  // Deletes light now. Do not call this directly. Call Destroy() instead. Otherwise you might get errors related to hierarchy.
119  private void DeleteLightNow()
120  {
121  GetGame().ObjectDelete(this);
122  }
123 
125  void AttachOnObject(Object parent, vector local_pos = "0 0 0", vector local_ori = "0 0 0")
126  {
127  if (!parent)
128  {
129  if (m_Parent)
130  {
131  m_Parent.RemoveChild(this);
132  }
133 
134  return;
135  }
136  else
137  {
138  if (m_Parent)
139  {
140  m_Parent.RemoveChild(this);
141  }
142  }
143 
144  m_Parent = parent;
145  m_LocalPos = local_pos;
146  m_LocalOri = local_ori;
147  SetOrientation(local_ori);
148  SetPosition(local_pos);
149  parent.AddChild(this, -1);
150  parent.Update();
151  }
152 
155  {
156  return m_Parent;
157  }
158 
160  void AttachOnMemoryPoint(Object parent, string memory_point_start, string memory_point_target = "")
161  {
162  if (parent.MemoryPointExists(memory_point_start))
163  {
164  m_LocalPos = parent.GetMemoryPointPos(memory_point_start);
165  vector local_ori;
166 
167  if (memory_point_target != "" )
168  {
169  if (parent.MemoryPointExists(memory_point_target))
170  {
171  vector target_pos = parent.GetSelectionPositionLS(memory_point_target);
172  target_pos = vector.Direction(m_LocalPos, target_pos);
173  local_ori = target_pos.VectorToAngles();
174  }
175  else
176  {
177  ErrorEx("memory point 'memory_point_target' not found when attaching light");
178  }
179  }
180  AttachOnObject(parent, m_LocalPos, local_ori);
181  UpdateMode();
182  }
183  else
184  {
185  ErrorEx("memory point 'memory_point_start' not found when attaching light");
186  }
187  }
188 
190  void DetachFromParent()
191  {
192  if (!m_Parent)
193  {
194  m_Parent = Object.Cast( GetParent() );
195  }
196 
197  if (m_Parent)
198  {
199  if ( !m_Parent.ToDelete() && !ToDelete() )
200  {
201  m_Parent.RemoveChild(this);
202  }
203  }
204 
205  m_Parent = null;
206  m_LocalPos = Vector(0,0,0);
207  m_LocalOri = Vector(0,0,0);
208  }
209 
210  static ScriptedLightBase CreateLightAtObjMemoryPoint(typename name, notnull Object target, string memory_point_start, string memory_point_target = "", vector global_pos = "0 0 0", float fade_in_time_in_s = 0)
211  {
212  ScriptedLightBase light;
213  if (target.MemoryPointExists(memory_point_start))
214  {
215  light = CreateLight(name, global_pos, fade_in_time_in_s);
216  light.AttachOnMemoryPoint(target, memory_point_start, memory_point_target);
217  }
218  return light;
219  }
220 
222  static ScriptedLightBase CreateLight(typename name, vector global_pos = "0 0 0", float fade_in_time_in_s = 0)
223  {
224  ScriptedLightBase light_instance;
225 
226  if ( !GetGame().IsServer() || !GetGame().IsMultiplayer() ) // Client side
227  {
228  light_instance = ScriptedLightBase.Cast( GetGame().CreateObject(name.ToString(), global_pos, true) );
229 
230  if (!light_instance)
231  {
232  Error("Error! Light entity of name " + name.ToString() + " cannot be spawned! This name is incorrect or not inherited from ScriptedLightBase." );
233  return null;
234  }
235 
236  if (fade_in_time_in_s != 0)
237  {
238  light_instance.FadeIn(fade_in_time_in_s);
239  }
240  }
241  else // Server side
242  {
243  if ( GetGame().IsDebug() )
244  {
245  Error("An instance of ScriptedLightBase was attempted to spawn on server side! Lights are CLIENT SIDE ONLY!");
246  }
247  }
248 
249  return light_instance;
250  }
251 
253  void SetBrightnessTo(float value)
254  {
255  m_Brightness = value;
256  m_BrightnessTarget = value;
257  SetBrightness(m_Brightness * m_BrightnessPulse);
258  CorrectLightPulseDuringDaylight();
259  }
260 
262  void CorrectLightPulseDuringDaylight()
263  {
264  if (m_Brightness < 100)
265  {
266  float v = m_Brightness * 0.01;
267 
268  if (v > 0)
269  {
270  float brightness_compesation = 1 / v;
271  float compenset_brightness = (m_Brightness * m_BrightnessPulse) * brightness_compesation;
272  SetBrightness(compenset_brightness);
273  SetPulseCoef(v);
274  }
275  }
276  else
277  {
278  SetPulseCoef(1);
279  }
280  }
281 
283  void FadeBrightnessTo( float value, float time_in_s )
284  {
285  m_BrightnessTarget = value;
286 
287  if (time_in_s == 0)
288  {
289  m_BrightnessSpeedOfChange = 9999;
290  }
291  else
292  {
293  m_BrightnessSpeedOfChange = Math.AbsFloat(m_Brightness - m_BrightnessTarget) / time_in_s;
294  }
295  }
296 
298  void SetRadiusTo(float value)
299  {
300  m_Radius = value;
301  m_RadiusTarget = value;
302  SetRadius(m_Radius);
303  }
304 
306  void FadeRadiusTo( float value, float time_in_s )
307  {
308  m_RadiusTarget = value;
309 
310  if (time_in_s == 0)
311  {
312  m_RadiusSpeedOfChange = 9999;
313  }
314  else
315  {
316  m_RadiusSpeedOfChange = Math.AbsFloat(m_Radius - m_RadiusTarget) / time_in_s;
317  }
318  }
319 
321  void Destroy()
322  {
323  ClearEventMask(EntityEvent.FRAME);
324  SetEnabled(false);
325  if (m_Parent)
326  DeleteLightWithDelay();
327  else
328  DeleteLightNow();
329  }
330 
332  void SetLifetime(float life_in_s)
333  {
334  if(GetGame())
335  m_LifetimeEnd = GetGame().GetTime() + life_in_s * 1000;
336  }
337 
339  void SetFadeOutTime(float time_in_s)
340  {
341  m_FadeOutTime = time_in_s * 1000;
342  }
343 
345  void FadeOut(float time_in_s = -1)
346  {
347  float time_in_ms = time_in_s * 1000;
348 
349  if (time_in_s == -1)
350  {
351  float kill_time_in_s = m_FadeOutTime*0.001;
352 
353  FadeBrightnessTo(0, kill_time_in_s);
354  FadeRadiusTo(0, kill_time_in_s);
355  SetLifetime(kill_time_in_s);
356  }
357  else
358  {
359  FadeBrightnessTo(0, time_in_s);
360  FadeRadiusTo(0, time_in_s);
361  SetLifetime(time_in_s);
362  }
363  }
364 
366  void FadeIn(float time_in_s)
367  {
368  float brightness = m_Brightness;
369  SetBrightnessTo(0);
370  FadeBrightnessTo(brightness, time_in_s);
371  }
372 
374  void AddLifetime(float life_in_s)
375  {
376  m_LifetimeEnd += life_in_s * 1000;
377  }
378 
380  void OnFrameLightSource(IEntity other, float timeSlice)
381  {
382  // ...
383  }
384 
386  override void EOnFrame(IEntity other, float timeSlice)
387  {
388  // Control lifetime of the light
389  int current_time = GetGame().GetTime();
390 
391  if ( CheckLifetime(current_time) )
392  {
393  SetRadius(m_Radius);
394  }
395  else
396  {
397  return;
398  }
399 
400  HandleFlickering(current_time - m_LifetimeStart, timeSlice);
401  HandleDancingShadows(current_time - m_LifetimeStart, timeSlice);
402  CheckFadeOut(current_time);
403  HandleBrightnessFadeing(timeSlice);
404  HandleRadiusFadeing(timeSlice);
405 
406  CheckIfParentIsInCargo();
407  TryShadowOptimization();
408  OnFrameLightSource(other, timeSlice);
409 
410  HandleBlinking(current_time);
411  }
412 
414  void SetDancingShadowsAmplitude(float max_deviation_in_meters)
415  {
416  m_DancingShadowsAmplitude = Math.AbsFloat(max_deviation_in_meters);
417  }
418 
420  void SetDancingShadowsMovementSpeed(float speed_in_meters_per_frame)
421  {
422  m_DancingShadowsSpeed = Math.AbsFloat(speed_in_meters_per_frame);
423  }
424 
426  float GetDancingShadowsAmplitude()
427  {
428  return m_DancingShadowsAmplitude;
429  }
430 
432  float GetDancingShadowsMovementSpeed()
433  {
434  return m_DancingShadowsSpeed;
435  }
436 
438  void EnableDebug(bool state)
439  {
440  m_IsDebugEnabled = state;
441  }
442 
443  // Handles subtle movement of the light point to create the effect of dancing shadows
444  void HandleDancingShadows(float time, float timeSlice)
445  {
446  if (m_DancingShadowsAmplitude > 0)
447  {
448  for (int i = 0; i < 3; i++ )
449  {
450  m_DancingShadowsLocalPos[i] = m_DancingShadowsLocalPos[i] + ( Math.RandomFloat(-m_DancingShadowsSpeed,m_DancingShadowsSpeed) * timeSlice) ;
451 
452  if (m_DancingShadowsLocalPos[i] > m_DancingShadowsAmplitude)
453  m_DancingShadowsLocalPos[i] = m_DancingShadowsAmplitude;
454 
455  if (m_DancingShadowsLocalPos[i] < -m_DancingShadowsAmplitude)
456  m_DancingShadowsLocalPos[i] = -m_DancingShadowsAmplitude;
457 
458  }
459 
460  if (m_Parent && !m_Parent.ToDelete())
461  {
462  // In order to move with the light, it must be detached from its parent first
463 
464  m_Parent.RemoveChild(this);
465  SetPosition(m_LocalPos + m_DancingShadowsLocalPos);
466 
467  m_Parent.AddChild(this, -1);
468  m_Parent.Update();
469  }
470 
471  if (m_IsDebugEnabled)
472  {
473  Particle p = ParticleManager.GetInstance().PlayInWorld( ParticleList.DEBUG_DOT, GetPosition() );
474  p.SetParticleParam( EmitorParam.SIZE, 0.01);
475  }
476  }
477  else
478  {
479  m_DancingShadowsLocalPos = Vector(0,0,0);
480  }
481  }
482 
483  // Updates flickering light
484  void HandleFlickering(float time, float timeSlice)
485  {
486  if (m_BrightnessPulseAmplitudeMax > 0)
487  {
488  m_BrightnessPulse += ( Math.RandomFloat(-m_BrightnessPulseSpeed, m_BrightnessPulseSpeed) ) * timeSlice;
489 
490  if (m_BrightnessPulse < m_BrightnessPulseAmplitudeMin + 1)
491  m_BrightnessPulse = m_BrightnessPulseAmplitudeMin + 1;
492 
493  if (m_BrightnessPulse > m_BrightnessPulseAmplitudeMax + 1)
494  m_BrightnessPulse = m_BrightnessPulseAmplitudeMax + 1;
495 
496  }
497  else
498  {
499  m_BrightnessPulse = 1;
500  }
501  }
502 
504  void SetFlickerSpeed(float speed)
505  {
506  m_BrightnessPulseSpeed = speed;
507  }
508 
510  void SetFlickerAmplitude(float coef)
511  {
512  m_BrightnessPulseAmplitudeMax = Math.AbsFloat(coef);
513  m_BrightnessPulseAmplitudeMin = -Math.AbsFloat(coef);
514  }
515 
516  void SetFlickerAmplitudeMax(float coef)
517  {
518  m_BrightnessPulseAmplitudeMax = coef;
519  }
520 
521  void SetFlickerAmplitudeMin(float coef)
522  {
523  m_BrightnessPulseAmplitudeMin = coef;
524  }
525 
527  float GetFlickerSpeed()
528  {
529  return m_BrightnessPulseSpeed;
530  }
531 
533  float GetFlickerAmplitudeCoefMax()
534  {
535  return m_BrightnessPulseAmplitudeMax;
536  }
537 
539  float GetFlickerAmplitudeCoefMin()
540  {
541  return m_BrightnessPulseAmplitudeMin;
542  }
543 
545  void TryShadowOptimization()
546  {
547  if (m_OptimizeShadowsRadius > 0)
548  {
549  float distance_to_camera = vector.Distance( GetPosition(), GetGame().GetCurrentCameraPosition() );
550 
551  if (distance_to_camera < m_OptimizeShadowsRadius)
552  {
553  SetCastShadow(false);
554  }
555  else
556  {
557  SetCastShadow(true);
558  }
559  }
560  }
561 
563  void SetDisableShadowsWithinRadius(float radius_in_m)
564  {
565  m_OptimizeShadowsRadius = radius_in_m;
566  }
567 
569  float GetDisableShadowsWithinRadius()
570  {
571  return m_OptimizeShadowsRadius;
572  }
573 
574  void CheckIfParentIsInCargo()
575  {
576  // TO DO: OPTIMIZE AND REFACTOR! THIS MUST BE HANDLED IN AN EVENT, NOT PER FRAME!
577 
578  if (m_Parent)
579  {
580  EntityAI parent_EAI = EntityAI.Cast( m_Parent );
581 
582  if (parent_EAI) // Check if the Cast was successfull
583  {
584  GameInventory GI = parent_EAI.GetInventory();
585 
586  if (GI) // Prevents handling of light on the parent item when it's projected in inventory as the item in inventory character's hands.
587  {
588  bool is_in_cargo = GI.IsInCargo();
589 
590  if (!is_in_cargo)
591  {
592  EntityAI parent2 = parent_EAI.GetHierarchyParent();
593 
594  if (parent2 && parent2.GetInventory())
595  {
596  is_in_cargo = parent2.GetInventory().IsInCargo();
597  }
598  }
599 
600  if ( is_in_cargo )
601  {
602  SetEnabled(false);
603  }
604  else
605  {
606  SetEnabled(true);
607  }
608  }
609  }
610  }
611  }
612 
613  // Destroys this light if it's past it lifetime
614  private bool CheckLifetime(int current_time)
615  {
616  if ( current_time > m_LifetimeEnd && m_LifetimeEnd != -1 )
617  {
618  Destroy();
619  return false;
620  }
621 
622  return true;
623  }
624 
625  // Handles fade out effect at the end of lifetime
626  private void CheckFadeOut( int current_time)
627  {
628  // Control fade out of the light
629  if ( m_FadeOutTime != -1 && m_LifetimeEnd != -1 && current_time > m_LifetimeEnd - m_FadeOutTime )
630  {
631  m_FadeOutTime = -1;
632  m_FadeInTime = -1; // Stop fade in process
633  float time_left_in_s = (m_LifetimeEnd - current_time) * 0.001;
634  FadeBrightnessTo(0, time_left_in_s);
635  FadeRadiusTo(0, time_left_in_s);
636  }
637  }
638 
639  // handles fading of brightness
640  private void HandleBrightnessFadeing(float timeSlice)
641  {
642  if ( m_Brightness != m_BrightnessTarget )
643  {
644  float brightness_difference = m_Brightness - m_BrightnessTarget;
645 
646  if (brightness_difference > m_BrightnessSpeedOfChange*timeSlice)
647  brightness_difference = m_BrightnessSpeedOfChange*timeSlice;
648 
649  if (brightness_difference < -m_BrightnessSpeedOfChange*timeSlice)
650  brightness_difference = -m_BrightnessSpeedOfChange*timeSlice;
651 
652  m_Brightness -= brightness_difference;
653 
654  if ( m_Brightness > 0 || m_BrightnessTarget > 0)
655  {
656  SetBrightness(m_Brightness * m_BrightnessPulse);
657  CorrectLightPulseDuringDaylight();
658  }
659  else
660  {
661  Destroy();
662  return;
663  }
664  }
665  else
666  {
667  SetBrightness(m_Brightness * m_BrightnessPulse);
668  CorrectLightPulseDuringDaylight();
669  }
670  }
671 
672  // handles fading of radius
673  private void HandleRadiusFadeing(float timeSlice)
674  {
675  if ( m_Radius != m_RadiusTarget )
676  {
677  float radius_difference = m_Radius - m_RadiusTarget;
678 
679  if (radius_difference > m_RadiusSpeedOfChange*timeSlice)
680  radius_difference = m_RadiusSpeedOfChange*timeSlice;
681 
682  if (radius_difference < -m_RadiusSpeedOfChange*timeSlice)
683  radius_difference = -m_RadiusSpeedOfChange*timeSlice;
684 
685  m_Radius -= radius_difference;
686 
687  if ( m_Radius > 0 || m_RadiusTarget > 0)
688  {
689  SetRadius(m_Radius);
690  }
691  else
692  {
693  Destroy();
694  return;
695  }
696  }
697  else
698  {
699  SetRadius(m_Radius);
700  }
701  }
702 
704  void SetBlinkingSpeed(float _speed)
705  {
706  m_BlinkingSpeed = _speed;
707  }
708 
710  float GetBlinkingSpeed()
711  {
712  return m_BlinkingSpeed;
713  }
714 
715  // handles blinking. Turns light on and off on regular intervals
716  private void HandleBlinking(float time)
717  {
718  if ( m_BlinkingSpeed <= 0 )
719  return;
720 
721  float multiplier;
722 
723  multiplier = Math.Sin(time * 0.001 * m_BlinkingSpeed); // Oscillate the multiplier overtime (time normalized to sec)
724  multiplier = (multiplier + 1)/2; // Normalized the value to 0-1
725 
726  multiplier = Math.Round(multiplier); // Rounding to 0 or 1 to make it blink instantly
727  SetBrightness(m_Brightness * multiplier);
728  }
729 };
ItemBase
Definition: inventoryitem.c:730
GetGame
proto native CGame GetGame()
CALL_CATEGORY_SYSTEM
const int CALL_CATEGORY_SYSTEM
Definition: tools.c:8
m_LocalPos
protected vector m_LocalPos
Cached local pos.
Definition: effect.c:60
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
InventorySlots
provides access to slot configuration
Definition: inventoryslots.c:5
InventoryLocation
InventoryLocation.
Definition: inventorylocation.c:27
m_Radius
float m_Radius
Definition: aigroupbehaviour.c:10
SetEnabled
void SetEnabled()
prevents insider adding in the wrong position, HOTFIX
Definition: traptrigger.c:50
m_DeleteTimer
protected ref Timer m_DeleteTimer
Definition: explosivesbase.c:28
m_Parent
protected Widget m_Parent
Definition: sizetochild.c:92
EOnInit
protected override void EOnInit(IEntity other, int extra)
Definition: testframework.c:235
EmitorParam
EmitorParam
Definition: envisual.c:113
ErrorEx
enum ShapeType ErrorEx
IEntity
Definition: enentity.c:164
GetPosition
class JsonUndergroundAreaTriggerData GetPosition
Definition: undergroundarealoader.c:9
ParticleList
Definition: particlelist.c:11
PlayerBase
Definition: playerbaseclient.c:1
vector
Definition: enconvert.c:105
Destroy
proto native void Destroy()
Cleans up the Effect, including unregistering if needed.
Definition: effect.c:212
CreateLight
protected void CreateLight()
Definition: explosivesbase.c:145
EnableDebug
void EnableDebug(bool pEnabled)
Definition: pluginpresencenotifier.c:122
InventoryLocationType
InventoryLocationType
types of Inventory Location
Definition: inventorylocation.c:3
Object
Definition: objecttyped.c:1
slotName
PlayerSpawnPreset slotName
ScriptedLightBase
Definition: pointlightbase.c:1
name
PlayerSpawnPresetDiscreteItemSetSlotData name
one set for cargo
SetPosition
proto native void SetPosition(vector position)
Set the world position of the Effect.
Definition: effect.c:436
EOnFrame
protected override void EOnFrame(IEntity other, float timeSlice)
Definition: testframework.c:240
GetPlayer
protected void GetPlayer()
Definition: crosshairselector.c:127
GetParent
proto native Widget GetParent()
Get parent of the Effect.
Definition: effect.c:405
Timer
Definition: dayzplayerimplement.c:62
Math
Definition: enmath.c:6
m_LocalOri
protected vector m_LocalOri
Local orientation set by SetAttachedLocalOri, only used by EffectParticle.
Definition: effect.c:62
ParticleManager
void ParticleManager(ParticleManagerSettings settings)
Constructor (ctor)
Definition: particlemanager.c:84
EntityEvent
EntityEvent
Entity events for event-mask, or throwing event from code.
Definition: enentity.c:44
Vector
proto native vector Vector(float x, float y, float z)
Vector constructor from components.
EntityAI
Definition: building.c:5
GetAttachmentParent
Object GetAttachmentParent()
Get the parent set by SetAttachmentParent.
Definition: effect.c:572
GameInventory
script counterpart to engine's class Inventory
Definition: inventory.c:78
EntityLightSource
Definition: scriptedlightbase.c:10