1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id:$
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 //
8 // This source is available for distribution and/or modification
9 // only under the terms of the DOOM Source Code License as
10 // published by id Software. All rights reserved.
11 //
12 // The source is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
15 // for more details.
16 //
17 // $Log:$
18 //
19 // DESCRIPTION:
20 // Handle Sector base lighting effects.
21 //
22 //-----------------------------------------------------------------------------
23
24
25 #include "templates.h"
26 #include "m_random.h"
27
28 #include "doomdef.h"
29 #include "p_local.h"
30
31 #include "p_lnspec.h"
32
33 // State.
34 #include "r_state.h"
35 #include "statnums.h"
36 #include "farchive.h"
37
38 static FRandom pr_flicker ("Flicker");
39 static FRandom pr_lightflash ("LightFlash");
40 static FRandom pr_strobeflash ("StrobeFlash");
41 static FRandom pr_fireflicker ("FireFlicker");
42
43 //-----------------------------------------------------------------------------
44 //
45 //
46 //
47 //-----------------------------------------------------------------------------
48
IMPLEMENT_CLASS(DLighting)49 IMPLEMENT_CLASS (DLighting)
50
51 DLighting::DLighting ()
52 {
53 }
54
DLighting(sector_t * sector)55 DLighting::DLighting (sector_t *sector)
56 : DSectorEffect (sector)
57 {
58 ChangeStatNum (STAT_LIGHT);
59 }
60
61 //-----------------------------------------------------------------------------
62 //
63 // FIRELIGHT FLICKER
64 //
65 //-----------------------------------------------------------------------------
66
IMPLEMENT_CLASS(DFireFlicker)67 IMPLEMENT_CLASS (DFireFlicker)
68
69 DFireFlicker::DFireFlicker ()
70 {
71 }
72
Serialize(FArchive & arc)73 void DFireFlicker::Serialize (FArchive &arc)
74 {
75 Super::Serialize (arc);
76 arc << m_Count << m_MaxLight << m_MinLight;
77 }
78
79
80 //-----------------------------------------------------------------------------
81 //
82 // T_FireFlicker
83 //
84 //-----------------------------------------------------------------------------
85
Tick()86 void DFireFlicker::Tick ()
87 {
88 int amount;
89
90 if (--m_Count == 0)
91 {
92 amount = (pr_fireflicker() & 3) << 4;
93
94 // [RH] Shouldn't this be (m_MaxLight - amount < m_MinLight)?
95 if (m_Sector->lightlevel - amount < m_MinLight)
96 m_Sector->SetLightLevel(m_MinLight);
97 else
98 m_Sector->SetLightLevel(m_MaxLight - amount);
99
100 m_Count = 4;
101 }
102 }
103
104 //-----------------------------------------------------------------------------
105 //
106 // P_SpawnFireFlicker
107 //
108 //-----------------------------------------------------------------------------
109
DFireFlicker(sector_t * sector)110 DFireFlicker::DFireFlicker (sector_t *sector)
111 : DLighting (sector)
112 {
113 m_MaxLight = sector->lightlevel;
114 m_MinLight = sector_t::ClampLight(sector->FindMinSurroundingLight(sector->lightlevel) + 16);
115 m_Count = 4;
116 }
117
DFireFlicker(sector_t * sector,int upper,int lower)118 DFireFlicker::DFireFlicker (sector_t *sector, int upper, int lower)
119 : DLighting (sector)
120 {
121 m_MaxLight = sector_t::ClampLight(upper);
122 m_MinLight = sector_t::ClampLight(lower);
123 m_Count = 4;
124 }
125
126 //-----------------------------------------------------------------------------
127 //
128 // [RH] flickering light like Hexen's
129 //
130 //-----------------------------------------------------------------------------
131
IMPLEMENT_CLASS(DFlicker)132 IMPLEMENT_CLASS (DFlicker)
133
134 DFlicker::DFlicker ()
135 {
136 }
137
Serialize(FArchive & arc)138 void DFlicker::Serialize (FArchive &arc)
139 {
140 Super::Serialize (arc);
141 arc << m_Count << m_MaxLight << m_MinLight;
142 }
143
144 //-----------------------------------------------------------------------------
145 //
146 //
147 //
148 //-----------------------------------------------------------------------------
149
Tick()150 void DFlicker::Tick ()
151 {
152 if (m_Count)
153 {
154 m_Count--;
155 }
156 else if (m_Sector->lightlevel == m_MaxLight)
157 {
158 m_Sector->SetLightLevel(m_MinLight);
159 m_Count = (pr_flicker()&7)+1;
160 }
161 else
162 {
163 m_Sector->SetLightLevel(m_MaxLight);
164 m_Count = (pr_flicker()&31)+1;
165 }
166 }
167
168 //-----------------------------------------------------------------------------
169 //
170 //
171 //
172 //-----------------------------------------------------------------------------
173
DFlicker(sector_t * sector,int upper,int lower)174 DFlicker::DFlicker (sector_t *sector, int upper, int lower)
175 : DLighting (sector)
176 {
177 m_MaxLight = upper;
178 m_MinLight = lower;
179 sector->lightlevel = upper;
180 m_Count = (pr_flicker()&64)+1;
181 }
182
183 //-----------------------------------------------------------------------------
184 //
185 //
186 //
187 //-----------------------------------------------------------------------------
188
EV_StartLightFlickering(int tag,int upper,int lower)189 void EV_StartLightFlickering (int tag, int upper, int lower)
190 {
191 int secnum;
192 FSectorTagIterator it(tag);
193 while ((secnum = it.Next()) >= 0)
194 {
195 new DFlicker (§ors[secnum], upper, lower);
196 }
197 }
198
199
200 //-----------------------------------------------------------------------------
201 //
202 // BROKEN LIGHT FLASHING
203 //
204 //-----------------------------------------------------------------------------
205
IMPLEMENT_CLASS(DLightFlash)206 IMPLEMENT_CLASS (DLightFlash)
207
208 DLightFlash::DLightFlash ()
209 {
210 }
211
Serialize(FArchive & arc)212 void DLightFlash::Serialize (FArchive &arc)
213 {
214 Super::Serialize (arc);
215 arc << m_Count << m_MaxLight << m_MaxTime << m_MinLight << m_MinTime;
216 }
217
218 //-----------------------------------------------------------------------------
219 //
220 // T_LightFlash
221 // Do flashing lights.
222 //
223 //-----------------------------------------------------------------------------
224
Tick()225 void DLightFlash::Tick ()
226 {
227 if (--m_Count == 0)
228 {
229 if (m_Sector->lightlevel == m_MaxLight)
230 {
231 m_Sector->SetLightLevel(m_MinLight);
232 m_Count = (pr_lightflash() & m_MinTime) + 1;
233 }
234 else
235 {
236 m_Sector->SetLightLevel(m_MaxLight);
237 m_Count = (pr_lightflash() & m_MaxTime) + 1;
238 }
239 }
240 }
241
242 //-----------------------------------------------------------------------------
243 //
244 // P_SpawnLightFlash
245 //
246 //-----------------------------------------------------------------------------
247
DLightFlash(sector_t * sector)248 DLightFlash::DLightFlash (sector_t *sector)
249 : DLighting (sector)
250 {
251 // Find light levels like Doom.
252 m_MaxLight = sector->lightlevel;
253 m_MinLight = sector->FindMinSurroundingLight (sector->lightlevel);
254 m_MaxTime = 64;
255 m_MinTime = 7;
256 m_Count = (pr_lightflash() & m_MaxTime) + 1;
257 }
258
DLightFlash(sector_t * sector,int min,int max)259 DLightFlash::DLightFlash (sector_t *sector, int min, int max)
260 : DLighting (sector)
261 {
262 // Use specified light levels.
263 m_MaxLight = sector_t::ClampLight(max);
264 m_MinLight = sector_t::ClampLight(min);
265 m_MaxTime = 64;
266 m_MinTime = 7;
267 m_Count = (pr_lightflash() & m_MaxTime) + 1;
268 }
269
270
271 //-----------------------------------------------------------------------------
272 //
273 // STROBE LIGHT FLASHING
274 //
275 //-----------------------------------------------------------------------------
276
IMPLEMENT_CLASS(DStrobe)277 IMPLEMENT_CLASS (DStrobe)
278
279 DStrobe::DStrobe ()
280 {
281 }
282
Serialize(FArchive & arc)283 void DStrobe::Serialize (FArchive &arc)
284 {
285 Super::Serialize (arc);
286 arc << m_Count << m_MaxLight << m_MinLight << m_DarkTime << m_BrightTime;
287 }
288
289 //-----------------------------------------------------------------------------
290 //
291 // T_StrobeFlash
292 //
293 //-----------------------------------------------------------------------------
294
Tick()295 void DStrobe::Tick ()
296 {
297 if (--m_Count == 0)
298 {
299 if (m_Sector->lightlevel == m_MinLight)
300 {
301 m_Sector->SetLightLevel(m_MaxLight);
302 m_Count = m_BrightTime;
303 }
304 else
305 {
306 m_Sector->SetLightLevel(m_MinLight);
307 m_Count = m_DarkTime;
308 }
309 }
310 }
311
312 //-----------------------------------------------------------------------------
313 //
314 // Hexen-style constructor
315 //
316 //-----------------------------------------------------------------------------
317
DStrobe(sector_t * sector,int upper,int lower,int utics,int ltics)318 DStrobe::DStrobe (sector_t *sector, int upper, int lower, int utics, int ltics)
319 : DLighting (sector)
320 {
321 m_DarkTime = ltics;
322 m_BrightTime = utics;
323 m_MaxLight = sector_t::ClampLight(upper);
324 m_MinLight = sector_t::ClampLight(lower);
325 m_Count = 1; // Hexen-style is always in sync
326 }
327
328 //-----------------------------------------------------------------------------
329 //
330 // Doom-style constructor
331 //
332 //-----------------------------------------------------------------------------
333
DStrobe(sector_t * sector,int utics,int ltics,bool inSync)334 DStrobe::DStrobe (sector_t *sector, int utics, int ltics, bool inSync)
335 : DLighting (sector)
336 {
337 m_DarkTime = ltics;
338 m_BrightTime = utics;
339
340 m_MaxLight = sector->lightlevel;
341 m_MinLight = sector->FindMinSurroundingLight (sector->lightlevel);
342
343 if (m_MinLight == m_MaxLight)
344 m_MinLight = 0;
345
346 m_Count = inSync ? 1 : (pr_strobeflash() & 7) + 1;
347 }
348
349
350
351 //-----------------------------------------------------------------------------
352 //
353 // Start strobing lights (usually from a trigger)
354 // [RH] Made it more configurable.
355 //
356 //-----------------------------------------------------------------------------
357
EV_StartLightStrobing(int tag,int upper,int lower,int utics,int ltics)358 void EV_StartLightStrobing (int tag, int upper, int lower, int utics, int ltics)
359 {
360 int secnum;
361 FSectorTagIterator it(tag);
362 while ((secnum = it.Next()) >= 0)
363 {
364 sector_t *sec = §ors[secnum];
365 if (sec->lightingdata)
366 continue;
367
368 new DStrobe (sec, upper, lower, utics, ltics);
369 }
370 }
371
EV_StartLightStrobing(int tag,int utics,int ltics)372 void EV_StartLightStrobing (int tag, int utics, int ltics)
373 {
374 int secnum;
375 FSectorTagIterator it(tag);
376 while ((secnum = it.Next()) >= 0)
377 {
378 sector_t *sec = §ors[secnum];
379 if (sec->lightingdata)
380 continue;
381
382 new DStrobe (sec, utics, ltics, false);
383 }
384 }
385
386
387 //-----------------------------------------------------------------------------
388 //
389 // TURN LINE'S TAG LIGHTS OFF
390 // [RH] Takes a tag instead of a line
391 //
392 //-----------------------------------------------------------------------------
393
EV_TurnTagLightsOff(int tag)394 void EV_TurnTagLightsOff (int tag)
395 {
396 int secnum;
397 FSectorTagIterator it(tag);
398 while ((secnum = it.Next()) >= 0)
399 {
400 sector_t *sector = sectors + secnum;
401 int min = sector->lightlevel;
402
403 for (int i = 0; i < sector->linecount; i++)
404 {
405 sector_t *tsec = getNextSector (sector->lines[i],sector);
406 if (!tsec)
407 continue;
408 if (tsec->lightlevel < min)
409 min = tsec->lightlevel;
410 }
411 sector->SetLightLevel(min);
412 }
413 }
414
415
416 //-----------------------------------------------------------------------------
417 //
418 // TURN LINE'S TAG LIGHTS ON
419 // [RH] Takes a tag instead of a line
420 //
421 //-----------------------------------------------------------------------------
422
EV_LightTurnOn(int tag,int bright)423 void EV_LightTurnOn (int tag, int bright)
424 {
425 int secnum;
426 FSectorTagIterator it(tag);
427 while ((secnum = it.Next()) >= 0)
428 {
429 sector_t *sector = sectors + secnum;
430 int tbright = bright; //jff 5/17/98 search for maximum PER sector
431
432 // bright = -1 means to search ([RH] Not 0)
433 // for highest light level
434 // surrounding sector
435 if (bright < 0)
436 {
437 int j;
438
439 for (j = 0; j < sector->linecount; j++)
440 {
441 sector_t *temp = getNextSector (sector->lines[j], sector);
442
443 if (!temp)
444 continue;
445
446 if (temp->lightlevel > tbright)
447 tbright = temp->lightlevel;
448 }
449 }
450 sector->SetLightLevel(tbright);
451
452 //jff 5/17/98 unless compatibility optioned
453 //then maximum near ANY tagged sector
454 if (i_compatflags & COMPATF_LIGHT)
455 {
456 bright = tbright;
457 }
458 }
459 }
460
461 //-----------------------------------------------------------------------------
462 //
463 // killough 10/98
464 //
465 // EV_LightTurnOnPartway
466 //
467 // Turn sectors tagged to line lights on to specified or max neighbor level
468 //
469 // Passed the tag of sector(s) to light and a light level fraction between 0 and 1.
470 // Sets the light to min on 0, max on 1, and interpolates in-between.
471 // Used for doors with gradual lighting effects.
472 //
473 //-----------------------------------------------------------------------------
474
EV_LightTurnOnPartway(int tag,fixed_t frac)475 void EV_LightTurnOnPartway (int tag, fixed_t frac)
476 {
477 frac = clamp<fixed_t> (frac, 0, FRACUNIT);
478
479 // Search all sectors for ones with same tag as activating line
480 int secnum;
481 FSectorTagIterator it(tag);
482 while ((secnum = it.Next()) >= 0)
483 {
484 sector_t *temp, *sector = §ors[secnum];
485 int j, bright = 0, min = sector->lightlevel;
486
487 for (j = 0; j < sector->linecount; ++j)
488 {
489 if ((temp = getNextSector (sector->lines[j], sector)) != NULL)
490 {
491 if (temp->lightlevel > bright)
492 {
493 bright = temp->lightlevel;
494 }
495 if (temp->lightlevel < min)
496 {
497 min = temp->lightlevel;
498 }
499 }
500 }
501 sector->SetLightLevel(DMulScale16 (frac, bright, FRACUNIT-frac, min));
502 }
503 }
504
505
506 //-----------------------------------------------------------------------------
507 //
508 // [RH] New function to adjust tagged sectors' light levels
509 // by a relative amount. Light levels are clipped to
510 // be within range for sector_t::lightlevel.
511 //
512 //-----------------------------------------------------------------------------
513
EV_LightChange(int tag,int value)514 void EV_LightChange (int tag, int value)
515 {
516 int secnum;
517 FSectorTagIterator it(tag);
518 while ((secnum = it.Next()) >= 0)
519 {
520 sectors[secnum].SetLightLevel(sectors[secnum].lightlevel + value);
521 }
522 }
523
524
525 //-----------------------------------------------------------------------------
526 //
527 // Spawn glowing light
528 //
529 //-----------------------------------------------------------------------------
530
IMPLEMENT_CLASS(DGlow)531 IMPLEMENT_CLASS (DGlow)
532
533 DGlow::DGlow ()
534 {
535 }
536
Serialize(FArchive & arc)537 void DGlow::Serialize (FArchive &arc)
538 {
539 Super::Serialize (arc);
540 arc << m_Direction << m_MaxLight << m_MinLight;
541 }
542
543 //-----------------------------------------------------------------------------
544 //
545 //
546 //
547 //-----------------------------------------------------------------------------
548
Tick()549 void DGlow::Tick ()
550 {
551 int newlight = m_Sector->lightlevel;
552
553 switch (m_Direction)
554 {
555 case -1:
556 // DOWN
557 newlight -= GLOWSPEED;
558 if (newlight <= m_MinLight)
559 {
560 newlight += GLOWSPEED;
561 m_Direction = 1;
562 }
563 break;
564
565 case 1:
566 // UP
567 newlight += GLOWSPEED;
568 if (newlight >= m_MaxLight)
569 {
570 newlight -= GLOWSPEED;
571 m_Direction = -1;
572 }
573 break;
574 }
575 m_Sector->SetLightLevel(newlight);
576 }
577
578 //-----------------------------------------------------------------------------
579 //
580 //
581 //
582 //-----------------------------------------------------------------------------
583
DGlow(sector_t * sector)584 DGlow::DGlow (sector_t *sector)
585 : DLighting (sector)
586 {
587 m_MinLight = sector->FindMinSurroundingLight (sector->lightlevel);
588 m_MaxLight = sector->lightlevel;
589 m_Direction = -1;
590 }
591
592 //-----------------------------------------------------------------------------
593 //
594 // [RH] More glowing light, this time appropriate for Hexen-ish uses.
595 //
596 //-----------------------------------------------------------------------------
597
IMPLEMENT_CLASS(DGlow2)598 IMPLEMENT_CLASS (DGlow2)
599
600 DGlow2::DGlow2 ()
601 {
602 }
603
Serialize(FArchive & arc)604 void DGlow2::Serialize (FArchive &arc)
605 {
606 Super::Serialize (arc);
607 arc << m_End << m_MaxTics << m_OneShot << m_Start << m_Tics;
608 }
609
610 //-----------------------------------------------------------------------------
611 //
612 //
613 //
614 //-----------------------------------------------------------------------------
615
Tick()616 void DGlow2::Tick ()
617 {
618 if (m_Tics++ >= m_MaxTics)
619 {
620 if (m_OneShot)
621 {
622 m_Sector->SetLightLevel(m_End);
623 Destroy ();
624 return;
625 }
626 else
627 {
628 int temp = m_Start;
629 m_Start = m_End;
630 m_End = temp;
631 m_Tics -= m_MaxTics;
632 }
633 }
634
635 m_Sector->SetLightLevel(((m_End - m_Start) * m_Tics) / m_MaxTics + m_Start);
636 }
637
638 //-----------------------------------------------------------------------------
639 //
640 //
641 //
642 //-----------------------------------------------------------------------------
643
DGlow2(sector_t * sector,int start,int end,int tics,bool oneshot)644 DGlow2::DGlow2 (sector_t *sector, int start, int end, int tics, bool oneshot)
645 : DLighting (sector)
646 {
647 m_Start = sector_t::ClampLight(start);
648 m_End = sector_t::ClampLight(end);
649 m_MaxTics = tics;
650 m_Tics = -1;
651 m_OneShot = oneshot;
652 }
653
654 //-----------------------------------------------------------------------------
655 //
656 //
657 //
658 //-----------------------------------------------------------------------------
659
EV_StartLightGlowing(int tag,int upper,int lower,int tics)660 void EV_StartLightGlowing (int tag, int upper, int lower, int tics)
661 {
662 int secnum;
663
664 // If tics is non-positive, then we can't really do anything.
665 if (tics <= 0)
666 {
667 return;
668 }
669
670 if (upper < lower)
671 {
672 int temp = upper;
673 upper = lower;
674 lower = temp;
675 }
676
677 FSectorTagIterator it(tag);
678 while ((secnum = it.Next()) >= 0)
679 {
680 sector_t *sec = §ors[secnum];
681 if (sec->lightingdata)
682 continue;
683
684 new DGlow2 (sec, upper, lower, tics, false);
685 }
686 }
687
688 //-----------------------------------------------------------------------------
689 //
690 //
691 //
692 //-----------------------------------------------------------------------------
693
EV_StartLightFading(int tag,int value,int tics)694 void EV_StartLightFading (int tag, int value, int tics)
695 {
696 int secnum;
697 FSectorTagIterator it(tag);
698 while ((secnum = it.Next()) >= 0)
699 {
700 sector_t *sec = §ors[secnum];
701 if (sec->lightingdata)
702 continue;
703
704 if (tics <= 0)
705 {
706 sec->SetLightLevel(value);
707 }
708 else
709 {
710 // No need to fade if lightlevel is already at desired value.
711 if (sec->lightlevel == value)
712 continue;
713
714 new DGlow2 (sec, sec->lightlevel, value, tics, true);
715 }
716 }
717 }
718
719
720 //-----------------------------------------------------------------------------
721 //
722 // [RH] Phased lighting ala Hexen, but implemented without the help of the Hexen source
723 // The effect is a little different, but close enough, I feel.
724 //
725 //-----------------------------------------------------------------------------
726
IMPLEMENT_CLASS(DPhased)727 IMPLEMENT_CLASS (DPhased)
728
729 DPhased::DPhased ()
730 {
731 }
732
Serialize(FArchive & arc)733 void DPhased::Serialize (FArchive &arc)
734 {
735 Super::Serialize (arc);
736 arc << m_BaseLevel << m_Phase;
737 }
738
739 //-----------------------------------------------------------------------------
740 //
741 //
742 //
743 //-----------------------------------------------------------------------------
744
Tick()745 void DPhased::Tick ()
746 {
747 const int steps = 12;
748
749 if (m_Phase < steps)
750 m_Sector->SetLightLevel( ((255 - m_BaseLevel) * m_Phase) / steps + m_BaseLevel);
751 else if (m_Phase < 2*steps)
752 m_Sector->SetLightLevel( ((255 - m_BaseLevel) * (2*steps - m_Phase - 1) / steps
753 + m_BaseLevel));
754 else
755 m_Sector->SetLightLevel(m_BaseLevel);
756
757 if (m_Phase == 0)
758 m_Phase = 63;
759 else
760 m_Phase--;
761 }
762
763 //-----------------------------------------------------------------------------
764 //
765 //
766 //
767 //-----------------------------------------------------------------------------
768
PhaseHelper(sector_t * sector,int index,int light,sector_t * prev)769 int DPhased::PhaseHelper (sector_t *sector, int index, int light, sector_t *prev)
770 {
771 if (!sector)
772 {
773 return index;
774 }
775 else
776 {
777 DPhased *l;
778 int baselevel = sector->lightlevel ? sector->lightlevel : light;
779
780 if (index == 0)
781 {
782 l = this;
783 m_BaseLevel = baselevel;
784 }
785 else
786 l = new DPhased (sector, baselevel);
787
788 int numsteps = PhaseHelper (sector->NextSpecialSector (
789 sector->special == LightSequenceSpecial1 ?
790 LightSequenceSpecial2 : LightSequenceSpecial1, prev),
791 index + 1, l->m_BaseLevel, sector);
792 l->m_Phase = ((numsteps - index - 1) * 64) / numsteps;
793
794 sector->special = 0;
795
796 return numsteps;
797 }
798 }
799
800 //-----------------------------------------------------------------------------
801 //
802 //
803 //
804 //-----------------------------------------------------------------------------
805
DPhased(sector_t * sector,int baselevel)806 DPhased::DPhased (sector_t *sector, int baselevel)
807 : DLighting (sector)
808 {
809 m_BaseLevel = baselevel;
810 }
811
DPhased(sector_t * sector)812 DPhased::DPhased (sector_t *sector)
813 : DLighting (sector)
814 {
815 PhaseHelper (sector, 0, 0, NULL);
816 }
817
DPhased(sector_t * sector,int baselevel,int phase)818 DPhased::DPhased (sector_t *sector, int baselevel, int phase)
819 : DLighting (sector)
820 {
821 m_BaseLevel = baselevel;
822 m_Phase = phase;
823 }
824
825 //============================================================================
826 //
827 // EV_StopLightEffect
828 //
829 // Stops a lighting effect that is currently running in a sector.
830 //
831 //============================================================================
832
EV_StopLightEffect(int tag)833 void EV_StopLightEffect (int tag)
834 {
835 TThinkerIterator<DLighting> iterator;
836 DLighting *effect;
837
838 while ((effect = iterator.Next()) != NULL)
839 {
840 if (tagManager.SectorHasTag(effect->GetSector(), tag))
841 {
842 effect->Destroy();
843 }
844 }
845 }
846