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