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 #include "build.h"
27 
28 #include "names2.h"
29 #include "panel.h"
30 #include "game.h"
31 #include "warp.h"
32 
33 void _ErrMsg(char *strFile, unsigned uLine, char *format, ...);
34 void FAF_DrawRooms(int posx, int posy, int posz, short ang, int horiz, short cursectnum);
35 
36 ////////////////////////////////////////////////////////////////////
37 //
38 // FLOOR ABOVE FLOOR
39 //
40 ////////////////////////////////////////////////////////////////////
41 
42 
43 #define ZMAX 400
44 typedef struct
45     {
46     LONG zval[ZMAX];
47     SHORT sectnum[ZMAX];
48     SHORT pic[ZMAX];
49     SHORT zcount;
50     SHORT slope[ZMAX];
51     } SAVE, *SAVEp;
52 
53 SAVE save;
54 
55 BOOL FAF_DebugView = 0;
56 
COVERupdatesector(LONG x,LONG y,SHORTp newsector)57 VOID COVERupdatesector(LONG x, LONG y, SHORTp newsector)
58     {
59     ASSERT(*newsector>=0 && *newsector<MAXSECTORS);
60     updatesector(x,y,newsector);
61     }
62 
COVERinsertsprite(short sectnum,short stat)63 int COVERinsertsprite(short sectnum, short stat)
64     {
65     short spnum;
66     spnum = insertsprite(sectnum, stat);
67 
68     PRODUCTION_ASSERT(spnum >= 0);
69 
70     sprite[spnum].x = sprite[spnum].y = sprite[spnum].z = 0;
71     sprite[spnum].cstat = 0;
72     sprite[spnum].picnum = 0;
73     sprite[spnum].shade = 0;
74     sprite[spnum].pal = 0;
75     sprite[spnum].clipdist = 0;
76     sprite[spnum].xrepeat = sprite[spnum].yrepeat = 0;
77     sprite[spnum].xoffset = sprite[spnum].yoffset = 0;
78     sprite[spnum].ang = 0;
79     sprite[spnum].owner = -1;
80     sprite[spnum].xvel = sprite[spnum].yvel = sprite[spnum].zvel = 0;
81     sprite[spnum].lotag = 0;
82     sprite[spnum].hitag = 0;
83     sprite[spnum].extra = 0;
84 
85     return(spnum);
86     }
87 
88 BOOL
FAF_Sector(short sectnum)89 FAF_Sector(short sectnum)
90     {
91     short SpriteNum, Next;
92     SPRITEp sp;
93     BOOL found = FALSE;
94 
95     TRAVERSE_SPRITE_SECT(headspritesect[sectnum], SpriteNum, Next)
96         {
97         sp = &sprite[SpriteNum];
98 
99         if (sp->statnum == STAT_FAF &&
100             (sp->hitag >= VIEW_LEVEL1 && sp->hitag <= VIEW_LEVEL6))
101             {
102             return (TRUE);
103             }
104         }
105 
106     return (FALSE);
107     }
108 
SetWallWarpHitscan(short sectnum)109 VOID SetWallWarpHitscan(short sectnum)
110     {
111     short start_wall, wall_num;
112     SPRITEp sp_warp;
113 
114     if (!WarpSectorInfo(sectnum, &sp_warp))
115         return;
116 
117     if (!sp_warp)
118         return;
119 
120     // move the the next wall
121     wall_num = start_wall = sector[sectnum].wallptr;
122 
123     // Travel all the way around loop setting wall bits
124     do
125         {
126         if (wall[wall_num].nextwall >= 0)
127             SET(wall[wall_num].cstat, CSTAT_WALL_WARP_HITSCAN);
128         wall_num = wall[wall_num].point2;
129         }
130     while(wall_num != start_wall);
131     }
132 
ResetWallWarpHitscan(short sectnum)133 VOID ResetWallWarpHitscan(short sectnum)
134     {
135     short start_wall, wall_num;
136 
137     // move the the next wall
138     wall_num = start_wall = sector[sectnum].wallptr;
139 
140     // Travel all the way around loop setting wall bits
141     do
142         {
143         RESET(wall[wall_num].cstat, CSTAT_WALL_WARP_HITSCAN);
144         wall_num = wall[wall_num].point2;
145         }
146     while(wall_num != start_wall);
147     }
148 
149 VOID
FAFhitscan(LONG x,LONG y,LONG z,SHORT sectnum,LONG xvect,LONG yvect,LONG zvect,SHORTp hitsect,SHORTp hitwall,SHORTp hitsprite,LONGp hitx,LONGp hity,LONGp hitz,LONG clipmask)150 FAFhitscan(LONG x, LONG y, LONG z, SHORT sectnum,
151     LONG xvect, LONG yvect, LONG zvect,
152     SHORTp hitsect, SHORTp hitwall, SHORTp hitsprite,
153     LONGp hitx, LONGp hity, LONGp hitz, LONG clipmask)
154     {
155     int loz, hiz;
156     short newsectnum = sectnum;
157     int startclipmask = 0;
158     BOOL plax_found = FALSE;
159     int sx,sy,sz;
160 
161     if (clipmask == CLIPMASK_MISSILE)
162         startclipmask = CLIPMASK_WARP_HITSCAN;
163 
164     hitscan(x, y, z, sectnum, xvect, yvect, zvect,
165         hitsect, hitwall, hitsprite,
166         hitx, hity, hitz, startclipmask);
167 
168     if (*hitsect < 0)
169         return;
170 
171     if (*hitwall >= 0)
172         {
173         // hitscan warping
174         if (TEST(wall[*hitwall].cstat, CSTAT_WALL_WARP_HITSCAN))
175             {
176             short src_sect = *hitsect;
177             short dest_sect;
178 
179             sx = *hitx;
180             sy = *hity;
181             sz = *hitz;
182 
183             //DSPRINTF(ds,"sx %d, sy %d, sz %d, xvect %d, yvect %d",sx, sy, sz,xvect,yvect);
184             MONO_PRINT(ds);
185 
186             // back it up a bit to get a correct warp location
187             *hitx -= xvect>>9;
188             *hity -= yvect>>9;
189 
190             // warp to new x,y,z, sectnum
191             if (Warp(hitx, hity, hitz, hitsect))
192                 {
193                 dest_sect = *hitsect;
194 
195                 // hitscan needs to pass through dest sect
196                 ResetWallWarpHitscan(dest_sect);
197 
198                 // NOTE: This could be recursive I think if need be
199                 hitscan(*hitx, *hity, *hitz, *hitsect, xvect, yvect, zvect,
200                     hitsect, hitwall, hitsprite,
201                     hitx, hity, hitz, startclipmask);
202 
203                 // reset hitscan block for dest sect
204                 SetWallWarpHitscan(dest_sect);
205 
206                 return;
207                 }
208             else
209                 {
210             //DSPRINTF(ds,"hitx %d, hity %d, hitz %d",*hitx, *hity, *hitz);
211             MONO_PRINT(ds);
212                 ASSERT(TRUE == FALSE);
213                 }
214             }
215         }
216 
217     // make sure it hit JUST a sector before doing a check
218     if (*hitwall < 0 && *hitsprite < 0)
219         {
220         if (TEST(sector[*hitsect].extra, SECTFX_WARP_SECTOR))
221             {
222             if (TEST(wall[sector[*hitsect].wallptr].cstat, CSTAT_WALL_WARP_HITSCAN))
223                 {
224                 // hit the floor of a sector that is a warping sector
225                 if (Warp(hitx, hity, hitz, hitsect))
226                     {
227                     hitscan(*hitx, *hity, *hitz, *hitsect, xvect, yvect, zvect,
228                         hitsect, hitwall, hitsprite,
229                         hitx, hity, hitz, clipmask);
230 
231                     return;
232                     }
233                 }
234             else
235                 {
236                 if (WarpPlane(hitx, hity, hitz, hitsect))
237                     {
238                     hitscan(*hitx, *hity, *hitz, *hitsect, xvect, yvect, zvect,
239                         hitsect, hitwall, hitsprite,
240                         hitx, hity, hitz, clipmask);
241 
242                     return;
243                     }
244                 }
245             }
246 
247         getzsofslope(*hitsect, *hitx, *hity, &hiz, &loz);
248         if (labs(*hitz - loz) < Z(4))
249             {
250             if (FAF_ConnectFloor(*hitsect) && !TEST(sector[*hitsect].floorstat, FLOOR_STAT_FAF_BLOCK_HITSCAN))
251                 {
252                 updatesectorz(*hitx, *hity, *hitz + Z(12), &newsectnum);
253                 plax_found = TRUE;
254                 }
255             }
256         else if (labs(*hitz - hiz) < Z(4))
257             {
258             if (FAF_ConnectCeiling(*hitsect) && !TEST(sector[*hitsect].floorstat, CEILING_STAT_FAF_BLOCK_HITSCAN))
259                 {
260                 updatesectorz(*hitx, *hity, *hitz - Z(12), &newsectnum);
261                 plax_found = TRUE;
262                 }
263             }
264         }
265 
266     if (plax_found)
267         {
268         hitscan(*hitx, *hity, *hitz, newsectnum, xvect, yvect, zvect,
269             hitsect, hitwall, hitsprite,
270             hitx, hity, hitz, clipmask);
271         }
272     }
273 
274 BOOL
FAFcansee(LONG xs,LONG ys,LONG zs,SHORT sects,LONG xe,LONG ye,LONG ze,SHORT secte)275 FAFcansee(LONG xs, LONG ys, LONG zs, SHORT sects,
276     LONG xe, LONG ye, LONG ze, SHORT secte)
277     {
278     int loz, hiz;
279     short newsectnum = sects;
280     int xvect, yvect, zvect;
281     short ang;
282     short hitsect, hitwall, hitsprite;
283     int hitx, hity, hitz;
284     int dist;
285     BOOL plax_found = FALSE;
286 
287     ASSERT(sects >= 0 && secte >= 0);
288 
289     // early out to regular routine
290     if (!FAF_Sector(sects) && !FAF_Sector(secte))
291         {
292         return(cansee(xs,ys,zs,sects,xe,ye,ze,secte));
293         }
294     else
295         {
296         }
297 
298     // get angle
299     ang = getangle(xe - xs, ye - ys);
300 
301     // get x,y,z, vectors
302     xvect = sintable[NORM_ANGLE(ang + 512)];
303     yvect = sintable[NORM_ANGLE(ang)];
304 
305     // find the distance to the target
306     dist = ksqrt(SQ(xe - xs) + SQ(ye - ys));
307 
308     if (dist != 0)
309         {
310         if (xe - xs != 0)
311             zvect = scale(xvect, ze - zs, xe - xs);
312         else
313         if (ye - ys != 0)
314             zvect = scale(yvect, ze - zs, ye - ys);
315         else
316             zvect = 0;
317         }
318     else
319         zvect = 0;
320 
321     hitscan(xs, ys, zs, sects, xvect, yvect, zvect,
322     &hitsect, &hitwall, &hitsprite,
323     &hitx, &hity, &hitz, CLIPMASK_MISSILE);
324 
325     if (hitsect < 0)
326         return(FALSE);
327 
328     // make sure it hit JUST a sector before doing a check
329     if (hitwall < 0 && hitsprite < 0)
330         {
331         getzsofslope(hitsect, hitx, hity, &hiz, &loz);
332         if (labs(hitz - loz) < Z(4))
333             {
334             if (FAF_ConnectFloor(hitsect))
335                 {
336                 updatesectorz(hitx, hity, hitz + Z(12), &newsectnum);
337                 plax_found = TRUE;
338                 }
339             }
340         else if (labs(hitz - hiz) < Z(4))
341             {
342             if (FAF_ConnectCeiling(hitsect))
343                 {
344                 updatesectorz(hitx, hity, hitz - Z(12), &newsectnum);
345                 plax_found = TRUE;
346                 }
347             }
348         }
349     else
350         {
351         return(cansee(xs,ys,zs,sects,xe,ye,ze,secte));
352         }
353 
354     if (plax_found)
355         return (cansee(hitx,hity,hitz,newsectnum,xe,ye,ze,secte));
356 
357     return(FALSE);
358     }
359 
360 
361 int
GetZadjustment(short sectnum,short hitag)362 GetZadjustment(short sectnum, short hitag)
363     {
364     short i, nexti;
365     SPRITEp sp;
366 
367     if (!TEST(sector[sectnum].extra, SECTFX_Z_ADJUST))
368         return(0L);
369 
370     TRAVERSE_SPRITE_STAT(headspritestat[STAT_ST1], i, nexti)
371         {
372         sp = &sprite[i];
373 
374         if (sp->hitag == hitag && sp->sectnum == sectnum)
375             {
376             return(Z(sp->lotag));
377             }
378         }
379 
380     return(0L);
381     }
382 
SectorZadjust(int ceilhit,LONGp hiz,short florhit,LONGp loz)383 BOOL SectorZadjust(int ceilhit, LONGp hiz, short florhit, LONGp loz)
384     {
385     extern int PlaxCeilGlobZadjust, PlaxFloorGlobZadjust;
386     int z_amt = 0;
387 
388     BOOL SkipFAFcheck = FALSE;
389 
390     if ((int)florhit != -1)
391         {
392         switch (TEST(florhit, HIT_MASK))
393             {
394             case HIT_SECTOR:
395                 {
396                 short hitsector = NORM_SECTOR(florhit);
397 
398                 // don't jack with connect sectors
399                 if (FAF_ConnectFloor(hitsector))
400                     {
401                     // rippers were dying through the floor in $rock
402                     if (TEST(sector[hitsector].floorstat, CEILING_STAT_FAF_BLOCK_HITSCAN))
403                         break;
404 
405                     if (TEST(sector[hitsector].extra, SECTFX_Z_ADJUST))
406                         {
407                         // see if a z adjust ST1 is around
408                         z_amt = GetZadjustment(hitsector, FLOOR_Z_ADJUST);
409 
410                         if (z_amt)
411                             {
412                             // explicit z adjust overrides Connect Floor
413                             *loz += z_amt;
414                             SkipFAFcheck = TRUE;
415                             }
416                         }
417 
418                     break;
419                     }
420 
421                 if (!TEST(sector[hitsector].extra, SECTFX_Z_ADJUST))
422                     break;
423 
424                 // see if a z adjust ST1 is around
425                 z_amt = GetZadjustment(hitsector, FLOOR_Z_ADJUST);
426 
427                 if (z_amt)
428                     {
429                     // explicit z adjust overrides plax default
430                     *loz += z_amt;
431                     }
432                 else
433                 // default adjustment for plax
434                 if (TEST(sector[hitsector].floorstat, FLOOR_STAT_PLAX))
435                     {
436                     *loz += PlaxFloorGlobZadjust;
437                     }
438 
439                 break;
440                 }
441             }
442         }
443 
444     if ((int)ceilhit != -1)
445         {
446         switch (TEST(ceilhit, HIT_MASK))
447             {
448             case HIT_SECTOR:
449                 {
450                 short hitsector = NORM_SECTOR(ceilhit);
451 
452                 // don't jack with connect sectors
453                 if (FAF_ConnectCeiling(hitsector))
454                     {
455                     if (TEST(sector[hitsector].extra, SECTFX_Z_ADJUST))
456                         {
457                         // see if a z adjust ST1 is around
458                         z_amt = GetZadjustment(hitsector, CEILING_Z_ADJUST);
459 
460                         if (z_amt)
461                             {
462                             // explicit z adjust overrides Connect Floor
463                             *loz += z_amt;
464                             SkipFAFcheck = TRUE;
465                             }
466                         }
467 
468                     break;
469                     }
470 
471                 if (!TEST(sector[hitsector].extra, SECTFX_Z_ADJUST))
472                     break;
473 
474                 // see if a z adjust ST1 is around
475                 z_amt = GetZadjustment(hitsector, CEILING_Z_ADJUST);
476 
477                 if (z_amt)
478                     {
479                     // explicit z adjust overrides plax default
480                     *hiz -= z_amt;
481                     }
482                 else
483                 // default adjustment for plax
484                 if (TEST(sector[hitsector].ceilingstat, CEILING_STAT_PLAX))
485                     {
486                     *hiz -= PlaxCeilGlobZadjust;
487                     }
488 
489                 break;
490                 }
491             }
492         }
493 
494     return(SkipFAFcheck);
495     }
496 
WaterAdjust(short florhit,LONGp loz)497 VOID WaterAdjust(short florhit, LONGp loz)
498     {
499     switch (TEST(florhit, HIT_MASK))
500         {
501         case HIT_SECTOR:
502             {
503             SECT_USERp sectu = SectUser[NORM_SECTOR(florhit)];
504 
505             if (sectu && sectu->depth)
506                 *loz += Z(sectu->depth);
507             }
508             break;
509         case HIT_SPRITE:
510             break;
511         }
512     }
513 
FAFgetzrange(LONG x,LONG y,LONG z,SHORT sectnum,LONGp hiz,LONGp ceilhit,LONGp loz,LONGp florhit,LONG clipdist,LONG clipmask)514 VOID FAFgetzrange(LONG x, LONG y, LONG z, SHORT sectnum,
515     LONGp hiz, LONGp ceilhit,
516     LONGp loz, LONGp florhit,
517     LONG clipdist, LONG clipmask)
518     {
519     int foo1;
520     int foo2;
521     BOOL SkipFAFcheck;
522 
523     // IMPORTANT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
524     // This will return invalid FAF ceiling and floor heights inside of analyzesprite
525     // because the ceiling and floors get moved out of the way for drawing.
526 
527     // early out to regular routine
528     if (!FAF_ConnectArea(sectnum))
529         {
530         getzrange(x, y, z, sectnum, hiz,  ceilhit, loz,  florhit, clipdist, clipmask);
531         SectorZadjust(*ceilhit, hiz, *florhit, loz);
532         WaterAdjust(*florhit, loz);
533         return;
534         }
535 
536     getzrange(x, y, z, sectnum, hiz,  ceilhit, loz,  florhit, clipdist, clipmask);
537     SkipFAFcheck = SectorZadjust(*ceilhit, hiz, *florhit, loz);
538     WaterAdjust(*florhit, loz);
539 
540     if (SkipFAFcheck)
541         return;
542 
543     if (FAF_ConnectCeiling(sectnum))
544         {
545         short uppersect = sectnum;
546         int newz = *hiz - Z(2);
547 
548         switch (TEST(*ceilhit, HIT_MASK))
549             {
550             case HIT_SPRITE:
551                 return;
552             }
553 
554         updatesectorz(x, y, newz, &uppersect);
555         if (uppersect < 0)
556             _ErrMsg(ERR_STD_ARG, "Did not find a sector at %d, %d, %d", x, y, newz);
557         getzrange(x, y, newz, uppersect, hiz,  ceilhit, &foo1,  &foo2, clipdist, clipmask);
558         SectorZadjust(*ceilhit, hiz, -1, NULL);
559         }
560     else
561     if (FAF_ConnectFloor(sectnum) && !TEST(sector[sectnum].floorstat, FLOOR_STAT_FAF_BLOCK_HITSCAN))
562     //if (FAF_ConnectFloor(sectnum))
563         {
564         short lowersect = sectnum;
565         int newz = *loz + Z(2);
566 
567         switch (TEST(*florhit, HIT_MASK))
568             {
569             case HIT_SECTOR:
570                 {
571                 short hitsector = NORM_SECTOR(*florhit);
572                 break;
573                 }
574             case HIT_SPRITE:
575                 return;
576             }
577 
578         updatesectorz(x, y, newz, &lowersect);
579         if (lowersect < 0)
580             _ErrMsg(ERR_STD_ARG, "Did not find a sector at %d, %d, %d", x, y, newz);
581         getzrange(x, y, newz, lowersect, &foo1,  &foo2, loz,  florhit, clipdist, clipmask);
582         SectorZadjust(-1, NULL, *florhit, loz);
583         WaterAdjust(*florhit, loz);
584         }
585     }
586 
FAFgetzrangepoint(LONG x,LONG y,LONG z,SHORT sectnum,LONGp hiz,LONGp ceilhit,LONGp loz,LONGp florhit)587 VOID FAFgetzrangepoint(LONG x, LONG y, LONG z, SHORT sectnum,
588     LONGp hiz, LONGp ceilhit,
589     LONGp loz, LONGp florhit)
590     {
591     int foo1;
592     int foo2;
593     BOOL SkipFAFcheck;
594 
595     // IMPORTANT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
596     // This will return invalid FAF ceiling and floor heights inside of analyzesprite
597     // because the ceiling and floors get moved out of the way for drawing.
598 
599     // early out to regular routine
600     if (!FAF_ConnectArea(sectnum))
601         {
602         getzrangepoint(x, y, z, sectnum, hiz,  ceilhit, loz,  florhit);
603         SectorZadjust(*ceilhit, hiz, *florhit, loz);
604         WaterAdjust(*florhit, loz);
605         return;
606         }
607 
608     getzrangepoint(x, y, z, sectnum, hiz,  ceilhit, loz,  florhit);
609     SkipFAFcheck = SectorZadjust(*ceilhit, hiz, *florhit, loz);
610     WaterAdjust(*florhit, loz);
611 
612     if (SkipFAFcheck)
613         return;
614 
615     if (FAF_ConnectCeiling(sectnum))
616         {
617         short uppersect = sectnum;
618         int newz = *hiz - Z(2);
619         switch (TEST(*ceilhit, HIT_MASK))
620             {
621             case HIT_SPRITE:
622                 return;
623             }
624         updatesectorz(x, y, newz, &uppersect);
625         if (uppersect < 0)
626             _ErrMsg(ERR_STD_ARG, "Did not find a sector at %d, %d, %d, sectnum %d", x, y, newz, sectnum);
627         getzrangepoint(x, y, newz, uppersect, hiz,  ceilhit, &foo1,  &foo2);
628         SectorZadjust(*ceilhit, hiz, -1, NULL);
629         }
630     else
631     if (FAF_ConnectFloor(sectnum) && !TEST(sector[sectnum].floorstat, FLOOR_STAT_FAF_BLOCK_HITSCAN))
632     //if (FAF_ConnectFloor(sectnum))
633         {
634         short lowersect = sectnum;
635         int newz = *loz + Z(2);
636         switch (TEST(*florhit, HIT_MASK))
637             {
638             case HIT_SPRITE:
639                 return;
640             }
641         updatesectorz(x, y, newz, &lowersect);
642         if (lowersect < 0)
643             _ErrMsg(ERR_STD_ARG, "Did not find a sector at %d, %d, %d, sectnum %d", x, y, newz, sectnum);
644         getzrangepoint(x, y, newz, lowersect, &foo1,  &foo2, loz,  florhit);
645         SectorZadjust(-1, NULL, *florhit, loz);
646         WaterAdjust(*florhit, loz);
647         }
648     }
649 
650 #if 0
651 BOOL
652 FAF_ConnectCeiling(short sectnum)
653     {
654     return(sector[sectnum].ceilingpicnum == FAF_MIRROR_PIC);
655     }
656 
657 BOOL
658 FAF_ConnectFloor(short sectnum)
659     {
660     return(sector[sectnum].floorpicnum == FAF_MIRROR_PIC);
661     }
662 #endif
663 
664 
665 // doesn't work for blank pics
666 BOOL
PicInView(short tile_num,BOOL reset)667 PicInView(short tile_num, BOOL reset)
668     {
669     if (TEST(gotpic[tile_num >> 3], 1 << (tile_num & 7)))
670         {
671         if (reset)
672             RESET(gotpic[tile_num >> 3], 1 << (tile_num & 7));
673 
674         return (TRUE);
675         }
676 
677     return (FALSE);
678     }
679 
680 VOID
SetupMirrorTiles(VOID)681 SetupMirrorTiles(VOID)
682     {
683     short i, nexti;
684     short j, nextj;
685     SPRITEp sp;
686     BOOL found;
687 
688     TRAVERSE_SPRITE_STAT(headspritestat[STAT_FAF], i, nexti)
689         {
690         sp = &sprite[i];
691 
692         if (sector[sp->sectnum].ceilingpicnum == FAF_PLACE_MIRROR_PIC)
693             {
694             sector[sp->sectnum].ceilingpicnum = FAF_MIRROR_PIC;
695             SET(sector[sp->sectnum].ceilingstat, CEILING_STAT_PLAX);
696             }
697 
698         if (sector[sp->sectnum].floorpicnum == FAF_PLACE_MIRROR_PIC)
699             {
700             sector[sp->sectnum].floorpicnum = FAF_MIRROR_PIC;
701             SET(sector[sp->sectnum].floorstat, FLOOR_STAT_PLAX);
702             }
703 
704         if (sector[sp->sectnum].ceilingpicnum == FAF_PLACE_MIRROR_PIC+1)
705             sector[sp->sectnum].ceilingpicnum = FAF_MIRROR_PIC+1;
706 
707         if (sector[sp->sectnum].floorpicnum == FAF_PLACE_MIRROR_PIC+1)
708             sector[sp->sectnum].floorpicnum = FAF_MIRROR_PIC+1;
709         }
710     }
711 
712 
713 //This function is like updatesector, but it takes a z-coordinate in addition
714 //   to help it get the right sector when there's overlapping.  (I may be
715 //   adding this function to the engine or making the standard updatesector
716 //   use z's.  Until then, use this.  )
717 
718 #if 0
719 void
720 updatesectorz(int x, int y, int z, short *sectnum)
721     {
722     walltype *wal;
723     int i, j, cz, fz;
724 
725     ASSERT(*sectnum >=0 && *sectnum <= MAXSECTORS);
726 
727     getzsofslope(*sectnum, x, y, &cz, &fz);
728     // go ahead and check the current sector
729     if ((z >= cz) && (z <= fz))
730         if (inside(x, y, *sectnum) != 0)
731             return;
732 
733     // Test the sectors immediately around your current sector
734     if ((*sectnum >= 0) && (*sectnum < numsectors))
735         {
736         wal = &wall[sector[*sectnum].wallptr];
737         j = sector[*sectnum].wallnum;
738         do
739             {
740             i = wal->nextsector;
741             if (i >= 0)
742                 {
743                 getzsofslope(i, x, y, &cz, &fz);
744                 if ((z >= cz) && (z <= fz))
745                     {
746                     if (inside(x, y, (short) i) == 1)
747                         {
748                         *sectnum = i;
749                         return;
750                         }
751                     }
752                 }
753             wal++;
754             j--;
755             }
756         while (j != 0);
757         }
758 
759     // didn't find it yet so test ALL sectors
760     for (i = numsectors - 1; i >= 0; i--)
761         {
762         getzsofslope(i, x, y, &cz, &fz);
763         if ((z >= cz) && (z <= fz))
764             {
765             if (inside(x, y, (short) i) == 1)
766                 {
767                 *sectnum = i;
768                 return;
769                 }
770             }
771         }
772 
773     *sectnum = -1;
774     }
775 #endif
776 
777 short GlobStackSect[2];
778 
779 void
GetUpperLowerSector(short match,int x,int y,short * upper,short * lower)780 GetUpperLowerSector(short match, int x, int y, short *upper, short *lower)
781     {
782     int i, j;
783     short sectorlist[16];
784     int sln = 0;
785     short SpriteNum, Next;
786     SPRITEp sp;
787 
788     // keep a list of the last stacked sectors the view was in and
789     // check those fisrt
790     sln = 0;
791     for (i = 0; i < (int)SIZ(GlobStackSect); i++)
792         {
793         // will not hurt if GlobStackSect is invalid - inside checks for this
794         if (inside(x, y, GlobStackSect[i]) == 1)
795             {
796             BOOL found = FALSE;
797 
798             TRAVERSE_SPRITE_SECT(headspritesect[GlobStackSect[i]], SpriteNum, Next)
799                 {
800                 sp = &sprite[SpriteNum];
801 
802                 if (sp->statnum == STAT_FAF &&
803                     (sp->hitag >= VIEW_LEVEL1 && sp->hitag <= VIEW_LEVEL6)
804                     && sp->lotag == match)
805                     {
806                     found = TRUE;
807                     }
808                 }
809 
810             if (!found)
811                 continue;
812 
813             sectorlist[sln] = GlobStackSect[i];
814             sln++;
815             }
816         }
817 
818     // didn't find it yet so test ALL sectors
819     if (sln < 2)
820         {
821         sln = 0;
822         for (i = numsectors - 1; i >= 0; i--)
823             {
824             if (inside(x, y, (short) i) == 1)
825                 {
826                 BOOL found = FALSE;
827 
828                 TRAVERSE_SPRITE_SECT(headspritesect[i], SpriteNum, Next)
829                     {
830                     sp = &sprite[SpriteNum];
831 
832                     if (sp->statnum == STAT_FAF &&
833                         (sp->hitag >= VIEW_LEVEL1 && sp->hitag <= VIEW_LEVEL6)
834                         && sp->lotag == match)
835                         {
836                         found = TRUE;
837                         }
838                     }
839 
840                 if (!found)
841                     continue;
842 
843                 sectorlist[sln] = i;
844                 if (sln < (int)SIZ(GlobStackSect))
845                     GlobStackSect[sln] = i;
846                 sln++;
847                 }
848             }
849         }
850 
851     // might not find ANYTHING if not tagged right
852     if (sln == 0)
853         {
854         *upper = -1;
855         *lower = -1;
856         return;
857         }
858     else
859     // inside will somtimes find that you are in two different sectors if the x,y
860     // is exactly on a sector line.
861     if (sln > 2)
862         {
863         //DSPRINTF(ds, "TOO MANY SECTORS FOUND: x=%d, y=%d, match=%d, num sectors %d, %d, %d, %d, %d, %d", x, y, match, sln, sectorlist[0], sectorlist[1], sectorlist[2], sectorlist[3], sectorlist[4]);
864         MONO_PRINT(ds);
865         // try again moving the x,y pos around until you only get two sectors
866         GetUpperLowerSector(match, x - 1, y, upper, lower);
867         }
868 
869     if (sln == 2)
870         {
871         if (sector[sectorlist[0]].floorz < sector[sectorlist[1]].floorz)
872             {
873             // swap
874             // make sectorlist[0] the LOW sector
875             short hold;
876 
877             hold = sectorlist[0];
878             sectorlist[0] = sectorlist[1];
879             sectorlist[1] = hold;
880             }
881 
882         *lower = sectorlist[0];
883         *upper = sectorlist[1];
884         }
885     }
886 
887 BOOL
FindCeilingView(short match,LONGp x,LONGp y,LONG z,SHORTp sectnum)888 FindCeilingView(short match, LONGp x, LONGp y, LONG z, SHORTp sectnum)
889     {
890     int xoff = 0;
891     int yoff = 0;
892     short i, nexti;
893     SPRITEp sp = NULL;
894     short top_sprite = -1;
895     int pix_diff;
896     int newz;
897 
898     save.zcount = 0;
899 
900     // Search Stat List For closest ceiling view sprite
901     // Get the match, xoff, yoff from this point
902     TRAVERSE_SPRITE_STAT(headspritestat[STAT_FAF], i, nexti)
903         {
904         sp = &sprite[i];
905 
906         if (sp->hitag == VIEW_THRU_CEILING && sp->lotag == match)
907             {
908             xoff = *x - sp->x;
909             yoff = *y - sp->y;
910             break;
911             }
912         }
913 
914     TRAVERSE_SPRITE_STAT(headspritestat[STAT_FAF], i, nexti)
915         {
916         sp = &sprite[i];
917 
918         if (sp->lotag == match)
919             {
920             // determine x,y position
921             if (sp->hitag == VIEW_THRU_FLOOR)
922                 {
923                 short upper, lower;
924 
925                 *x = sp->x + xoff;
926                 *y = sp->y + yoff;
927 
928                 // get new sector
929                 GetUpperLowerSector(match, *x, *y, &upper, &lower);
930                 *sectnum = upper;
931                 break;
932                 }
933             }
934         }
935 
936     if (*sectnum < 0)
937         return(FALSE);
938 
939     ASSERT(sp);
940     ASSERT(sp->hitag == VIEW_THRU_FLOOR);
941 
942     pix_diff = labs(z - sector[sp->sectnum].floorz) >> 8;
943     newz = sector[sp->sectnum].floorz + ((pix_diff / 128) + 1) * Z(128);
944 
945     TRAVERSE_SPRITE_STAT(headspritestat[STAT_FAF], i, nexti)
946         {
947         sp = &sprite[i];
948 
949         if (sp->lotag == match)
950             {
951             // move lower levels ceilings up for the correct view
952             if (sp->hitag == VIEW_LEVEL2)
953                 {
954                 // save it off
955                 save.sectnum[save.zcount] = sp->sectnum;
956                 save.zval[save.zcount] = sector[sp->sectnum].floorz;
957                 save.pic[save.zcount] = sector[sp->sectnum].floorpicnum;
958                 save.slope[save.zcount] = sector[sp->sectnum].floorheinum;
959 
960                 sector[sp->sectnum].floorz = newz;
961                 // don't change FAF_MIRROR_PIC - ConnectArea
962                 if (sector[sp->sectnum].floorpicnum != FAF_MIRROR_PIC)
963                     sector[sp->sectnum].floorpicnum = FAF_MIRROR_PIC+1;
964                 sector[sp->sectnum].floorheinum = 0;
965 
966                 save.zcount++;
967                 PRODUCTION_ASSERT(save.zcount < ZMAX);
968                 }
969             }
970         }
971 
972     return (TRUE);
973     }
974 
975 BOOL
FindFloorView(short match,LONGp x,LONGp y,LONG z,SHORTp sectnum)976 FindFloorView(short match, LONGp x, LONGp y, LONG z, SHORTp sectnum)
977     {
978     int xoff = 0;
979     int yoff = 0;
980     short i, nexti;
981     SPRITEp sp = NULL;
982     int newz;
983     int pix_diff;
984 
985     save.zcount = 0;
986 
987     // Search Stat List For closest ceiling view sprite
988     // Get the match, xoff, yoff from this point
989     TRAVERSE_SPRITE_STAT(headspritestat[STAT_FAF], i, nexti)
990         {
991         sp = &sprite[i];
992 
993         if (sp->hitag == VIEW_THRU_FLOOR && sp->lotag == match)
994             {
995             xoff = *x - sp->x;
996             yoff = *y - sp->y;
997             break;
998             }
999         }
1000 
1001 
1002     TRAVERSE_SPRITE_STAT(headspritestat[STAT_FAF], i, nexti)
1003         {
1004         sp = &sprite[i];
1005 
1006         if (sp->lotag == match)
1007             {
1008             // determine x,y position
1009             if (sp->hitag == VIEW_THRU_CEILING)
1010                 {
1011                 short upper, lower;
1012 
1013                 *x = sp->x + xoff;
1014                 *y = sp->y + yoff;
1015 
1016                 // get new sector
1017                 GetUpperLowerSector(match, *x, *y, &upper, &lower);
1018                 *sectnum = lower;
1019                 break;
1020                 }
1021             }
1022         }
1023 
1024     if (*sectnum < 0)
1025         return(FALSE);
1026 
1027     ASSERT(sp);
1028     ASSERT(sp->hitag == VIEW_THRU_CEILING);
1029 
1030     // move ceiling multiple of 128 so that the wall tile will line up
1031     pix_diff = labs(z - sector[sp->sectnum].ceilingz) >> 8;
1032     newz = sector[sp->sectnum].ceilingz - ((pix_diff / 128) + 1) * Z(128);
1033 
1034     TRAVERSE_SPRITE_STAT(headspritestat[STAT_FAF], i, nexti)
1035         {
1036         sp = &sprite[i];
1037 
1038         if (sp->lotag == match)
1039             {
1040             // move upper levels floors down for the correct view
1041             if (sp->hitag == VIEW_LEVEL1)
1042                 {
1043                 // save it off
1044                 save.sectnum[save.zcount] = sp->sectnum;
1045                 save.zval[save.zcount] = sector[sp->sectnum].ceilingz;
1046                 save.pic[save.zcount] = sector[sp->sectnum].ceilingpicnum;
1047                 save.slope[save.zcount] = sector[sp->sectnum].ceilingheinum;
1048 
1049                 sector[sp->sectnum].ceilingz = newz;
1050 
1051                 // don't change FAF_MIRROR_PIC - ConnectArea
1052                 if (sector[sp->sectnum].ceilingpicnum != FAF_MIRROR_PIC)
1053                     sector[sp->sectnum].ceilingpicnum = FAF_MIRROR_PIC+1;
1054                 sector[sp->sectnum].ceilingheinum = 0;
1055 
1056                 save.zcount++;
1057                 PRODUCTION_ASSERT(save.zcount < ZMAX);
1058                 }
1059             }
1060         }
1061 
1062     return (TRUE);
1063     }
1064 
1065 short
ViewSectorInScene(short cursectnum,short UNUSED (type),short level)1066 ViewSectorInScene(short cursectnum, short UNUSED(type), short level)
1067     {
1068     int i, nexti;
1069     int j, nextj;
1070     SPRITEp sp;
1071     SPRITEp sp2;
1072     int cz, fz;
1073     short match;
1074 
1075     TRAVERSE_SPRITE_STAT(headspritestat[STAT_FAF], i, nexti)
1076         {
1077         sp = &sprite[i];
1078 
1079         if (sp->hitag == level)
1080             {
1081             if (cursectnum == sp->sectnum)
1082                 {
1083                 // ignore case if sprite is pointing up
1084                 if (sp->ang == 1536)
1085                     continue;
1086 
1087                 // only gets to here is sprite is pointing down
1088 
1089                 // found a potential match
1090                 match = sp->lotag;
1091 
1092                 if (!PicInView(FAF_MIRROR_PIC, TRUE))
1093                     return (-1);
1094 
1095                 return(match);
1096                 }
1097             }
1098         }
1099 
1100     return (-1);
1101     }
1102 
1103 VOID
DrawOverlapRoom(int tx,int ty,int tz,short tang,int thoriz,short tsectnum)1104 DrawOverlapRoom(int tx, int ty, int tz, short tang, int thoriz, short tsectnum)
1105     {
1106     short i;
1107     short match;
1108 
1109     save.zcount = 0;
1110 
1111     match = ViewSectorInScene(tsectnum, VIEW_THRU_CEILING, VIEW_LEVEL1);
1112     if (match != -1)
1113         {
1114         FindCeilingView(match, &tx, &ty, tz, &tsectnum);
1115 
1116         if (tsectnum < 0)
1117             return;
1118 
1119         drawrooms(tx, ty, tz, tang, thoriz, tsectnum);
1120         //FAF_DrawRooms(tx, ty, tz, tang, thoriz, tsectnum);
1121 
1122         // reset Z's
1123         for (i = 0; i < save.zcount; i++)
1124             {
1125             sector[save.sectnum[i]].floorz = save.zval[i];
1126             sector[save.sectnum[i]].floorpicnum = save.pic[i];
1127             sector[save.sectnum[i]].floorheinum = save.slope[i];
1128             }
1129 
1130         analyzesprites(tx, ty, tz, FALSE);
1131         post_analyzesprites();
1132         drawmasks();
1133 
1134         }
1135     else
1136         {
1137         match = ViewSectorInScene(tsectnum, VIEW_THRU_FLOOR, VIEW_LEVEL2);
1138         if (match != -1)
1139             {
1140             FindFloorView(match, &tx, &ty, tz, &tsectnum);
1141 
1142             if (tsectnum < 0)
1143                 return;
1144 
1145             drawrooms(tx, ty, tz, tang, thoriz, tsectnum);
1146             //FAF_DrawRooms(tx, ty, tz, tang, thoriz, tsectnum);
1147 
1148             // reset Z's
1149             for (i = 0; i < save.zcount; i++)
1150                 {
1151                 sector[save.sectnum[i]].ceilingz = save.zval[i];
1152                 sector[save.sectnum[i]].ceilingpicnum = save.pic[i];
1153                 sector[save.sectnum[i]].ceilingheinum = save.slope[i];
1154                 }
1155 
1156             analyzesprites(tx, ty, tz, FALSE);
1157             post_analyzesprites();
1158             drawmasks();
1159 
1160             }
1161         }
1162     }
1163 
1164