1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 1997, 2005 - 3D Realms Entertainment
4 
5 This file is part of Shadow Warrior version 1.2
6 
7 Shadow Warrior is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21 
22 Original Source: 1997 - Frank Maddin and Jim Norwood
23 Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
24 */
25 //-------------------------------------------------------------------------
26 
27 // JSECTOR.C
28 // This is all Jim's programming having to do with sectors.
29 
30 #include "build.h"
31 
32 #include "keys.h"
33 #include "names2.h"
34 #include "jnames.h"
35 #include "panel.h"
36 #include "game.h"
37 #include "tags.h"
38 #include "sector.h"
39 #include "player.h"
40 #include "sprite.h"
41 #include "reserve.h"
42 #include "jsector.h"
43 #include "jtags.h"
44 #include "lists.h"
45 #include "pal.h"
46 #include "parent.h"
47 
48 
49 // V A R I A B L E   D E C L A R A T I O N S //////////////////////////////////////////////////////
50 
51 MIRRORTYPE mirror[MAXMIRRORS];
52 
53 short mirrorcnt;//, floormirrorcnt;
54 //short floormirrorsector[MAXMIRRORS];
55 BOOL mirrorinview;
56 
57 static char tempbuf[/*max(576, */MAXXDIM/*)*/];
58 
59 BOOL MirrorMoveSkip16 = 0;
60 
61 // Voxel stuff
62 //BOOL bVoxelsOn = TRUE;                  // Turn voxels on by default
63 BOOL bSpinBobVoxels = FALSE;            // Do twizzly stuff to voxels, but
64                                         // not by default
65 BOOL bAutoSize = TRUE;                  // Autosizing on/off
66 
67 //extern int chainnumpages;
68 extern AMB_INFO ambarray[];
69 extern short NormalVisibility;
70 
71 extern ParentalStruct aVoxelArray[MAXTILES];
72 
73 // F U N C T I O N S //////////////////////////////////////////////////////////////////////////////
74 
75 
76 /////////////////////////////////////////////////////
77 //  SpawnWallSound
78 /////////////////////////////////////////////////////
79 VOID
SpawnWallSound(short sndnum,short i)80 SpawnWallSound(short sndnum, short i)
81     {
82     short SpriteNum;
83     int midx, midy, midz;
84     SPRITEp sp;
85     int handle;
86 
87     SpriteNum = COVERinsertsprite(0, STAT_DEFAULT);
88     if (SpriteNum < 0)
89         return;
90 
91     sp = &sprite[SpriteNum];
92     sp->cstat = 0;
93     sp->extra = 0;
94     // Get wall midpoint for offset in mirror view
95     midx = (wall[i].x + wall[wall[i].point2].x) / 2;
96     midy = (wall[i].y + wall[wall[i].point2].y) / 2;
97     midz = (sector[wall[i].nextsector].ceilingz + sector[wall[i].nextsector].floorz) / 2;
98     setspritez(SpriteNum, midx, midy, midz);
99     sp = &sprite[SpriteNum];
100 
101     handle = PlaySound(sndnum, &sp->x, &sp->y, &sp->z, v3df_dontpan | v3df_doppler);
102     if (handle != -1)
103         Set3DSoundOwner(SpriteNum);
104     }
105 
106 short
CheckTileSound(short picnum)107 CheckTileSound(short picnum)
108     {
109     short sndnum = -1;
110 
111     switch (picnum)
112         {
113     case 163:                           // Sizzly Lava
114     case 167:
115         sndnum = DIGI_VOLCANOSTEAM1;
116         break;
117     case 175:                           // Flowing Lava
118         sndnum = DIGI_ERUPTION;
119         break;
120     case 179:                           // Bubbly lava
121         sndnum = DIGI_LAVAFLOW1;
122         break;
123     case 300:                           // Water fall tile
124         sndnum = DIGI_WATERFALL1;
125         break;
126     case 334:                           // Teleporter Pad
127         sndnum = DIGI_ENGROOM1;
128         break;
129     case 2690:                          // Jet engine fan
130         sndnum = DIGI_JET;
131         break;
132     case 2672:                          // X-Ray Machine engine
133         sndnum = DIGI_ENGROOM5;
134         break;
135     case 768:                           // Electricity
136 //          sndnum = DIGI_;
137         break;
138     case 2714:                          // Pachinko Machine
139 //          sndnum = DIGI_;
140         break;
141     case 2782:                          // Telepad
142         sndnum = DIGI_ENGROOM4;
143         break;
144     case 3382:                          // Gears
145         sndnum = DIGI_ENGROOM5;
146         break;
147     case 2801:                          // Computers
148     case 2804:
149     case 2807:
150     case 3352:
151     case 3385:
152     case 3389:
153     case 3393:
154     case 3397:
155     case 3401:
156     case 3405:
157 //          sndnum = DIGI_;
158         break;
159     case 3478:                          // Radar screen
160 //          sndnum = DIGI_;
161         break;
162     default:
163         sndnum = -1;
164         break;
165         }
166     return (sndnum);
167     }
168 
169 /////////////////////////////////////////////////////
170 //  Initialize any of my special use sprites
171 /////////////////////////////////////////////////////
172 void
JS_SpriteSetup(void)173 JS_SpriteSetup(void)
174     {
175     SPRITEp sp;
176     short SpriteNum = 0, NextSprite, ndx;
177     USERp u;
178     short i, num;
179     int handle;
180 
181 
182     TRAVERSE_SPRITE_STAT(headspritestat[0], SpriteNum, NextSprite)
183         {
184         short tag;
185         short bit;
186 
187         sp = &sprite[SpriteNum];
188         tag = sp->hitag;
189 
190         // Non static camera. Camera sprite will be drawn!
191         if (tag == MIRROR_CAM && sprite[SpriteNum].picnum != ST1)
192             {
193             // Just change it to static, sprite has all the info I need
194 //          u = SpawnUser(SpriteNum, sp->picnum, NULL);
195 //          RESET(sp->cstat, CSTAT_SPRITE_BLOCK);
196 //          SET(sp->cstat, CSTAT_SPRITE_BLOCK_HITSCAN);
197             change_sprite_stat(SpriteNum, STAT_SPAWN_SPOT);
198             }
199 
200         switch (sprite[SpriteNum].picnum)
201             {
202         case ST1:
203             if (tag == MIRROR_CAM)
204                 {
205                 // Just change it to static, sprite has all the info I need
206                 // ST1 cameras won't move with SOBJ's!
207                 change_sprite_stat(SpriteNum, STAT_ST1);
208                 }
209             else if (tag == MIRROR_SPAWNSPOT)
210                 {
211                 // Just change it to static, sprite has all the info I need
212                 change_sprite_stat(SpriteNum, STAT_ST1);
213                 }
214             else if (tag == AMBIENT_SOUND)
215                 {
216                 change_sprite_stat(SpriteNum, STAT_AMBIENT);
217                 // PlaySound(sp->lotag, &sp->x, &sp->y, &sp->z, v3df_ambient
218                 // | v3df_init | v3df_doppler);
219                 }
220             else if (tag == TAG_ECHO_SOUND)
221                 {
222                 change_sprite_stat(SpriteNum, STAT_ECHO);
223                 }
224             else if (tag == TAG_DRIPGEN)
225                 {
226                 ANIMATOR GenerateDrips;
227 
228                 u = SpawnUser(SpriteNum, 0, NULL);
229 
230                 ASSERT(u != NULL);
231                 u->RotNum = 0;
232                 u->WaitTics = sp->lotag * 120;
233 
234                 u->ActorActionFunc = GenerateDrips;
235 
236                 change_sprite_stat(SpriteNum, STAT_NO_STATE);
237                 SET(sp->cstat, CSTAT_SPRITE_INVISIBLE);
238                 }
239             break;
240             // Sprites in editart that should play ambient sounds
241             // automatically
242         case 380:
243         case 396:
244         case 430:
245         case 443:
246         case 512:
247         case 521:
248         case 541:
249         case 2720:
250         case 3143:
251         case 3157:
252             handle = PlaySound(DIGI_FIRE1, &sp->x, &sp->y, &sp->z, v3df_follow|v3df_dontpan|v3df_doppler);
253             if (handle != -1)
254                 Set3DSoundOwner(SpriteNum);
255             break;
256         case 795:
257         case 880:
258             handle = PlaySound(DIGI_WATERFLOW1, &sp->x, &sp->y, &sp->z, v3df_follow|v3df_dontpan|v3df_doppler);
259             if (handle != -1)
260                 Set3DSoundOwner(SpriteNum);
261             break;
262         case 460:  // Wind Chimes
263             handle = PlaySound(79, &sp->x, &sp->y, &sp->z, v3df_ambient | v3df_init
264                 | v3df_doppler | v3df_follow);
265             if (handle != -1)
266                 Set3DSoundOwner(SpriteNum);
267             break;
268 
269             }
270         }
271     // Check for certain walls to make sounds
272     for (i = 0; i < numwalls; i++)
273         {
274         short picnum;
275         short sndnum;
276 
277 
278         picnum = wall[i].picnum;
279 
280         // Set the don't stick bit for liquid tiles
281         switch(picnum)
282             {
283             case 175:
284             case 179:
285             case 300:
286             case 320:
287             case 330:
288             case 352:
289             case 780:
290             case 890:
291             case 2608:
292             case 2616:
293             //case 3834:
294                 SET(wall[i].extra, WALLFX_DONT_STICK);
295             break;
296             }
297 
298         #if 0
299         if ((sndnum = CheckTileSound(picnum)) != -1)
300             {
301             SpawnWallSound(sndnum, i);
302             }
303         picnum = wall[i].overpicnum;
304         if ((sndnum = CheckTileSound(picnum)) != -1)
305             {
306             SpawnWallSound(sndnum, i);
307             }
308         #endif
309         }
310     }
311 
312 
313 /////////////////////////////////////////////////////
314 //  Initialize the mirrors
315 /////////////////////////////////////////////////////
316 void
JS_InitMirrors(void)317 JS_InitMirrors(void)
318     {
319     short startwall, endwall, dasector;
320     int i, j, k, s, dax, day, daz, dax2, day2;
321     short SpriteNum = 0, NextSprite;
322     SPRITEp sp;
323     static short on_cam = 0;
324     BOOL Found_Cam = FALSE;
325 
326 
327     // Set all the mirror struct values to -1
328     memset(mirror, 0xFF, sizeof(mirror));
329 
330     mirrorinview = FALSE;               // Initially set global mirror flag
331     // to no mirrors seen
332 
333     // Scan wall tags for mirrors
334     mirrorcnt = 0;
335     tilesizx[MIRROR] = 0;
336     tilesizy[MIRROR] = 0;
337 
338     for (i = 0; i < MAXMIRRORS; i++)
339         {
340         tilesizx[i + MIRRORLABEL] = 0;
341         tilesizy[i + MIRRORLABEL] = 0;
342         mirror[i].campic = -1;
343         mirror[i].camsprite = -1;
344         mirror[i].camera = -1;
345         mirror[i].ismagic = FALSE;
346         }
347 
348     for (i = 0; i < numwalls; i++)
349         {
350         s = wall[i].nextsector;
351         if ((s >= 0) && (wall[i].overpicnum == MIRROR) && (wall[i].cstat & 32))
352             {
353             if ((sector[s].floorstat & 1) == 0)
354                 {
355                 wall[i].overpicnum = MIRRORLABEL + mirrorcnt;
356 		wall[i].picnum = MIRRORLABEL + mirrorcnt;
357                 sector[s].ceilingpicnum = MIRRORLABEL + mirrorcnt;
358                 sector[s].floorpicnum = MIRRORLABEL + mirrorcnt;
359                 sector[s].floorstat |= 1;
360                 mirror[mirrorcnt].mirrorwall = i;
361                 mirror[mirrorcnt].mirrorsector = s;
362                 mirror[mirrorcnt].numspawnspots = 0;
363                 mirror[mirrorcnt].ismagic = FALSE;
364                 if (wall[i].lotag == TAG_WALL_MAGIC_MIRROR)
365                     {
366                     short ii, nextii;
367                     SPRITEp sp;
368                     USERp u;
369 
370                     mirror[mirrorcnt].ismagic = TRUE;
371                     Found_Cam = FALSE;
372                     TRAVERSE_SPRITE_STAT(headspritestat[STAT_ST1], ii, nextii)
373                         {
374                         sp = &sprite[ii];
375                         // if correct type and matches
376                         if (sp->hitag == MIRROR_CAM && sp->lotag == wall[i].hitag)
377                             {
378                             mirror[mirrorcnt].camera = ii;
379                             // Set up camera varialbes
380                             SP_TAG5(sp) = sp->ang;      // Set current angle to
381                                                         // sprite angle
382                             Found_Cam = TRUE;
383                             }
384                         }
385 
386                     ii = nextii = 0;
387                     TRAVERSE_SPRITE_STAT(headspritestat[STAT_SPAWN_SPOT], ii, nextii)
388                         {
389 
390                         sp = &sprite[ii];
391 
392                         // if correct type and matches
393                         if (sp->hitag == MIRROR_CAM && sp->lotag == wall[i].hitag)
394                             {
395                             mirror[mirrorcnt].camera = ii;
396                             // Set up camera varialbes
397                             SP_TAG5(sp) = sp->ang;      // Set current angle to
398                                                         // sprite angle
399                             Found_Cam = TRUE;
400                             }
401                         }
402 
403                     if(!Found_Cam)
404                         {
405                         printf("Cound not find the camera view sprite for match %d\n",wall[i].hitag);
406                         printf("Map Coordinates: x = %d, y = %d\n",wall[i].x,wall[i].y);
407                         exit(0);
408                         }
409 
410                     Found_Cam = FALSE;
411                     if(TEST_BOOL1(&sprite[mirror[mirrorcnt].camera]))
412                         {
413                         TRAVERSE_SPRITE_STAT(headspritestat[0], SpriteNum, NextSprite)
414                             {
415                             sp = &sprite[SpriteNum];
416                             if (sp->picnum >= CAMSPRITE && sp->picnum < CAMSPRITE + 8 &&
417                                 sp->hitag == wall[i].hitag)
418                                 {
419                                 mirror[mirrorcnt].campic = sp->picnum;
420                                 mirror[mirrorcnt].camsprite = SpriteNum;
421 
422 				// JBF: commenting out this line results in the screen in $BULLET being visible
423                                 tilesizx[mirror[mirrorcnt].campic] = tilesizy[mirror[mirrorcnt].campic] = 0;
424 
425                                 Found_Cam = TRUE;
426                                 }
427                             }
428 
429                         if(!Found_Cam)
430                             {
431                             printf("Did not find drawtotile for camera number %d\n",mirrorcnt);
432                             printf("wall[%d].hitag == %d\n",i,wall[i].hitag);
433                             printf("Map Coordinates: x = %d, y = %d\n",wall[i].x,wall[i].y);
434                             exit(0);
435                             }
436                         }
437 
438                     // For magic mirrors, set allowable viewing time to 30
439                     // secs
440                     // Base rate is supposed to be 120, but time is double
441                     // what I expect
442                     mirror[mirrorcnt].maxtics = 60 * 30;
443 
444                     }
445 
446                 mirror[mirrorcnt].mstate = m_normal;
447 
448                 // Set tics used to none
449                 mirror[mirrorcnt].tics = 0;
450 
451                 if (mirror[mirrorcnt].ismagic)
452                     {
453                     //DSPRINTF(ds, "mirror.mirrorwall %d", mirror[mirrorcnt].mirrorwall);
454                     MONO_PRINT(ds);
455                     //DSPRINTF(ds, "mirror.mirrorsector %d", mirror[mirrorcnt].mirrorsector);
456                     MONO_PRINT(ds);
457                     //DSPRINTF(ds, "mirror.camera %d", mirror[mirrorcnt].camera);
458                     MONO_PRINT(ds);
459                     }
460 
461                 mirrorcnt++;
462                 ASSERT(mirrorcnt < MAXMIRRORS);
463                 }
464             else
465                 wall[i].overpicnum = sector[s].ceilingpicnum;
466             }
467         }
468 
469     // Invalidate textures in sector behind mirror
470     for (i = 0; i < mirrorcnt; i++)
471         {
472         startwall = sector[mirror[i].mirrorsector].wallptr;
473         endwall = startwall + sector[mirror[i].mirrorsector].wallnum;
474         for (j = startwall; j < endwall; j++)
475             {
476             wall[j].picnum = MIRROR;
477             wall[j].overpicnum = MIRROR;
478             }
479         }
480 
481     }                                   // InitMirrors
482 
483 /////////////////////////////////////////////////////
484 //  Draw a 3d screen to a specific tile
485 /////////////////////////////////////////////////////
486 #if 1
drawroomstotile(int daposx,int daposy,int daposz,short daang,int dahoriz,short dacursectnum,short tilenume)487 void drawroomstotile(int daposx, int daposy, int daposz,
488 	 short daang, int dahoriz, short dacursectnum, short tilenume)
489 {
490     if (waloff[tilenume] == 0)
491         loadtile(tilenume);
492 
493     PRODUCTION_ASSERT(waloff[tilenume]);
494 
495 	setviewtotile(tilenume, tilesizx[tilenume], tilesizy[tilenume]);
496 
497 	drawrooms(daposx, daposy, daposz, daang, dahoriz, dacursectnum);
498 	analyzesprites(daposx, daposy, daposz, FALSE);
499 	drawmasks();
500 
501 	setviewback();
502 
503 	squarerotatetile(tilenume);
504 
505 #if USE_POLYMOST && USE_OPENGL
506 	invalidatetile(tilenume, -1, -1);
507 #endif
508 }
509 #else
510 void
drawroomstotile(int daposx,int daposy,int daposz,short daang,int dahoriz,short dacursectnum,short tilenume)511 drawroomstotile(int daposx, int daposy, int daposz,
512     short daang, int dahoriz, short dacursectnum, short tilenume)
513     {
514 
515     int i, j, k, bakchainnumpages, bakvidoption;
516     intptr_t bakframeplace;
517     int bakwindowx1, bakwindowy1, bakwindowx2, bakwindowy2, xsiz, ysiz;
518     char *ptr1, *ptr2;
519 
520     // DRAWROOMS TO TILE BACKUP&SET CODE
521     xsiz = tilesizx[tilenume];
522     ysiz = tilesizy[tilenume];
523     // bakchainnumpages = chainnumpages;
524     bakchainnumpages = numpages;
525     // chainnumpages = 0;
526     numpages = 0;
527     bakvidoption = vidoption;
528     vidoption = 1;
529     if (waloff[tilenume] == 0)
530         loadtile(tilenume);
531     bakframeplace = frameplace;
532     frameplace = waloff[tilenume];
533     bakwindowx1 = windowx1;
534     bakwindowy1 = windowy1;
535     bakwindowx2 = windowx2;
536     bakwindowy2 = windowy2;
537     setview(0, 0, xsiz - 1, ysiz - 1);
538     setvlinebpl(xsiz);
539     j = 0;
540     for (i = 0; i <= ysiz; i++)
541         {
542         ylookup[i] = j, j += xsiz;
543         }
544 
545     // DRAWS TO TILE HERE
546     drawrooms(daposx, daposy, daposz, daang, dahoriz, dacursectnum + MAXSECTORS);
547     analyzesprites(daposx, daposy, daposz, FALSE);
548     drawmasks();
549 
550     setviewback();
551 
552     // ROTATE TILE (supports square tiles only for rotation part)
553     if (xsiz == ysiz)
554         {
555         k = (xsiz << 1);
556         for (i = xsiz - 1; i >= 0; i--)
557             {
558             ptr1 = (char *) (waloff[tilenume] + i * (xsiz + 1));
559             ptr2 = ptr1;
560             if ((i & 1) != 0)
561                 {
562                 ptr1--;
563                 ptr2 -= xsiz;
564                 swapchar(ptr1, ptr2);
565                 }
566             for (j = (i >> 1) - 1; j >= 0; j--)
567                 {
568                 ptr1 -= 2;
569                 ptr2 -= k;
570                 swapchar2(ptr1, ptr2, xsiz);
571                 // swapchar(ptr1,ptr2);
572                 // swapchar(ptr1+1,ptr2+xsiz);
573                 }
574             }
575         }
576 
577     // DRAWROOMS TO TILE RESTORE CODE
578     setview(bakwindowx1, bakwindowy1, bakwindowx2, bakwindowy2);
579     // chainnumpages = bakchainnumpages;
580     numpages = bakchainnumpages;
581     vidoption = bakvidoption;
582     frameplace = bakframeplace;
583     j = 0;
584     // if (chainnumpages >= 2)
585     if (numpages >= 2)
586         {
587         for (i = 0; i <= ysiz; i++)
588             ylookup[i] = j, j += (xdim >> 2);
589         }
590     else
591         {
592         for (i = 0; i <= ysiz; i++)
593             ylookup[i] = j, j += xdim;
594         }
595     setvlinebpl(ylookup[1]);
596     }
597 #endif
598 
599 void
JS_ProcessEchoSpot()600 JS_ProcessEchoSpot()
601     {
602     short i,nexti;
603     SPRITEp tp;
604     int j,dist;
605     PLAYERp pp = Player+screenpeek;
606     SHORT reverb;
607     BOOL reverb_set = FALSE;
608 
609     // Process echo sprites
610     TRAVERSE_SPRITE_STAT(headspritestat[STAT_ECHO], i, nexti)
611         {
612         dist = 0x7fffffff;
613 
614         tp = &sprite[i];
615 
616         j = klabs(tp->x - pp->posx);
617         j += klabs(tp->y - pp->posy);
618         if (j < dist)
619             dist = j;
620 
621         if(dist <= SP_TAG4(tp)) // tag4 = ang
622             {
623             reverb = SP_TAG2(tp);
624             if(reverb > 200) reverb = 200;
625             if(reverb < 100) reverb = 100;
626 
627             COVER_SetReverb(reverb);
628             reverb_set = TRUE;
629             }
630         }
631         if (!TEST(pp->Flags, PF_DIVING) && !reverb_set && pp->Reverb <= 0)
632             COVER_SetReverb(0);
633     }
634 
635 /////////////////////////////////////////////////////
636 //  Draw one mirror, the one closest to player
637 //  Cams and see to teleporters do NOT support room above room!
638 /////////////////////////////////////////////////////
639 #define MAXCAMDIST 8000
640 
641 int camloopcnt = 0;                    // Timer to cycle through player
642                                         // views
643 short camplayerview = 1;                // Don't show yourself!
644 
645 void
JS_DrawMirrors(PLAYERp pp,int tx,int ty,int tz,short tpang,int tphoriz)646 JS_DrawMirrors(PLAYERp pp, int tx, int ty, int tz, short tpang, int tphoriz)
647     {
648     int j, dx, dy, top, bot, cnt;
649     int x1, y1, x2, y2, ox1, oy1, ox2, oy2, dist, maxdist;
650     int tposx, tposy, thoriz;
651     int tcx, tcy, tcz;                 // Camera
652     int tiltlock, *longptr;
653     short tang;
654     char ch, *ptr, *ptr2, *ptr3, *ptr4;
655     char tvisibility, palok;
656 
657 //    long tx, ty, tz, tpang;             // Interpolate so mirror doesn't
658     // drift!
659     BOOL bIsWallMirror = FALSE;
660 
661     MirrorMoveSkip16 = (MirrorMoveSkip16 + 1) & 15;
662 
663     camloopcnt += (totalclock - ototalclock);
664     if (camloopcnt > (60 * 5))          // 5 seconds per player view
665         {
666         camloopcnt = 0;
667         camplayerview++;
668         if (camplayerview >= CommPlayers)
669             camplayerview = 1;
670         }
671 
672     // WARNING!  Assuming (MIRRORLABEL&31) = 0 and MAXMIRRORS = 64 <-- JBF: wrong
673     longptr = (int *)&gotpic[MIRRORLABEL >> 3];
674     if (longptr && (longptr[0] || longptr[1]))
675         {
676         for (cnt = MAXMIRRORS - 1; cnt >= 0; cnt--)
677             //if (TEST_GOTPIC(cnt + MIRRORLABEL) || TEST_GOTPIC(cnt + CAMSPRITE))
678             if (TEST_GOTPIC(cnt + MIRRORLABEL) || TEST_GOTPIC(mirror[cnt].campic))
679                 {
680                 bIsWallMirror = FALSE;
681                 if (TEST_GOTPIC(cnt + MIRRORLABEL))
682                     {
683                     bIsWallMirror = TRUE;
684                     RESET_GOTPIC(cnt + MIRRORLABEL);
685                     }
686                 //else if (TEST_GOTPIC(cnt + CAMSPRITE))
687                 else if (TEST_GOTPIC(mirror[cnt].campic))
688                     {
689                     //RESET_GOTPIC(cnt + CAMSPRITE);
690                     RESET_GOTPIC(mirror[cnt].campic);
691                     }
692 
693                 mirrorinview = TRUE;
694 
695 //                tx = pp->oposx + mulscale(pp->posx - pp->oposx, smoothratio, 16);
696 //                ty = pp->oposy + mulscale(pp->posy - pp->oposy, smoothratio, 16);
697 //                tz = pp->oposz + mulscale(pp->posz - pp->oposz, smoothratio, 16);
698 //                tpang = pp->oang + mulscale(((pp->pang + 1024 - pp->oang) & 2047) - 1024, smoothratio, 16);
699 
700 
701                 dist = 0x7fffffff;
702 
703                 if (bIsWallMirror)
704                     {
705                     j = klabs(wall[mirror[cnt].mirrorwall].x - tx);
706                     j += klabs(wall[mirror[cnt].mirrorwall].y - ty);
707                     if (j < dist)
708                         dist = j;
709                     }
710                 else
711                     {
712                     SPRITEp tp;
713 
714                     tp = &sprite[mirror[cnt].camsprite];
715 
716                     j = klabs(tp->x - tx);
717                     j += klabs(tp->y - ty);
718                     if (j < dist)
719                         dist = j;
720                     }
721 
722 
723 
724 //              //DSPRINTF(ds,"mirror.tics == %ul", mirror[i].tics);
725 //              MONO_PRINT(ds);
726 
727 
728                 if (mirror[cnt].ismagic)
729                     {
730                     SPRITEp sp=NULL;
731                     int camhoriz;
732                     short wall_ang, w, nw, da, tda;
733                     int dx, dy, dz, tdx, tdy, tdz, midx, midy;
734 
735 
736                     ASSERT(mirror[cnt].camera != -1);
737 
738                     sp = &sprite[mirror[cnt].camera];
739 
740                     ASSERT(sp);
741 
742                     // tvisibility = visibility;
743 //                  visibility <<= 1;       // Make mirror darker
744 
745                     // Make TV cam style mirror seem to shimmer
746 //                  if (mirror[cnt].ismagic && STD_RANDOM_P2(256) > 128)
747 //                      visibility -= STD_RANDOM_P2(128);
748 
749                     // Calculate the angle of the mirror wall
750                     w = mirror[cnt].mirrorwall;
751                     nw = wall[w].point2;
752 
753                     // Get wall midpoint for offset in mirror view
754                     midx = (wall[w].x + wall[wall[w].point2].x) / 2;
755                     midy = (wall[w].y + wall[wall[w].point2].y) / 2;
756 
757                     // Finish finding offsets
758                     tdx = klabs(midx - tx);
759                     tdy = klabs(midy - ty);
760 
761                     if (midx >= tx)
762                         dx = sp->x - tdx;
763                     else
764                         dx = sp->x + tdx;
765 
766                     if (midy >= ty)
767                         dy = sp->y - tdy;
768                     else
769                         dy = sp->y + tdy;
770 
771                     tdz = klabs(tz - sp->z);
772                     if (tz >= sp->z)
773                         dz = sp->z + tdz;
774                     else
775                         dz = sp->z - tdz;
776 
777 
778                     // Is it a TV cam or a teleporter that shows destination?
779                     // TRUE = It's a TV cam
780                     mirror[cnt].mstate = m_normal;
781                     if (TEST_BOOL1(sp))
782                         mirror[cnt].mstate = m_viewon;
783 
784                     // Show teleport destination
785                     // NOTE: Adding MAXSECTORS lets you draw a room, even if
786                     // you are outside of it!
787                     if (mirror[cnt].mstate != m_viewon)
788                         {
789                         tilesizx[MIRROR] = tilesizy[MIRROR] = 0;
790                         // Set TV camera sprite size to 0 to show mirror
791                         // behind in this case!
792 
793                         if(mirror[cnt].campic != -1)
794                             tilesizx[mirror[cnt].campic] = tilesizy[mirror[cnt].campic] = 0;
795                         drawrooms(dx, dy, dz, tpang, tphoriz, sp->sectnum + MAXSECTORS);
796                         analyzesprites(dx, dy, dz, FALSE);
797                         drawmasks();
798                         }
799                     else
800                         {
801                         BOOL DoCam = FALSE;
802 
803                         if(mirror[cnt].campic == -1)
804                             {
805                             TerminateGame();
806                             printf("Missing campic for mirror %d\n",cnt);
807                             printf("Map Coordinates: x = %d, y = %d\n",midx,midy);
808                             exit(0);
809                             }
810 
811                         // BOOL2 = Oscilate camera
812                         if (TEST_BOOL2(sp) && MoveSkip2 == 0)
813                             {
814                             if (TEST_BOOL3(sp)) // If true add increment to
815                                                 // angle else subtract
816                                 {
817                                 // Store current angle in TAG5
818                                 SP_TAG5(sp) = NORM_ANGLE((SP_TAG5(sp) + 4));
819 
820                                 // TAG6 = Turn radius
821                                 if (klabs(GetDeltaAngle(SP_TAG5(sp), sp->ang)) >= SP_TAG6(sp))
822                                     {
823                                     RESET_BOOL3(sp);    // Reverse turn
824                                                         // direction.
825                                     }
826                                 }
827                             else
828                                 {
829                                 // Store current angle in TAG5
830                                 SP_TAG5(sp) = NORM_ANGLE((SP_TAG5(sp) - 4));
831 
832                                 // TAG6 = Turn radius
833                                 if (klabs(GetDeltaAngle(SP_TAG5(sp), sp->ang)) >= SP_TAG6(sp))
834                                     {
835                                     SET_BOOL3(sp);      // Reverse turn
836                                                         // direction.
837                                     }
838                                 }
839                             }
840                         else if (!TEST_BOOL2(sp))
841                             {
842                             SP_TAG5(sp) = sp->ang;      // Copy sprite angle to
843                                                         // tag5
844                             }
845 
846                         // See if there is a horizon value.  0 defaults to
847                         // 100!
848                         if (SP_TAG7(sp) != 0)
849                             {
850                             camhoriz = SP_TAG7(sp);
851                             if (camhoriz > PLAYER_HORIZ_MAX)
852                                 camhoriz = PLAYER_HORIZ_MAX;
853                             else if (camhoriz < PLAYER_HORIZ_MIN)
854                                 camhoriz = PLAYER_HORIZ_MIN;
855                             }
856                         else
857                             camhoriz = 100;     // Default
858 
859                         // If player is dead still then update at MoveSkip4
860                         // rate.
861                         if (pp->posx == pp->oposx && pp->posy == pp->oposy && pp->posz == pp->oposz)
862                             DoCam = TRUE;
863 
864 
865                         // Set up the tile for drawing
866                         tilesizx[mirror[cnt].campic] = tilesizy[mirror[cnt].campic] = 128;
867 
868                         if (MirrorMoveSkip16 == 0 || (DoCam && (MoveSkip4 == 0)))
869                             {
870                             if (dist < MAXCAMDIST)
871                                 {
872                                 PLAYERp cp = Player + camplayerview;
873 
874                                 if (TEST_BOOL11(sp) && CommPlayers > 1)
875                                     {
876                                     drawroomstotile(cp->posx, cp->posy, cp->posz, cp->pang, cp->horiz, cp->cursectnum, mirror[cnt].campic);
877                                     }
878                                 else
879                                     {
880                                     drawroomstotile(sp->x, sp->y, sp->z, SP_TAG5(sp), camhoriz, sp->sectnum, mirror[cnt].campic);
881                                     }
882                                 }
883                             }
884                         }
885                     }
886                 else
887                     {                   // It's just a mirror
888                     // Prepare drawrooms for drawing mirror and calculate
889                     // reflected
890                     // position into tposx, tposy, and tang (tposz == cposz)
891                     // Must call preparemirror before drawrooms and
892                     // completemirror after drawrooms
893 
894                     preparemirror(tx, ty, tz, tpang, tphoriz,
895                         mirror[cnt].mirrorwall, mirror[cnt].mirrorsector, &tposx, &tposy, &tang);
896 
897                     drawrooms(tposx, tposy, tz, tang, tphoriz, mirror[cnt].mirrorsector + MAXSECTORS);
898 
899                     analyzesprites(tposx, tposy, tz, TRUE);
900                     drawmasks();
901 
902                     completemirror();   // Reverse screen x-wise in this
903                     // function
904                     }
905 
906 
907                 // visibility = tvisibility;
908                 // visibility = NormalVisibility;
909 
910                 // drawrooms(tx, ty, tz, tpang, tphoriz, pp->cursectnum);
911                 // Clean up anything that the camera view might have done
912                 SetFragBar(pp);
913                 tilesizx[MIRROR] = tilesizy[MIRROR] = 0;
914                 wall[mirror[cnt].mirrorwall].overpicnum = MIRRORLABEL + cnt;
915                 }
916             else
917                 mirrorinview = FALSE;
918         }
919     }
920 
921 void
DoAutoSize(SPRITEp tspr)922 DoAutoSize(SPRITEp tspr)
923     {
924     short i;
925 
926     if (!bAutoSize)
927         return;
928 
929     switch (tspr->picnum)
930         {
931     case ICON_STAR:                     // 1793
932         break;
933     case ICON_UZI:                      // 1797
934         tspr->xrepeat = 43;
935         tspr->yrepeat = 40;
936         break;
937     case ICON_UZIFLOOR:         // 1807
938         tspr->xrepeat = 43;
939         tspr->yrepeat = 40;
940         break;
941     case ICON_LG_UZI_AMMO:              // 1799
942         break;
943     case ICON_HEART:                    // 1824
944         break;
945     case ICON_HEART_LG_AMMO:            // 1820
946         break;
947     case ICON_GUARD_HEAD:               // 1814
948         break;
949     case ICON_FIREBALL_LG_AMMO: // 3035
950         break;
951     case ICON_ROCKET:                   // 1843
952         break;
953     case ICON_SHOTGUN:                  // 1794
954         tspr->xrepeat = 57;
955         tspr->yrepeat = 58;
956         break;
957     case ICON_LG_ROCKET:                // 1796
958         break;
959     case ICON_LG_SHOTSHELL:             // 1823
960         break;
961     case ICON_MICRO_GUN:                // 1818
962         break;
963     case ICON_MICRO_BATTERY:            // 1800
964         break;
965     case ICON_GRENADE_LAUNCHER: // 1817
966         tspr->xrepeat = 54;
967         tspr->yrepeat = 52;
968         break;
969     case ICON_LG_GRENADE:               // 1831
970         break;
971     case ICON_LG_MINE:                  // 1842
972         break;
973     case ICON_RAIL_GUN:         // 1811
974         tspr->xrepeat = 50;
975         tspr->yrepeat = 54;
976         break;
977     case ICON_RAIL_AMMO:                // 1812
978         break;
979     case ICON_SM_MEDKIT:                // 1802
980         break;
981     case ICON_MEDKIT:                   // 1803
982         break;
983     case ICON_CHEMBOMB:
984         tspr->xrepeat = 64;
985         tspr->yrepeat = 47;
986         break;
987     case ICON_FLASHBOMB:
988         tspr->xrepeat = 32;
989         tspr->yrepeat = 34;
990         break;
991     case ICON_NUKE:
992         break;
993     case ICON_CALTROPS:
994         tspr->xrepeat = 37;
995         tspr->yrepeat = 30;
996         break;
997     case ICON_BOOSTER:                  // 1810
998         tspr->xrepeat = 30;
999         tspr->yrepeat = 38;
1000         break;
1001     case ICON_HEAT_CARD:                // 1819
1002         tspr->xrepeat = 46;
1003         tspr->yrepeat = 47;
1004         break;
1005     case ICON_REPAIR_KIT:               // 1813
1006         break;
1007     case ICON_EXPLOSIVE_BOX:            // 1801
1008         break;
1009     case ICON_ENVIRON_SUIT:             // 1837
1010         break;
1011     case ICON_FLY:                      // 1782
1012         break;
1013     case ICON_CLOAK:                    // 1826
1014         break;
1015     case ICON_NIGHT_VISION:             // 3031
1016         tspr->xrepeat = 59;
1017         tspr->yrepeat = 71;
1018         break;
1019     case ICON_NAPALM:                   // 3046
1020         break;
1021     case ICON_RING:                     // 3050
1022         break;
1023     case ICON_RINGAMMO:         // 3054
1024         break;
1025     case ICON_NAPALMAMMO:               // 3058
1026         break;
1027     case ICON_GRENADE:                  // 3059
1028         break;
1029     case ICON_ARMOR:                    // 3030
1030         tspr->xrepeat = 82;
1031         tspr->yrepeat = 84;
1032         break;
1033     case BLUE_KEY:                      // 1766
1034         break;
1035     case RED_KEY:                       // 1770
1036         break;
1037     case GREEN_KEY:                     // 1774
1038         break;
1039     case YELLOW_KEY:                    // 1778
1040         break;
1041     case BLUE_CARD:
1042     case RED_CARD:
1043     case GREEN_CARD:
1044     case YELLOW_CARD:
1045         tspr->xrepeat = 36;
1046         tspr->yrepeat = 33;
1047         break;
1048     case GOLD_SKELKEY:
1049     case SILVER_SKELKEY:
1050     case BRONZE_SKELKEY:
1051     case RED_SKELKEY:
1052         tspr->xrepeat = 39;
1053         tspr->yrepeat = 45;
1054         break;
1055     case SKEL_LOCKED:
1056     case SKEL_UNLOCKED:
1057         tspr->xrepeat = 47;
1058         tspr->yrepeat = 40;
1059         break;
1060     case RAMCARD_LOCKED:
1061     case RAMCARD_UNLOCKED:
1062     case CARD_LOCKED:
1063     case CARD_UNLOCKED:
1064         break;
1065     default:
1066         break;
1067         }
1068     }
1069 
1070 // Rotation angles for sprites
1071 short rotang = 0;
1072 
1073 void
JAnalyzeSprites(SPRITEp tspr)1074 JAnalyzeSprites(SPRITEp tspr)
1075     {
1076     int i, currsprite;
1077 
1078     rotang += 4;
1079     if (rotang > 2047)
1080         rotang = 0;
1081 
1082 
1083     // Take care of autosizing
1084     DoAutoSize(tspr);
1085 
1086 #if USE_POLYMOST && USE_OPENGL
1087     if (getrendermode() == 3 && md_tilehasmodel(tspr->picnum) >= 0 && usemodels) return;
1088 #endif
1089 
1090     // Check for voxels
1091     //if (bVoxelsOn)
1092     if (gs.Voxels)
1093         {
1094         if (aVoxelArray[tspr->picnum].Voxel >= 0)
1095             {
1096             // Turn on voxels
1097             tspr->picnum = aVoxelArray[tspr->picnum].Voxel;     // Get the voxel number
1098             tspr->cstat |= 48;          // Set stat to voxelize sprite
1099             }
1100         }
1101     else
1102         {
1103         switch (tspr->picnum)
1104             {
1105             case 764: // Gun barrel
1106 
1107                 if (aVoxelArray[tspr->picnum].Voxel >= 0)
1108                     {
1109                     // Turn on voxels
1110                     tspr->picnum = aVoxelArray[tspr->picnum].Voxel;     // Get the voxel number
1111                     tspr->cstat |= 48;          // Set stat to voxelize sprite
1112                     }
1113                   break;
1114             }
1115         }
1116     }
1117 
1118 //////////////////////////////////////////////////////////////////////////////////////////////
1119 // Parental Lockout Stuff
1120 //////////////////////////////////////////////////////////////////////////////////////////////
1121 OrgTileList orgwalllist;                // The list containing orginal wall
1122                                         // pics
1123 OrgTileList orgwalloverlist;            // The list containing orginal wall
1124                                         // over pics
1125 OrgTileList orgsectorceilinglist;       // The list containing orginal sector
1126                                         // ceiling pics
1127 OrgTileList orgsectorfloorlist;         // The list containing orginal sector
1128                                         // floor pics
1129 
1130 void
InsertOrgTile(OrgTileP tp,OrgTileListP thelist)1131 InsertOrgTile(OrgTileP tp, OrgTileListP thelist)
1132     {
1133     OrgTileP cur, nxt;
1134 
1135     ASSERT(tp);
1136     ASSERT(ValidPtr(tp));
1137 
1138     // if list is empty, insert at front
1139     if (EMPTY(thelist))
1140         {
1141         INSERT(thelist, tp);
1142         return;
1143         }
1144 
1145     // Otherwise insert it at end
1146     INSERT_TAIL(thelist, tp);
1147     return;
1148     }
1149 
1150 
1151 OrgTileP
InitOrgTile(OrgTileListP thelist)1152 InitOrgTile(OrgTileListP thelist)
1153     {
1154     int i;
1155     OrgTileP tp;
1156 
1157 
1158     tp = CallocMem(sizeof(OrgTile), 1);
1159 
1160     ASSERT(tp);
1161 
1162     InsertOrgTile(tp, thelist);
1163 
1164     return (tp);
1165     }
1166 
1167 VOID
KillOrgTile(OrgTileP tp)1168 KillOrgTile(OrgTileP tp)
1169     {
1170     ASSERT(tp);
1171     ASSERT(ValidPtr(tp));
1172 
1173     DELETE(tp);
1174 
1175     FreeMem(tp);
1176     }
1177 
1178 OrgTileP
FindOrgTile(short index,OrgTileListP thelist)1179 FindOrgTile(short index, OrgTileListP thelist)
1180     {
1181     OrgTileP tp, next_tp;
1182 
1183     if (EMPTY(thelist))
1184         return (NULL);
1185 
1186     TRAVERSE(thelist, tp, next_tp)
1187         {
1188         if (tp->index == index)
1189             return (tp);
1190         }
1191 
1192     return (NULL);
1193     }
1194 
1195 // Call this at terminate game time
1196 VOID
JS_UnInitLockouts(void)1197 JS_UnInitLockouts(void)
1198     {
1199     OrgTileP tp=NULL, next_tp=NULL;
1200 
1201 
1202     TRAVERSE(&orgwalllist, tp, next_tp)
1203         {
1204         KillOrgTile(tp);
1205         }
1206     TRAVERSE(&orgwalloverlist, tp, next_tp)
1207         {
1208         KillOrgTile(tp);
1209         }
1210     TRAVERSE(&orgsectorceilinglist, tp, next_tp)
1211         {
1212         KillOrgTile(tp);
1213         }
1214     TRAVERSE(&orgsectorfloorlist, tp, next_tp)
1215         {
1216         KillOrgTile(tp);
1217         }
1218     }
1219 
1220 /////////////////////////////////////////////////////
1221 //  Initialize the original tiles list
1222 //  Creates a list of all orginal tiles and their
1223 //  replacements.  Several tiles can use the same
1224 //  replacement tilenum, so the list is built
1225 //  using the original tilenums as a basis for
1226 //  memory allocation
1227 //  t == 1 - wall
1228 //  t == 2 - overpicnum
1229 //  t == 3 - ceiling
1230 //  t == 4 - floor
1231 /////////////////////////////////////////////////////
1232 void
JS_PlockError(short wall_num,short t)1233 JS_PlockError(short wall_num, short t)
1234     {
1235     TerminateGame();
1236     printf("ERROR: JS_InitLockouts(), out of range tile number\n");
1237     switch(t)
1238         {
1239         case 1:
1240         printf("wall %d, x %d, y %d, pic %d\n", wall_num, wall[wall_num].x, wall[wall_num].y, wall[wall_num].picnum);
1241         break;
1242         case 2:
1243         printf("wall %d, x %d, y %d, OVERpic %d\n", wall_num, wall[wall_num].x, wall[wall_num].y, wall[wall_num].overpicnum);
1244         break;
1245         case 3:
1246         printf("sector %d, ceiling %d\n", wall_num, sector[wall_num].ceilingpicnum);
1247         break;
1248         case 4:
1249         printf("sector %d, floor %d\n", wall_num, sector[wall_num].floorpicnum);
1250         break;
1251         }
1252     exit(0);
1253     }
1254 
1255 void
JS_InitLockouts(void)1256 JS_InitLockouts(void)
1257     {
1258     SPRITEp sp;
1259     short i, num;
1260     OrgTileP tp;
1261 
1262     INITLIST(&orgwalllist);             // The list containing orginal wall
1263                                         // pics
1264     INITLIST(&orgwalloverlist);         // The list containing orginal wall
1265                                         // over pics
1266     INITLIST(&orgsectorceilinglist);    // The list containing orginal sector
1267                                         // ceiling pics
1268     INITLIST(&orgsectorfloorlist);      // The list containing orginal sector
1269                                         // floor pics
1270 
1271     // Check all walls
1272     for (i = 0; i < numwalls; i++)
1273         {
1274         short picnum;
1275 
1276         picnum = wall[i].picnum;
1277         if(aVoxelArray[picnum].Parental >= INVISTILE)
1278             JS_PlockError(i,1);
1279 
1280         if (aVoxelArray[picnum].Parental >= 0)
1281             {
1282             if ((tp = FindOrgTile(i, &orgwalllist)) == NULL)
1283                 tp = InitOrgTile(&orgwalllist);
1284             tp->index = i;
1285             tp->orgpicnum = wall[i].picnum;
1286             }
1287 
1288         picnum = wall[i].overpicnum;
1289         if(aVoxelArray[picnum].Parental >= INVISTILE)
1290             JS_PlockError(i,2);
1291 
1292         if (aVoxelArray[picnum].Parental >= 0)
1293             {
1294             if ((tp = FindOrgTile(i, &orgwalloverlist)) == NULL)
1295                 tp = InitOrgTile(&orgwalloverlist);
1296             tp->index = i;
1297             tp->orgpicnum = wall[i].overpicnum;
1298             }
1299         }
1300     // Check all ceilings and floors
1301     for (i = 0; i < numsectors; i++)
1302         {
1303         short picnum;
1304 
1305         picnum = sector[i].ceilingpicnum;
1306         if(aVoxelArray[picnum].Parental >= INVISTILE)
1307             JS_PlockError(i,3);
1308 
1309         if (aVoxelArray[picnum].Parental >= 0)
1310             {
1311             if ((tp = FindOrgTile(i, &orgsectorceilinglist)) == NULL)
1312                 tp = InitOrgTile(&orgsectorceilinglist);
1313             tp->index = i;
1314             tp->orgpicnum = sector[i].ceilingpicnum;
1315             }
1316 
1317         picnum = sector[i].floorpicnum;
1318         if(aVoxelArray[picnum].Parental >= INVISTILE)
1319             JS_PlockError(i,2);
1320 
1321         if (aVoxelArray[picnum].Parental >= 0)
1322             {
1323             if ((tp = FindOrgTile(i, &orgsectorfloorlist)) == NULL)
1324                 tp = InitOrgTile(&orgsectorfloorlist);
1325             tp->index = i;
1326             tp->orgpicnum = sector[i].floorpicnum;
1327             }
1328         }
1329     }
1330 
1331 /////////////////////////////////////////////////////
1332 //  Switch back and forth between locked out stuff
1333 /////////////////////////////////////////////////////
1334 void
JS_ToggleLockouts(void)1335 JS_ToggleLockouts(void)
1336     {
1337     SPRITEp sp;
1338     short i, num;
1339     OrgTileP tp;
1340 
1341 
1342     // Check all walls
1343     for (i = 0; i < numwalls; i++)
1344         {
1345         short picnum;
1346 
1347         if (gs.ParentalLock)
1348             {
1349             picnum = wall[i].picnum;
1350             ASSERT(aVoxelArray[picnum].Parental < INVISTILE);   // Invalid, walls can't
1351                                                                 // be invisible
1352             if (aVoxelArray[picnum].Parental >= 0)
1353                 {
1354                 wall[i].picnum = aVoxelArray[picnum].Parental;
1355                 }
1356             }
1357         else if ((tp = FindOrgTile(i, &orgwalllist)) != NULL)
1358             wall[i].picnum = tp->orgpicnum;     // Restore them
1359 
1360 
1361         if (gs.ParentalLock)
1362             {
1363             picnum = wall[i].overpicnum;
1364             ASSERT(aVoxelArray[picnum].Parental < INVISTILE);   // Invalid, walls can't
1365                                                                 // be invisible
1366             if (aVoxelArray[picnum].Parental >= 0)
1367                 {
1368                 wall[i].overpicnum = aVoxelArray[picnum].Parental;
1369                 }
1370             }
1371         else if ((tp = FindOrgTile(i, &orgwalloverlist)) != NULL)
1372             wall[i].overpicnum = tp->orgpicnum; // Restore them
1373         }
1374 
1375     // Check all sectors
1376     for (i = 0; i < numsectors; i++)
1377         {
1378         short picnum;
1379 
1380         if (gs.ParentalLock)
1381             {
1382             picnum = sector[i].ceilingpicnum;
1383             ASSERT(aVoxelArray[picnum].Parental < INVISTILE);   // Invalid, walls can't
1384                                                                 // be invisible
1385             if (aVoxelArray[picnum].Parental >= 0)
1386                 {
1387                 sector[i].ceilingpicnum = aVoxelArray[picnum].Parental;
1388                 }
1389             }
1390         else if ((tp = FindOrgTile(i, &orgsectorceilinglist)) != NULL)
1391             sector[i].ceilingpicnum = tp->orgpicnum;    // Restore them
1392 
1393 
1394         if (gs.ParentalLock)
1395             {
1396             picnum = sector[i].floorpicnum;
1397             ASSERT(aVoxelArray[picnum].Parental < INVISTILE);   // Invalid, walls can't
1398                                                                 // be invisible
1399             if (aVoxelArray[picnum].Parental >= 0)
1400                 {
1401                 sector[i].floorpicnum = aVoxelArray[picnum].Parental;
1402                 }
1403             }
1404         else if ((tp = FindOrgTile(i, &orgsectorfloorlist)) != NULL)
1405             sector[i].floorpicnum = tp->orgpicnum;      // Restore them
1406         }
1407     }
1408 
1409 ////////////////////////////////////////////////////////////////////////////////////////////////
1410 
1411 void
UnlockKeyLock(short key_num,short hitsprite)1412 UnlockKeyLock(short key_num, short hitsprite)
1413     {
1414     SPRITEp sp;
1415     int SpriteNum = 0, NextSprite = 0, color = 0;
1416 
1417     // Get palette by looking at key number
1418     switch (key_num - 1)
1419         {
1420     case 0:                             // RED_KEY
1421         color = PALETTE_PLAYER9;
1422         break;
1423     case 1:                             // BLUE_KEY
1424         color = PALETTE_PLAYER7;
1425         break;
1426     case 2:                             // GREEN_KEY
1427         color = PALETTE_PLAYER6;
1428         break;
1429     case 3:                             // YELLOW_KEY
1430         color = PALETTE_PLAYER4;
1431         break;
1432     case 4:                             // SILVER_SKELKEY
1433         color = PALETTE_PLAYER4;
1434         break;
1435     case 5:                             // GOLD_SKELKEY
1436         color = PALETTE_PLAYER1;
1437         break;
1438     case 6:                             // BRONZE_SKELKEY
1439         color = PALETTE_PLAYER8;
1440         break;
1441     case 7:                             // RED_SKELKEY
1442         color = PALETTE_PLAYER9;
1443         break;
1444         }
1445 
1446     TRAVERSE_SPRITE_STAT(headspritestat[0], SpriteNum, NextSprite)
1447         {
1448         sp = &sprite[SpriteNum];
1449 
1450         switch (sp->picnum)
1451             {
1452         case SKEL_LOCKED:
1453             if (sp->pal == color)
1454                 {
1455                 PlaySound(DIGI_UNLOCK, &sp->x, &sp->y, &sp->z, v3df_doppler | v3df_dontpan);
1456                 if(SpriteNum == hitsprite)
1457                     sp->picnum = SKEL_UNLOCKED;
1458                 }
1459             break;
1460         case RAMCARD_LOCKED:
1461             if (sp->pal == color)
1462                 {
1463                 PlaySound(DIGI_CARDUNLOCK, &sp->x, &sp->y, &sp->z, v3df_doppler | v3df_dontpan);
1464                 sp->picnum = RAMCARD_UNLOCKED;
1465                 }
1466             break;
1467         case CARD_LOCKED:
1468             if (sp->pal == color)
1469                 {
1470                 PlaySound(DIGI_RAMUNLOCK, &sp->x, &sp->y, &sp->z, v3df_doppler | v3df_dontpan);
1471                 if(SpriteNum == hitsprite)
1472                     sp->picnum = CARD_UNLOCKED;
1473                 else
1474                     sp->picnum = CARD_UNLOCKED+1;
1475                 }
1476             break;
1477             }
1478 
1479         }
1480     }
1481