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