1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 2010-2019 EDuke32 developers and contributors
4 Copyright (C) 2019 sirlemonhead, Nuke.YKT
5 
6 This file is part of PCExhumed.
7 
8 PCExhumed is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License version 2
10 as published by the Free Software Foundation.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 
16 See the GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 */
22 //-------------------------------------------------------------------------
23 
24 #include "typedefs.h"
25 #include "lighting.h"
26 #include "player.h"
27 #include "engine.h"
28 #include "exhumed.h"
29 #include "sound.h"
30 #include "light.h"
31 #include "random.h"
32 #include "save.h"
33 #include "status.h"
34 #include <string.h>
35 #include <assert.h>
36 
37 #define kMaxFlashes			2000
38 #define kMaxFlickerMask		25
39 #define kMaxGlows			50
40 #define kMaxFlickers		100
41 #define kMaxFlows			375
42 
43 struct Flash
44 {
45     char field_0;
46     short field_1;
47     int8_t shade;
48 };
49 
50 struct Glow
51 {
52     short field_0;
53     short field_2;
54     short nSector;
55     short field_6;
56 };
57 
58 struct Flicker
59 {
60     short field_0;
61     short nSector;
62     unsigned int field_4;
63 };
64 
65 struct Flow
66 {
67     short field_0;
68     short field_2;
69     int field_4;
70     int field_8;
71     int field_C;
72     int field_10;
73     int field_14;
74     int field_18;
75 };
76 
77 Flash sFlash[kMaxFlashes];
78 Glow sGlow[kMaxGlows];
79 short nNextFlash[kMaxFlashes];
80 Flicker sFlicker[kMaxFlickers];
81 short nFreeFlash[kMaxFlashes];
82 Flow sFlowInfo[kMaxFlows];
83 int flickermask[kMaxFlickerMask];
84 
85 short bTorch = 0;
86 short nFirstFlash = -1;
87 short nLastFlash = -1;
88 short nFlashDepth = 2;
89 short nFlashes;
90 short nFlowCount;
91 short nFlickerCount;
92 short nGlowCount;
93 
94 int bDoFlicks = 0;
95 int bDoGlows = 0;
96 
97 
GrabFlash()98 int GrabFlash()
99 {
100     if (nFlashes >= kMaxFlashes) {
101         return -1;
102     }
103 
104     short nFlash = nFreeFlash[nFlashes];
105     nNextFlash[nFlash] = -1;
106 
107     nFlashes++;
108 
109     if (nLastFlash <= -1)
110     {
111         nFirstFlash = nFlash;
112     }
113     else
114     {
115         nNextFlash[nLastFlash] = nFlash;
116     }
117 
118     nLastFlash = nFlash;
119 
120     return nLastFlash;
121 }
122 
InitLights()123 void InitLights()
124 {
125     int i;
126     nFlickerCount = 0;
127 
128     for (i = 0; i < kMaxFlickerMask; i++) {
129         flickermask[i] = RandomSize(0x1F) * 2;
130     }
131 
132     nGlowCount = 0;
133     nFlowCount = 0;
134     nFlashes  = 0;
135     bDoFlicks = kFalse;
136     bDoGlows  = kFalse;
137 
138     for (i = 0; i < kMaxFlashes; i++) {
139         nFreeFlash[i] = i;
140     }
141 
142     nFirstFlash = -1;
143     nLastFlash  = -1;
144 }
145 
AddFlash(short nSector,int x,int y,int z,int val)146 void AddFlash(short nSector, int x, int y, int z, int val)
147 {
148     assert(nSector >= 0 && nSector < kMaxSectors);
149 
150     int var_28 = 0;
151     unsigned int var_1C = val >> 8;
152 
153     if (var_1C >= nFlashDepth) {
154         return;
155     }
156 
157     unsigned int var_20 = val & 0x80;
158     unsigned int var_18 = val & 0x40;
159 
160     val = ((var_1C + 1) << 8) | (char)val;
161 
162     int var_14 = 0;
163 
164     short startwall = sector[nSector].wallptr;
165     short endwall = sector[nSector].wallptr + sector[nSector].wallnum;
166 
167     for (int i = startwall; i < endwall; i++)
168     {
169         short wall2 = wall[i].point2;
170 
171         int xAverage = (wall[i].x + wall[wall2].x) / 2;
172         int yAverage = (wall[i].y + wall[wall2].y) / 2;
173 
174         sectortype *pNextSector = NULL;
175         if (wall[i].nextsector > -1) {
176             pNextSector = &sector[wall[i].nextsector];
177         }
178 
179         int ebx = -255;
180 
181         if (!var_18)
182         {
183             int x2 = x - xAverage;
184             if (x2 < 0) {
185                 x2 = -x2;
186             }
187 
188             ebx = x2;
189 
190             int y2 = y - yAverage;
191             if (y2 < 0) {
192                 y2 = -y2;
193             }
194 
195             ebx = ((y2 + ebx) >> 4) - 255;
196         }
197 
198         if (ebx < 0)
199         {
200             var_14++;
201             var_28 += ebx;
202 
203             if (wall[i].pal < 5)
204             {
205                 if (!pNextSector || pNextSector->floorz < sector[nSector].floorz)
206                 {
207                     short nFlash = GrabFlash();
208                     if (nFlash < 0) {
209                         return;
210                     }
211 
212                     sFlash[nFlash].field_0 = var_20 | 2;
213                     sFlash[nFlash].shade = wall[i].shade;
214                     sFlash[nFlash].field_1 = i;
215 
216                     wall[i].pal += 7;
217 
218                     ebx += wall[i].shade;
219                     int eax = ebx;
220 
221                     if (ebx < -127) {
222                         eax = -127;
223                     }
224 
225                     wall[i].shade = eax;
226 
227                     if (!var_1C && !wall[i].overpicnum && pNextSector)
228                     {
229                         AddFlash(wall[i].nextsector, x, y, z, val);
230                     }
231                 }
232             }
233         }
234     }
235 
236     if (var_14 && sector[nSector].floorpal < 4)
237     {
238         short nFlash = GrabFlash();
239         if (nFlash < 0) {
240             return;
241         }
242 
243         sFlash[nFlash].field_0 = var_20 | 1;
244         sFlash[nFlash].field_1 = nSector;
245         sFlash[nFlash].shade = sector[nSector].floorshade;
246 
247         sector[nSector].floorpal += 7;
248 
249         int edx = sector[nSector].floorshade + var_28;
250         int eax = edx;
251 
252         if (edx < -127) {
253             eax = -127;
254         }
255 
256         sector[nSector].floorshade = eax;
257 
258         if (!(sector[nSector].ceilingstat & 1))
259         {
260             if (sector[nSector].ceilingpal < 4)
261             {
262                 short nFlash2 = GrabFlash();
263                 if (nFlash2 >= 0)
264                 {
265                     sFlash[nFlash2].field_0 = var_20 | 3;
266                     sFlash[nFlash2].field_1 = nSector;
267                     sFlash[nFlash2].shade = sector[nSector].ceilingshade;
268 
269                     sector[nSector].ceilingpal += 7;
270 
271                     int edx = sector[nSector].ceilingshade + var_28;
272                     int eax = edx;
273 
274                     if (edx < -127) {
275                         eax = -127;
276                     }
277 
278                     sector[nSector].ceilingshade = eax;
279                 }
280             }
281         }
282 
283         for (short nSprite = headspritesect[nSector]; nSprite >= 0; nSprite = nextspritesect[nSprite])
284         {
285             if (sprite[nSprite].pal < 4)
286             {
287                 short nFlash3 = GrabFlash();
288                 if (nFlash3 >= 0)
289                 {
290                     sFlash[nFlash3].field_0 = var_20 | 4;
291                     sFlash[nFlash3].shade = sprite[nSprite].shade;
292                     sFlash[nFlash3].field_1 = nSprite;
293 
294                     sprite[nSprite].pal += 7;
295 
296                     int eax = -255;
297 
298                     if (!var_18)
299                     {
300                         int xDiff = x - sprite[nSprite].x;
301                         if (xDiff < 0) {
302                             xDiff = -xDiff;
303                         }
304 
305                         int yDiff = y - sprite[nSprite].y;
306                         if (yDiff < 0) {
307                             yDiff = -yDiff;
308                         }
309 
310                         eax = ((xDiff + yDiff) >> 4) - 255;
311                     }
312 
313                     if (eax < 0)
314                     {
315                         short shade = sprite[nSprite].shade + eax;
316                         if (shade < -127) {
317                             shade = -127;
318                         }
319 
320                         sprite[nSprite].shade = shade;
321                     }
322                 }
323             }
324         }
325     }
326 }
327 
UndoFlashes()328 void UndoFlashes()
329 {
330     if (!nFlashes) {
331         return;
332     }
333 
334     int var_24 = 0; // CHECKME - Watcom error "initializer for variable var_24 may not execute
335 
336     int edi = -1;
337 
338     for (short nFlash = nFirstFlash; nFlash >= 0; nFlash = nNextFlash[nFlash])
339     {
340         assert(nFlash < 2000 && nFlash >= 0);
341 
342         uint8_t var_28 = sFlash[nFlash].field_0 & 0x3F;
343         short nIndex = sFlash[nFlash].field_1;
344 
345         if (sFlash[nFlash].field_0 & 0x80)
346         {
347             int var_20 = var_28 - 1;
348             assert(var_20 >= 0);
349 
350             int8_t *pShade = NULL;
351 
352             switch (var_20)
353             {
354                 case 0:
355                 {
356                     assert(nIndex >= 0 && nIndex < kMaxSectors);
357 
358                     pShade = &sector[nIndex].floorshade;
359                     break;
360                 }
361 
362                 case 1:
363                 {
364                     assert(nIndex >= 0 && nIndex < kMaxWalls);
365 
366                     pShade = &wall[nIndex].shade;
367                     break;
368                 }
369 
370                 case 2:
371                 {
372                     assert(nIndex >= 0 && nIndex < kMaxSectors);
373 
374                     pShade = &sector[nIndex].ceilingshade;
375                     break;
376                 }
377 
378                 case 3:
379                 {
380                     assert(nIndex >= 0 && nIndex < kMaxSprites);
381 
382                     if (sprite[nIndex].pal >= 7)
383                     {
384                         pShade = &sprite[nIndex].shade;
385                     }
386                     else {
387                         goto loc_1868A;
388                     }
389 
390                     break;
391                 }
392 
393                 default:
394                     break;
395             }
396 
397             assert(pShade != NULL);
398 
399             short var_2C = (*pShade) + 6;
400             int var_30 = sFlash[nFlash].shade;
401 
402             if (var_2C < var_30)
403             {
404                 *pShade = var_2C;
405                 edi = nFlash;
406                 continue;
407             }
408         }
409 
410         // loc_185FE
411         var_24 = var_28 - 1; // CHECKME - Watcom error "initializer for variable var_24 may not execute
412         assert(var_24 >= 0);
413 
414         switch (var_24)
415         {
416             default:
417                 break;
418 
419             case 0:
420             {
421                 sector[nIndex].floorpal -= 7;
422                 sector[nIndex].floorshade = sFlash[nFlash].shade;
423                 break;
424             }
425 
426             case 1:
427             {
428                 wall[nIndex].pal -= 7;
429                 wall[nIndex].shade = sFlash[nFlash].shade;
430                 break;
431             }
432 
433             case 2:
434             {
435                 sector[nIndex].ceilingpal -= 7;
436                 sector[nIndex].ceilingshade = sFlash[nFlash].shade;
437                 break;
438             }
439 
440             case 3:
441             {
442                 if (sprite[nIndex].pal >= 7)
443                 {
444                     sprite[nIndex].pal -= 7;
445                     sprite[nIndex].shade = sFlash[nFlash].shade;
446                 }
447 
448                 break;
449             }
450         }
451 
452 loc_1868A:
453 
454         nFlashes--;
455         assert(nFlashes >= 0);
456 
457         nFreeFlash[nFlashes] = nFlash;
458 
459         if (edi != -1)
460         {
461             nNextFlash[edi] = nNextFlash[nFlash];
462         }
463 
464         if (nFlash == nFirstFlash)
465         {
466             nFirstFlash = nNextFlash[nFirstFlash];
467         }
468 
469         if (nFlash == nLastFlash)
470         {
471             nLastFlash = edi;
472         }
473     }
474 }
475 
AddGlow(short nSector,int nVal)476 void AddGlow(short nSector, int nVal)
477 {
478     if (nGlowCount >= kMaxGlows) {
479         return;
480     }
481 
482     sGlow[nGlowCount].field_6 = nVal;
483     sGlow[nGlowCount].nSector = nSector;
484     sGlow[nGlowCount].field_0 = -1;
485     sGlow[nGlowCount].field_2 = 0;
486 
487     nGlowCount++;
488 }
489 
AddFlicker(short nSector,int nVal)490 void AddFlicker(short nSector, int nVal)
491 {
492     if (nFlickerCount >= kMaxFlickers) {
493         return;
494     }
495 
496     sFlicker[nFlickerCount].field_0 = nVal;
497     sFlicker[nFlickerCount].nSector = nSector;
498 
499     if (nVal >= 25) {
500         nVal = 24;
501     }
502 
503     sFlicker[nFlickerCount].field_4 = flickermask[nVal];
504 
505     nFlickerCount++;
506 }
507 
DoGlows()508 void DoGlows()
509 {
510     bDoGlows++;
511 
512     if (bDoGlows < 3) {
513         return;
514     }
515 
516     bDoGlows = 0;
517 
518     for (int i = 0; i < nGlowCount; i++)
519     {
520         sGlow[i].field_2++;
521 
522         short nSector = sGlow[i].nSector;
523         short nShade = sGlow[i].field_0;
524 
525         if (sGlow[i].field_2 >= sGlow[i].field_6)
526         {
527             sGlow[i].field_2 = 0;
528             sGlow[i].field_0 = -sGlow[i].field_0;
529         }
530 
531         sector[nSector].ceilingshade += nShade;
532         sector[nSector].floorshade   += nShade;
533 
534         int startwall = sector[nSector].wallptr;
535         int endwall = startwall + sector[nSector].wallnum - 1;
536 
537         for (int nWall = startwall; nWall <= endwall; nWall++)
538         {
539             wall[nWall].shade += nShade;
540 
541             // CHECKME - ASM has edx decreasing here. why?
542         }
543     }
544 }
545 
DoFlickers()546 void DoFlickers()
547 {
548     bDoFlicks ^= 1;
549     if (!bDoFlicks) {
550         return;
551     }
552 
553     for (int i = 0; i < nFlickerCount; i++)
554     {
555         short nSector = sFlicker[i].nSector;
556 
557         unsigned int eax = (sFlicker[i].field_4 & 1);
558         unsigned int edx = (sFlicker[i].field_4 & 1) << 31;
559         unsigned int ebp = sFlicker[i].field_4 >> 1;
560 
561         ebp |= edx;
562         edx = ebp & 1;
563 
564         sFlicker[i].field_4 = ebp;
565 
566         if (edx ^ eax)
567         {
568             short shade;
569 
570             if (eax)
571             {
572                 shade = sFlicker[i].field_0;
573             }
574             else
575             {
576                 shade = -sFlicker[i].field_0;
577             }
578 
579             sector[nSector].ceilingshade += shade;
580             sector[nSector].floorshade += shade;
581 
582             int startwall = sector[nSector].wallptr;
583             int endwall = startwall + sector[nSector].wallnum - 1;
584 
585             for (int nWall = endwall; nWall >= startwall; nWall--)
586             {
587                 wall[nWall].shade += shade;
588 
589                 // CHECKME - ASM has edx decreasing here. why?
590             }
591         }
592     }
593 }
594 
595 // nWall can also be passed in here via nSprite parameter - TODO - rename nSprite parameter :)
AddFlow(int nSprite,int nSpeed,int b)596 void AddFlow(int nSprite, int nSpeed, int b)
597 {
598     if (nFlowCount >= kMaxFlows)
599         return;
600 
601     short nFlow = nFlowCount;
602     nFlowCount++;
603 
604     short var_18;
605 
606     if (b < 2)
607     {
608         var_18 = sprite[nSprite].sectnum;
609         short nPic = sector[var_18].floorpicnum;
610         short nAngle = sprite[nSprite].ang;
611 
612         sFlowInfo[nFlow].field_14 = (tilesiz[nPic].x << 14) - 1;
613         sFlowInfo[nFlow].field_18 = (tilesiz[nPic].y << 14) - 1;
614         sFlowInfo[nFlow].field_C  = -Cos(nAngle) * nSpeed;
615         sFlowInfo[nFlow].field_10 = Sin(nAngle) * nSpeed;
616     }
617     else
618     {
619         short nAngle;
620 
621         if (b == 2) {
622             nAngle = 512;
623         }
624         else {
625             nAngle = 1536;
626         }
627 
628         var_18 = nSprite;
629         short nPic = wall[var_18].picnum;
630 
631         sFlowInfo[nFlow].field_14 = (tilesiz[nPic].x * wall[var_18].xrepeat) << 8;
632         sFlowInfo[nFlow].field_18 = (tilesiz[nPic].y * wall[var_18].yrepeat) << 8;
633         sFlowInfo[nFlow].field_C = -Cos(nAngle) * nSpeed;
634         sFlowInfo[nFlow].field_10 = Sin(nAngle) * nSpeed;
635     }
636 
637     sFlowInfo[nFlow].field_8 = 0;
638     sFlowInfo[nFlow].field_4 = 0;
639     sFlowInfo[nFlow].field_0 = var_18;
640     sFlowInfo[nFlow].field_2 = b;
641 }
642 
DoFlows()643 void DoFlows()
644 {
645     for (int i = 0; i < nFlowCount; i++)
646     {
647         sFlowInfo[i].field_4 += sFlowInfo[i].field_C;
648         sFlowInfo[i].field_8 += sFlowInfo[i].field_10;
649 
650         switch (sFlowInfo[i].field_2)
651         {
652             case 0:
653             {
654                 sFlowInfo[i].field_4 &= sFlowInfo[i].field_14;
655                 sFlowInfo[i].field_8 &= sFlowInfo[i].field_18;
656 
657                 short nSector = sFlowInfo[i].field_0;
658                 sector[nSector].floorxpanning = sFlowInfo[i].field_4 >> 14;
659                 sector[nSector].floorypanning = sFlowInfo[i].field_8 >> 14;
660                 break;
661             }
662 
663             case 1:
664             {
665                 short nSector = sFlowInfo[i].field_0;
666 
667                 sector[nSector].ceilingxpanning = sFlowInfo[i].field_4 >> 14;
668                 sector[nSector].ceilingypanning = sFlowInfo[i].field_8 >> 14;
669 
670                 sFlowInfo[i].field_4 &= sFlowInfo[i].field_14;
671                 sFlowInfo[i].field_8 &= sFlowInfo[i].field_18;
672                 break;
673             }
674 
675             case 2:
676             {
677                 short nWall = sFlowInfo[i].field_0;
678 
679                 wall[nWall].xpanning = sFlowInfo[i].field_4 >> 14;
680                 wall[nWall].ypanning = sFlowInfo[i].field_8 >> 14;
681 
682                 if (sFlowInfo[i].field_4 < 0)
683                 {
684                     sFlowInfo[i].field_4 += sFlowInfo[i].field_14;
685                 }
686 
687                 if (sFlowInfo[i].field_8 < 0)
688                 {
689                     sFlowInfo[i].field_8 += sFlowInfo[i].field_18;
690                 }
691 
692                 break;
693             }
694 
695             case 3:
696             {
697                 short nWall = sFlowInfo[i].field_0;
698 
699                 wall[nWall].xpanning = sFlowInfo[i].field_4 >> 14;
700                 wall[nWall].ypanning = sFlowInfo[i].field_8 >> 14;
701 
702                 if (sFlowInfo[i].field_4 >= sFlowInfo[i].field_14)
703                 {
704                     sFlowInfo[i].field_4 -= sFlowInfo[i].field_14;
705                 }
706 
707                 if (sFlowInfo[i].field_8 >= sFlowInfo[i].field_18)
708                 {
709                     sFlowInfo[i].field_8 -= sFlowInfo[i].field_18;
710                 }
711 
712                 break;
713             }
714         }
715     }
716 }
717 
DoLights()718 void DoLights()
719 {
720     DoFlickers();
721     DoGlows();
722     DoFlows();
723 }
724 
SetTorch(int nPlayer,int bTorchOnOff)725 void SetTorch(int nPlayer, int bTorchOnOff)
726 {
727     char buf[40];
728 
729     if (bTorchOnOff == bTorch) {
730         return;
731     }
732 
733     if (nPlayer != nLocalPlayer) {
734         return;
735     }
736 
737     // char *pTempPal = origpalookup[kPalTorch];
738     // palookup[kPalTorch] = palookup[kPalNoTorch];
739     // palookup[kPalNoTorch] = pTempPal;
740     //
741     // pTempPal = origpalookup[kPalTorch];
742     // origpalookup[kPalTorch] = origpalookup[kPalNoTorch];
743     // origpalookup[kPalNoTorch] = pTempPal;
744     //
745     // pTempPal = origpalookup[kPalTorch2];
746     // origpalookup[kPalTorch2] = origpalookup[kPalNoTorch2];
747     // origpalookup[kPalNoTorch2] = pTempPal;
748     //
749     // pTempPal = palookup[kPalTorch2];
750     // palookup[kPalNoTorch2] = palookup[kPalTorch2];
751     // palookup[kPalTorch2] = pTempPal;
752 
753     if (bTorchOnOff == 2) {
754         bTorch = !bTorch;
755     }
756     else {
757         bTorch = bTorchOnOff;
758     }
759 
760     if (bTorch) {
761         PlayLocalSound(kSoundTorchOn, 0);
762     }
763 
764     strcpy(buf, "TORCH IS ");
765 
766     if (bTorch) {
767         strcat(buf, "LIT");
768     }
769     else {
770         strcat(buf, "OUT");
771     }
772 
773     StatusMessage(150, buf);
774 }
775 
BuildFlash(short nPlayer,short UNUSED (nSector),int nVal)776 void BuildFlash(short nPlayer, short UNUSED(nSector), int nVal)
777 {
778     if (nPlayer == nLocalPlayer)
779     {
780         flash = nVal;
781         flash = -nVal; // ???
782     }
783 }
784 
785 class LightingLoadSave : public LoadSave
786 {
787 public:
788     virtual void Load();
789     virtual void Save();
790 };
791 
Load()792 void LightingLoadSave::Load()
793 {
794     Read(&bTorch, sizeof(bTorch));
795     Read(&nFirstFlash, sizeof(nFirstFlash));
796     Read(&nLastFlash, sizeof(nLastFlash));
797     Read(&nFlashDepth, sizeof(nFlashDepth));
798     Read(&nFlashes, sizeof(nFlashes));
799     Read(&nFlowCount, sizeof(nFlowCount));
800     Read(&nFlickerCount, sizeof(nFlickerCount));
801     Read(&nGlowCount, sizeof(nGlowCount));
802     Read(&bDoFlicks, sizeof(bDoFlicks));
803     Read(&bDoGlows, sizeof(bDoGlows));
804 
805     Read(sFlash, sizeof(sFlash));
806     Read(sGlow, sizeof(sGlow));
807     Read(nNextFlash, sizeof(nNextFlash));
808     Read(sFlicker, sizeof(sFlicker));
809     Read(nFreeFlash, sizeof(nFreeFlash));
810     Read(sFlowInfo, sizeof(sFlowInfo));
811     Read(flickermask, sizeof(flickermask));
812 }
813 
Save()814 void LightingLoadSave::Save()
815 {
816     Write(&bTorch, sizeof(bTorch));
817     Write(&nFirstFlash, sizeof(nFirstFlash));
818     Write(&nLastFlash, sizeof(nLastFlash));
819     Write(&nFlashDepth, sizeof(nFlashDepth));
820     Write(&nFlashes, sizeof(nFlashes));
821     Write(&nFlowCount, sizeof(nFlowCount));
822     Write(&nFlickerCount, sizeof(nFlickerCount));
823     Write(&nGlowCount, sizeof(nGlowCount));
824     Write(&bDoFlicks, sizeof(bDoFlicks));
825     Write(&bDoGlows, sizeof(bDoGlows));
826 
827     Write(sFlash, sizeof(sFlash));
828     Write(sGlow, sizeof(sGlow));
829     Write(nNextFlash, sizeof(nNextFlash));
830     Write(sFlicker, sizeof(sFlicker));
831     Write(nFreeFlash, sizeof(nFreeFlash));
832     Write(sFlowInfo, sizeof(sFlowInfo));
833     Write(flickermask, sizeof(flickermask));
834 }
835 
836 static LightingLoadSave* myLoadSave;
837 
LightingLoadSaveConstruct()838 void LightingLoadSaveConstruct()
839 {
840     myLoadSave = new LightingLoadSave();
841 }
842