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