123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396 |
- //**************************************************************************
- //**
- //** p_sight.c : Heretic 2 : Raven Software, Corp.
- //**
- //** $RCSfile: p_sight.c,v $
- //** $Revision: 1.1 $
- //** $Date: 95/05/11 00:22:50 $
- //** $Author: bgokey $
- //**
- //**************************************************************************
- #include "h2def.h"
- #include "p_local.h"
- /*
- ==============================================================================
- P_CheckSight
- This uses specialized forms of the maputils routines for optimized performance
- ==============================================================================
- */
- fixed_t sightzstart; // eye z of looker
- fixed_t topslope, bottomslope; // slopes to top and bottom of target
- int sightcounts[3];
- /*
- ==============
- =
- = PTR_SightTraverse
- =
- ==============
- */
- boolean PTR_SightTraverse (intercept_t *in)
- {
- line_t *li;
- fixed_t slope;
- li = in->d.line;
- //
- // crosses a two sided line
- //
- P_LineOpening (li);
- if (openbottom >= opentop) // quick test for totally closed doors
- return false; // stop
- if (li->frontsector->floorheight != li->backsector->floorheight)
- {
- slope = FixedDiv (openbottom - sightzstart , in->frac);
- if (slope > bottomslope)
- bottomslope = slope;
- }
- if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
- {
- slope = FixedDiv (opentop - sightzstart , in->frac);
- if (slope < topslope)
- topslope = slope;
- }
- if (topslope <= bottomslope)
- return false; // stop
- return true; // keep going
- }
- /*
- ==================
- =
- = P_SightBlockLinesIterator
- =
- ===================
- */
- boolean P_SightBlockLinesIterator (int x, int y )
- {
- int offset;
- short *list;
- line_t *ld;
- int s1, s2;
- divline_t dl;
- polyblock_t *polyLink;
- seg_t **segList;
- int i;
- extern polyblock_t **PolyBlockMap;
- offset = y*bmapwidth+x;
- polyLink = PolyBlockMap[offset];
- while(polyLink)
- {
- if(polyLink->polyobj)
- { // only check non-empty links
- if(polyLink->polyobj->validcount != validcount)
- {
- segList = polyLink->polyobj->segs;
- for(i = 0; i < polyLink->polyobj->numsegs; i++, segList++)
- {
- ld = (*segList)->linedef;
- if(ld->validcount == validcount)
- {
- continue;
- }
- ld->validcount = validcount;
- s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace);
- s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace);
- if (s1 == s2)
- continue; // line isn't crossed
- P_MakeDivline (ld, &dl);
- s1 = P_PointOnDivlineSide (trace.x, trace.y, &dl);
- s2 = P_PointOnDivlineSide (trace.x+trace.dx, trace.y+trace.dy, &dl);
- if (s1 == s2)
- continue; // line isn't crossed
- // try to early out the check
- if (!ld->backsector)
- return false; // stop checking
- // store the line for later intersection testing
- intercept_p->d.line = ld;
- intercept_p++;
- }
- polyLink->polyobj->validcount = validcount;
- }
- }
- polyLink = polyLink->next;
- }
- offset = *(blockmap+offset);
- for ( list = blockmaplump+offset ; *list != -1 ; list++)
- {
- ld = &lines[*list];
- if (ld->validcount == validcount)
- continue; // line has already been checked
- ld->validcount = validcount;
- s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace);
- s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace);
- if (s1 == s2)
- continue; // line isn't crossed
- P_MakeDivline (ld, &dl);
- s1 = P_PointOnDivlineSide (trace.x, trace.y, &dl);
- s2 = P_PointOnDivlineSide (trace.x+trace.dx, trace.y+trace.dy, &dl);
- if (s1 == s2)
- continue; // line isn't crossed
- // try to early out the check
- if (!ld->backsector)
- return false; // stop checking
- // store the line for later intersection testing
- intercept_p->d.line = ld;
- intercept_p++;
- }
- return true; // everything was checked
- }
- /*
- ====================
- =
- = P_SightTraverseIntercepts
- =
- = Returns true if the traverser function returns true for all lines
- ====================
- */
- boolean P_SightTraverseIntercepts ( void )
- {
- int count;
- fixed_t dist;
- intercept_t *scan, *in;
- divline_t dl;
- count = intercept_p - intercepts;
- //
- // calculate intercept distance
- //
- for (scan = intercepts ; scan<intercept_p ; scan++)
- {
- P_MakeDivline (scan->d.line, &dl);
- scan->frac = P_InterceptVector (&trace, &dl);
- }
- //
- // go through in order
- //
- in = 0; // shut up compiler warning
- while (count--)
- {
- dist = MAXINT;
- for (scan = intercepts ; scan<intercept_p ; scan++)
- if (scan->frac < dist)
- {
- dist = scan->frac;
- in = scan;
- }
- if ( !PTR_SightTraverse (in) )
- return false; // don't bother going farther
- in->frac = MAXINT;
- }
- return true; // everything was traversed
- }
- /*
- ==================
- =
- = P_SightPathTraverse
- =
- = Traces a line from x1,y1 to x2,y2, calling the traverser function for each
- = Returns true if the traverser function returns true for all lines
- ==================
- */
- boolean P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
- {
- fixed_t xt1,yt1,xt2,yt2;
- fixed_t xstep,ystep;
- fixed_t partial;
- fixed_t xintercept, yintercept;
- int mapx, mapy, mapxstep, mapystep;
- int count;
- validcount++;
- intercept_p = intercepts;
- if ( ((x1-bmaporgx)&(MAPBLOCKSIZE-1)) == 0)
- x1 += FRACUNIT; // don't side exactly on a line
- if ( ((y1-bmaporgy)&(MAPBLOCKSIZE-1)) == 0)
- y1 += FRACUNIT; // don't side exactly on a line
- trace.x = x1;
- trace.y = y1;
- trace.dx = x2 - x1;
- trace.dy = y2 - y1;
- x1 -= bmaporgx;
- y1 -= bmaporgy;
- xt1 = x1>>MAPBLOCKSHIFT;
- yt1 = y1>>MAPBLOCKSHIFT;
- x2 -= bmaporgx;
- y2 -= bmaporgy;
- xt2 = x2>>MAPBLOCKSHIFT;
- yt2 = y2>>MAPBLOCKSHIFT;
- // points should never be out of bounds, but check once instead of
- // each block
- if (xt1<0 || yt1<0 || xt1>=bmapwidth || yt1>=bmapheight
- || xt2<0 || yt2<0 || xt2>=bmapwidth || yt2>=bmapheight)
- return false;
- if (xt2 > xt1)
- {
- mapxstep = 1;
- partial = FRACUNIT - ((x1>>MAPBTOFRAC)&(FRACUNIT-1));
- ystep = FixedDiv (y2-y1,abs(x2-x1));
- }
- else if (xt2 < xt1)
- {
- mapxstep = -1;
- partial = (x1>>MAPBTOFRAC)&(FRACUNIT-1);
- ystep = FixedDiv (y2-y1,abs(x2-x1));
- }
- else
- {
- mapxstep = 0;
- partial = FRACUNIT;
- ystep = 256*FRACUNIT;
- }
- yintercept = (y1>>MAPBTOFRAC) + FixedMul (partial, ystep);
- if (yt2 > yt1)
- {
- mapystep = 1;
- partial = FRACUNIT - ((y1>>MAPBTOFRAC)&(FRACUNIT-1));
- xstep = FixedDiv (x2-x1,abs(y2-y1));
- }
- else if (yt2 < yt1)
- {
- mapystep = -1;
- partial = (y1>>MAPBTOFRAC)&(FRACUNIT-1);
- xstep = FixedDiv (x2-x1,abs(y2-y1));
- }
- else
- {
- mapystep = 0;
- partial = FRACUNIT;
- xstep = 256*FRACUNIT;
- }
- xintercept = (x1>>MAPBTOFRAC) + FixedMul (partial, xstep);
- //
- // step through map blocks
- // Count is present to prevent a round off error from skipping the break
- mapx = xt1;
- mapy = yt1;
- for (count = 0 ; count < 64 ; count++)
- {
- if (!P_SightBlockLinesIterator (mapx, mapy))
- {
- sightcounts[1]++;
- return false; // early out
- }
- if (mapx == xt2 && mapy == yt2)
- break;
- if ( (yintercept >> FRACBITS) == mapy)
- {
- yintercept += ystep;
- mapx += mapxstep;
- }
- else if ( (xintercept >> FRACBITS) == mapx)
- {
- xintercept += xstep;
- mapy += mapystep;
- }
- }
- //
- // couldn't early out, so go through the sorted list
- //
- sightcounts[2]++;
- return P_SightTraverseIntercepts ( );
- }
- /*
- =====================
- =
- = P_CheckSight
- =
- = Returns true if a straight line between t1 and t2 is unobstructed
- = look from eyes of t1 to any part of t2
- =
- =====================
- */
- boolean P_CheckSight (mobj_t *t1, mobj_t *t2)
- {
- int s1, s2;
- int pnum, bytenum, bitnum;
- //
- // check for trivial rejection
- //
- s1 = (t1->subsector->sector - sectors);
- s2 = (t2->subsector->sector - sectors);
- pnum = s1*numsectors + s2;
- bytenum = pnum>>3;
- bitnum = 1 << (pnum&7);
- if (rejectmatrix[bytenum]&bitnum)
- {
- sightcounts[0]++;
- return false; // can't possibly be connected
- }
- //
- // check precisely
- //
- sightzstart = t1->z + t1->height - (t1->height>>2);
- topslope = (t2->z+t2->height) - sightzstart;
- bottomslope = (t2->z) - sightzstart;
- return P_SightPathTraverse ( t1->x, t1->y, t2->x, t2->y );
- }
|