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