1056 lines
21 KiB
C
1056 lines
21 KiB
C
|
|
//**************************************************************************
|
|
//**
|
|
//** p_maputl.c : Heretic 2 : Raven Software, Corp.
|
|
//**
|
|
//** $RCSfile: p_maputl.c,v $
|
|
//** $Revision: 1.11 $
|
|
//** $Date: 95/10/04 02:39:28 $
|
|
//** $Author: paul $
|
|
//**
|
|
//**************************************************************************
|
|
|
|
#include "h2def.h"
|
|
#include "p_local.h"
|
|
|
|
static mobj_t *RoughBlockCheck(mobj_t *mo, int index);
|
|
|
|
/*
|
|
===================
|
|
=
|
|
= P_AproxDistance
|
|
=
|
|
= Gives an estimation of distance (not exact)
|
|
=
|
|
===================
|
|
*/
|
|
|
|
fixed_t P_AproxDistance (fixed_t dx, fixed_t dy)
|
|
{
|
|
dx = abs(dx);
|
|
dy = abs(dy);
|
|
if (dx < dy)
|
|
return dx+dy-(dx>>1);
|
|
return dx+dy-(dy>>1);
|
|
}
|
|
|
|
|
|
/*
|
|
==================
|
|
=
|
|
= P_PointOnLineSide
|
|
=
|
|
= Returns 0 or 1
|
|
==================
|
|
*/
|
|
|
|
int P_PointOnLineSide (fixed_t x, fixed_t y, line_t *line)
|
|
{
|
|
fixed_t dx,dy;
|
|
fixed_t left, right;
|
|
|
|
if (!line->dx)
|
|
{
|
|
if (x <= line->v1->x)
|
|
return line->dy > 0;
|
|
return line->dy < 0;
|
|
}
|
|
if (!line->dy)
|
|
{
|
|
if (y <= line->v1->y)
|
|
return line->dx < 0;
|
|
return line->dx > 0;
|
|
}
|
|
|
|
dx = (x - line->v1->x);
|
|
dy = (y - line->v1->y);
|
|
|
|
left = FixedMul ( line->dy>>FRACBITS , dx );
|
|
right = FixedMul ( dy , line->dx>>FRACBITS );
|
|
|
|
if (right < left)
|
|
return 0; // front side
|
|
return 1; // back side
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
=
|
|
= P_BoxOnLineSide
|
|
=
|
|
= Considers the line to be infinite
|
|
= Returns side 0 or 1, -1 if box crosses the line
|
|
=================
|
|
*/
|
|
|
|
int P_BoxOnLineSide (fixed_t *tmbox, line_t *ld)
|
|
{
|
|
int p1, p2;
|
|
|
|
switch (ld->slopetype)
|
|
{
|
|
case ST_HORIZONTAL:
|
|
p1 = tmbox[BOXTOP] > ld->v1->y;
|
|
p2 = tmbox[BOXBOTTOM] > ld->v1->y;
|
|
if (ld->dx < 0)
|
|
{
|
|
p1 ^= 1;
|
|
p2 ^= 1;
|
|
}
|
|
break;
|
|
case ST_VERTICAL:
|
|
p1 = tmbox[BOXRIGHT] < ld->v1->x;
|
|
p2 = tmbox[BOXLEFT] < ld->v1->x;
|
|
if (ld->dy < 0)
|
|
{
|
|
p1 ^= 1;
|
|
p2 ^= 1;
|
|
}
|
|
break;
|
|
case ST_POSITIVE:
|
|
p1 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXTOP], ld);
|
|
p2 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXBOTTOM], ld);
|
|
break;
|
|
case ST_NEGATIVE:
|
|
p1 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXTOP], ld);
|
|
p2 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXBOTTOM], ld);
|
|
break;
|
|
}
|
|
|
|
if (p1 == p2)
|
|
return p1;
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
=
|
|
= P_PointOnDivlineSide
|
|
=
|
|
= Returns 0 or 1
|
|
==================
|
|
*/
|
|
|
|
int P_PointOnDivlineSide (fixed_t x, fixed_t y, divline_t *line)
|
|
{
|
|
fixed_t dx,dy;
|
|
fixed_t left, right;
|
|
|
|
if (!line->dx)
|
|
{
|
|
if (x <= line->x)
|
|
return line->dy > 0;
|
|
return line->dy < 0;
|
|
}
|
|
if (!line->dy)
|
|
{
|
|
if (y <= line->y)
|
|
return line->dx < 0;
|
|
return line->dx > 0;
|
|
}
|
|
|
|
dx = (x - line->x);
|
|
dy = (y - line->y);
|
|
|
|
// try to quickly decide by looking at sign bits
|
|
if ( (line->dy ^ line->dx ^ dx ^ dy)&0x80000000 )
|
|
{
|
|
if ( (line->dy ^ dx) & 0x80000000 )
|
|
return 1; // (left is negative)
|
|
return 0;
|
|
}
|
|
|
|
left = FixedMul ( line->dy>>8, dx>>8 );
|
|
right = FixedMul ( dy>>8 , line->dx>>8 );
|
|
|
|
if (right < left)
|
|
return 0; // front side
|
|
return 1; // back side
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
==============
|
|
=
|
|
= P_MakeDivline
|
|
=
|
|
==============
|
|
*/
|
|
|
|
void P_MakeDivline (line_t *li, divline_t *dl)
|
|
{
|
|
dl->x = li->v1->x;
|
|
dl->y = li->v1->y;
|
|
dl->dx = li->dx;
|
|
dl->dy = li->dy;
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
=
|
|
= P_InterceptVector
|
|
=
|
|
= Returns the fractional intercept point along the first divline
|
|
=
|
|
= This is only called by the addthings and addlines traversers
|
|
===============
|
|
*/
|
|
|
|
fixed_t P_InterceptVector (divline_t *v2, divline_t *v1)
|
|
{
|
|
#if 1
|
|
fixed_t frac, num, den;
|
|
|
|
den = FixedMul (v1->dy>>8,v2->dx) - FixedMul(v1->dx>>8,v2->dy);
|
|
if (den == 0)
|
|
return 0;
|
|
// I_Error ("P_InterceptVector: parallel");
|
|
num = FixedMul ( (v1->x - v2->x)>>8 ,v1->dy) +
|
|
FixedMul ( (v2->y - v1->y)>>8 , v1->dx);
|
|
frac = FixedDiv (num , den);
|
|
|
|
return frac;
|
|
#else
|
|
float frac, num, den, v1x,v1y,v1dx,v1dy,v2x,v2y,v2dx,v2dy;
|
|
|
|
v1x = (float)v1->x/FRACUNIT;
|
|
v1y = (float)v1->y/FRACUNIT;
|
|
v1dx = (float)v1->dx/FRACUNIT;
|
|
v1dy = (float)v1->dy/FRACUNIT;
|
|
v2x = (float)v2->x/FRACUNIT;
|
|
v2y = (float)v2->y/FRACUNIT;
|
|
v2dx = (float)v2->dx/FRACUNIT;
|
|
v2dy = (float)v2->dy/FRACUNIT;
|
|
|
|
den = v1dy*v2dx - v1dx*v2dy;
|
|
if (den == 0)
|
|
return 0; // parallel
|
|
num = (v1x - v2x)*v1dy + (v2y - v1y)*v1dx;
|
|
frac = num / den;
|
|
|
|
return frac*FRACUNIT;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
==================
|
|
=
|
|
= P_LineOpening
|
|
=
|
|
= Sets opentop and openbottom to the window through a two sided line
|
|
= OPTIMIZE: keep this precalculated
|
|
==================
|
|
*/
|
|
|
|
fixed_t opentop, openbottom, openrange;
|
|
fixed_t lowfloor;
|
|
|
|
void P_LineOpening (line_t *linedef)
|
|
{
|
|
sector_t *front, *back;
|
|
|
|
if (linedef->sidenum[1] == -1)
|
|
{ // single sided line
|
|
openrange = 0;
|
|
return;
|
|
}
|
|
|
|
front = linedef->frontsector;
|
|
back = linedef->backsector;
|
|
|
|
if (front->ceilingheight < back->ceilingheight)
|
|
opentop = front->ceilingheight;
|
|
else
|
|
opentop = back->ceilingheight;
|
|
if (front->floorheight > back->floorheight)
|
|
{
|
|
openbottom = front->floorheight;
|
|
lowfloor = back->floorheight;
|
|
tmfloorpic = front->floorpic;
|
|
}
|
|
else
|
|
{
|
|
openbottom = back->floorheight;
|
|
lowfloor = front->floorheight;
|
|
tmfloorpic = back->floorpic;
|
|
}
|
|
|
|
openrange = opentop - openbottom;
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
THING POSITION SETTING
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
/*
|
|
===================
|
|
=
|
|
= P_UnsetThingPosition
|
|
=
|
|
= Unlinks a thing from block map and sectors
|
|
=
|
|
===================
|
|
*/
|
|
|
|
void P_UnsetThingPosition (mobj_t *thing)
|
|
{
|
|
int blockx, blocky;
|
|
|
|
if ( ! (thing->flags & MF_NOSECTOR) )
|
|
{ // inert things don't need to be in blockmap
|
|
// unlink from subsector
|
|
if (thing->snext)
|
|
thing->snext->sprev = thing->sprev;
|
|
if (thing->sprev)
|
|
thing->sprev->snext = thing->snext;
|
|
else
|
|
thing->subsector->sector->thinglist = thing->snext;
|
|
}
|
|
|
|
if ( ! (thing->flags & MF_NOBLOCKMAP) )
|
|
{ // inert things don't need to be in blockmap
|
|
// unlink from block map
|
|
if (thing->bnext)
|
|
thing->bnext->bprev = thing->bprev;
|
|
if (thing->bprev)
|
|
thing->bprev->bnext = thing->bnext;
|
|
else
|
|
{
|
|
blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT;
|
|
blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT;
|
|
if (blockx>=0 && blockx < bmapwidth
|
|
&& blocky>=0 && blocky <bmapheight)
|
|
blocklinks[blocky*bmapwidth+blockx] = thing->bnext;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===================
|
|
=
|
|
= P_SetThingPosition
|
|
=
|
|
= Links a thing into both a block and a subsector based on it's x y
|
|
= Sets thing->subsector properly
|
|
=
|
|
===================
|
|
*/
|
|
|
|
void P_SetThingPosition (mobj_t *thing)
|
|
{
|
|
subsector_t *ss;
|
|
sector_t *sec;
|
|
int blockx, blocky;
|
|
mobj_t **link;
|
|
|
|
//
|
|
// link into subsector
|
|
//
|
|
ss = R_PointInSubsector (thing->x,thing->y);
|
|
thing->subsector = ss;
|
|
if ( ! (thing->flags & MF_NOSECTOR) )
|
|
{ // invisible things don't go into the sector links
|
|
sec = ss->sector;
|
|
|
|
thing->sprev = NULL;
|
|
thing->snext = sec->thinglist;
|
|
if (sec->thinglist)
|
|
sec->thinglist->sprev = thing;
|
|
sec->thinglist = thing;
|
|
}
|
|
|
|
//
|
|
// link into blockmap
|
|
//
|
|
if ( ! (thing->flags & MF_NOBLOCKMAP) )
|
|
{ // inert things don't need to be in blockmap
|
|
blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT;
|
|
blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT;
|
|
if (blockx>=0 && blockx < bmapwidth && blocky>=0 && blocky <bmapheight)
|
|
{
|
|
link = &blocklinks[blocky*bmapwidth+blockx];
|
|
thing->bprev = NULL;
|
|
thing->bnext = *link;
|
|
if (*link)
|
|
(*link)->bprev = thing;
|
|
*link = thing;
|
|
}
|
|
else
|
|
{ // thing is off the map
|
|
thing->bnext = thing->bprev = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
BLOCK MAP ITERATORS
|
|
|
|
For each line/thing in the given mapblock, call the passed function.
|
|
If the function returns false, exit with false without checking anything else.
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
/*
|
|
==================
|
|
=
|
|
= P_BlockLinesIterator
|
|
=
|
|
= The validcount flags are used to avoid checking lines
|
|
= that are marked in multiple mapblocks, so increment validcount before
|
|
= the first call to P_BlockLinesIterator, then make one or more calls to it
|
|
===================
|
|
*/
|
|
|
|
boolean P_BlockLinesIterator (int x, int y, boolean(*func)(line_t*) )
|
|
{
|
|
int offset;
|
|
short *list;
|
|
line_t *ld;
|
|
|
|
int i;
|
|
polyblock_t *polyLink;
|
|
seg_t **tempSeg;
|
|
extern polyblock_t **PolyBlockMap;
|
|
|
|
if (x < 0 || y<0 || x>=bmapwidth || y>=bmapheight)
|
|
return true;
|
|
offset = y*bmapwidth+x;
|
|
|
|
polyLink = PolyBlockMap[offset];
|
|
while(polyLink)
|
|
{
|
|
if(polyLink->polyobj)
|
|
{
|
|
if(polyLink->polyobj->validcount != validcount)
|
|
{
|
|
polyLink->polyobj->validcount = validcount;
|
|
tempSeg = polyLink->polyobj->segs;
|
|
for(i = 0; i < polyLink->polyobj->numsegs; i++, tempSeg++)
|
|
{
|
|
if((*tempSeg)->linedef->validcount == validcount)
|
|
{
|
|
continue;
|
|
}
|
|
(*tempSeg)->linedef->validcount = validcount;
|
|
if(!func((*tempSeg)->linedef))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
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;
|
|
|
|
if ( !func(ld) )
|
|
return false;
|
|
}
|
|
|
|
return true; // everything was checked
|
|
}
|
|
|
|
|
|
/*
|
|
==================
|
|
=
|
|
= P_BlockThingsIterator
|
|
=
|
|
==================
|
|
*/
|
|
|
|
boolean P_BlockThingsIterator (int x, int y, boolean(*func)(mobj_t*) )
|
|
{
|
|
mobj_t *mobj;
|
|
|
|
if (x<0 || y<0 || x>=bmapwidth || y>=bmapheight)
|
|
return true;
|
|
|
|
for (mobj = blocklinks[y*bmapwidth+x] ; mobj ; mobj = mobj->bnext)
|
|
if (!func( mobj ) )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
INTERCEPT ROUTINES
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
intercept_t intercepts[MAXINTERCEPTS], *intercept_p;
|
|
|
|
divline_t trace;
|
|
boolean earlyout;
|
|
int ptflags;
|
|
|
|
/*
|
|
==================
|
|
=
|
|
= PIT_AddLineIntercepts
|
|
=
|
|
= Looks for lines in the given block that intercept the given trace
|
|
= to add to the intercepts list
|
|
= A line is crossed if its endpoints are on opposite sides of the trace
|
|
= Returns true if earlyout and a solid line hit
|
|
==================
|
|
*/
|
|
|
|
boolean PIT_AddLineIntercepts (line_t *ld)
|
|
{
|
|
int s1, s2;
|
|
fixed_t frac;
|
|
divline_t dl;
|
|
|
|
// avoid precision problems with two routines
|
|
if ( trace.dx > FRACUNIT*16 || trace.dy > FRACUNIT*16
|
|
|| trace.dx < -FRACUNIT*16 || trace.dy < -FRACUNIT*16)
|
|
{
|
|
s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &trace);
|
|
s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &trace);
|
|
}
|
|
else
|
|
{
|
|
s1 = P_PointOnLineSide (trace.x, trace.y, ld);
|
|
s2 = P_PointOnLineSide (trace.x+trace.dx, trace.y+trace.dy, ld);
|
|
}
|
|
if (s1 == s2)
|
|
return true; // line isn't crossed
|
|
|
|
//
|
|
// hit the line
|
|
//
|
|
P_MakeDivline (ld, &dl);
|
|
frac = P_InterceptVector (&trace, &dl);
|
|
if (frac < 0)
|
|
return true; // behind source
|
|
|
|
// try to early out the check
|
|
if (earlyout && frac < FRACUNIT && !ld->backsector)
|
|
return false; // stop checking
|
|
|
|
intercept_p->frac = frac;
|
|
intercept_p->isaline = true;
|
|
intercept_p->d.line = ld;
|
|
intercept_p++;
|
|
|
|
return true; // continue
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
==================
|
|
=
|
|
= PIT_AddThingIntercepts
|
|
=
|
|
==================
|
|
*/
|
|
|
|
boolean PIT_AddThingIntercepts (mobj_t *thing)
|
|
{
|
|
fixed_t x1,y1, x2,y2;
|
|
int s1, s2;
|
|
boolean tracepositive;
|
|
divline_t dl;
|
|
fixed_t frac;
|
|
|
|
tracepositive = (trace.dx ^ trace.dy)>0;
|
|
|
|
// check a corner to corner crossection for hit
|
|
|
|
if (tracepositive)
|
|
{
|
|
x1 = thing->x - thing->radius;
|
|
y1 = thing->y + thing->radius;
|
|
|
|
x2 = thing->x + thing->radius;
|
|
y2 = thing->y - thing->radius;
|
|
}
|
|
else
|
|
{
|
|
x1 = thing->x - thing->radius;
|
|
y1 = thing->y - thing->radius;
|
|
|
|
x2 = thing->x + thing->radius;
|
|
y2 = thing->y + thing->radius;
|
|
}
|
|
s1 = P_PointOnDivlineSide (x1, y1, &trace);
|
|
s2 = P_PointOnDivlineSide (x2, y2, &trace);
|
|
if (s1 == s2)
|
|
return true; // line isn't crossed
|
|
|
|
dl.x = x1;
|
|
dl.y = y1;
|
|
dl.dx = x2-x1;
|
|
dl.dy = y2-y1;
|
|
frac = P_InterceptVector (&trace, &dl);
|
|
if (frac < 0)
|
|
return true; // behind source
|
|
intercept_p->frac = frac;
|
|
intercept_p->isaline = false;
|
|
intercept_p->d.thing = thing;
|
|
intercept_p++;
|
|
|
|
return true; // keep going
|
|
}
|
|
|
|
|
|
/*
|
|
====================
|
|
=
|
|
= P_TraverseIntercepts
|
|
=
|
|
= Returns true if the traverser function returns true for all lines
|
|
====================
|
|
*/
|
|
|
|
boolean P_TraverseIntercepts ( traverser_t func, fixed_t maxfrac )
|
|
{
|
|
int count;
|
|
fixed_t dist;
|
|
intercept_t *scan, *in;
|
|
|
|
count = intercept_p - intercepts;
|
|
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 (dist > maxfrac)
|
|
return true; // checked everything in range
|
|
#if 0
|
|
{ // don't check these yet, ther may be others inserted
|
|
in = scan = intercepts;
|
|
for ( scan = intercepts ; scan<intercept_p ; scan++)
|
|
if (scan->frac > maxfrac)
|
|
*in++ = *scan;
|
|
intercept_p = in;
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
if ( !func (in) )
|
|
return false; // don't bother going farther
|
|
in->frac = MAXINT;
|
|
}
|
|
|
|
return true; // everything was traversed
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
==================
|
|
=
|
|
= P_PathTraverse
|
|
=
|
|
= 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_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2,
|
|
int flags, boolean (*trav) (intercept_t *))
|
|
{
|
|
fixed_t xt1,yt1,xt2,yt2;
|
|
fixed_t xstep,ystep;
|
|
fixed_t partial;
|
|
fixed_t xintercept, yintercept;
|
|
int mapx, mapy, mapxstep, mapystep;
|
|
int count;
|
|
|
|
earlyout = flags & PT_EARLYOUT;
|
|
|
|
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;
|
|
|
|
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 (flags & PT_ADDLINES)
|
|
{
|
|
if (!P_BlockLinesIterator (mapx, mapy,PIT_AddLineIntercepts))
|
|
return false; // early out
|
|
}
|
|
if (flags & PT_ADDTHINGS)
|
|
{
|
|
if (!P_BlockThingsIterator (mapx, mapy,PIT_AddThingIntercepts))
|
|
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;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// go through the sorted list
|
|
//
|
|
return P_TraverseIntercepts ( trav, FRACUNIT );
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// P_RoughMonsterSearch
|
|
//
|
|
// Searches though the surrounding mapblocks for monsters/players
|
|
// distance is in MAPBLOCKUNITS
|
|
//===========================================================================
|
|
|
|
mobj_t *P_RoughMonsterSearch(mobj_t *mo, int distance)
|
|
{
|
|
int blockX;
|
|
int blockY;
|
|
int startX, startY;
|
|
int blockIndex;
|
|
int firstStop;
|
|
int secondStop;
|
|
int thirdStop;
|
|
int finalStop;
|
|
int count;
|
|
mobj_t *target;
|
|
|
|
startX = (mo->x-bmaporgx)>>MAPBLOCKSHIFT;
|
|
startY = (mo->y-bmaporgy)>>MAPBLOCKSHIFT;
|
|
|
|
if(startX >= 0 && startX < bmapwidth && startY >= 0 && startY < bmapheight)
|
|
{
|
|
if(target = RoughBlockCheck(mo, startY*bmapwidth+startX))
|
|
{ // found a target right away
|
|
return target;
|
|
}
|
|
}
|
|
for(count = 1; count <= distance; count++)
|
|
{
|
|
blockX = startX-count;
|
|
blockY = startY-count;
|
|
|
|
if(blockY < 0)
|
|
{
|
|
blockY = 0;
|
|
}
|
|
else if(blockY >= bmapheight)
|
|
{
|
|
blockY = bmapheight-1;
|
|
}
|
|
if(blockX < 0)
|
|
{
|
|
blockX = 0;
|
|
}
|
|
else if(blockX >= bmapwidth)
|
|
{
|
|
blockX = bmapwidth-1;
|
|
}
|
|
blockIndex = blockY*bmapwidth+blockX;
|
|
firstStop = startX+count;
|
|
if(firstStop < 0)
|
|
{
|
|
continue;
|
|
}
|
|
if(firstStop >= bmapwidth)
|
|
{
|
|
firstStop = bmapwidth-1;
|
|
}
|
|
secondStop = startY+count;
|
|
if(secondStop < 0)
|
|
{
|
|
continue;
|
|
}
|
|
if(secondStop >= bmapheight)
|
|
{
|
|
secondStop = bmapheight-1;
|
|
}
|
|
thirdStop = secondStop*bmapwidth+blockX;
|
|
secondStop = secondStop*bmapwidth+firstStop;
|
|
firstStop += blockY*bmapwidth;
|
|
finalStop = blockIndex;
|
|
|
|
// Trace the first block section (along the top)
|
|
for(; blockIndex <= firstStop; blockIndex++)
|
|
{
|
|
if(target = RoughBlockCheck(mo, blockIndex))
|
|
{
|
|
return target;
|
|
}
|
|
}
|
|
// Trace the second block section (right edge)
|
|
for(blockIndex--; blockIndex <= secondStop; blockIndex += bmapwidth)
|
|
{
|
|
if(target = RoughBlockCheck(mo, blockIndex))
|
|
{
|
|
return target;
|
|
}
|
|
}
|
|
// Trace the third block section (bottom edge)
|
|
for(blockIndex -= bmapwidth; blockIndex >= thirdStop; blockIndex--)
|
|
{
|
|
if(target = RoughBlockCheck(mo, blockIndex))
|
|
{
|
|
return target;
|
|
}
|
|
}
|
|
// Trace the final block section (left edge)
|
|
for(blockIndex++; blockIndex > finalStop; blockIndex -= bmapwidth)
|
|
{
|
|
if(target = RoughBlockCheck(mo, blockIndex))
|
|
{
|
|
return target;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// RoughBlockCheck
|
|
//
|
|
//===========================================================================
|
|
|
|
static mobj_t *RoughBlockCheck(mobj_t *mo, int index)
|
|
{
|
|
mobj_t *link;
|
|
mobj_t *master;
|
|
angle_t angle;
|
|
|
|
link = blocklinks[index];
|
|
while(link)
|
|
{
|
|
if (mo->player) // Minotaur looking around player
|
|
{
|
|
if ((link->flags&MF_COUNTKILL) ||
|
|
(link->player && (link != mo)))
|
|
{
|
|
if (!(link->flags&MF_SHOOTABLE))
|
|
{
|
|
link = link->bnext;
|
|
continue;
|
|
}
|
|
if (link->flags2&MF2_DORMANT)
|
|
{
|
|
link = link->bnext;
|
|
continue;
|
|
}
|
|
if ((link->type == MT_MINOTAUR) &&
|
|
(((mobj_t *)link->special1) == mo))
|
|
{
|
|
link = link->bnext;
|
|
continue;
|
|
}
|
|
if(netgame && !deathmatch && link->player)
|
|
{
|
|
link = link->bnext;
|
|
continue;
|
|
}
|
|
if(P_CheckSight(mo, link))
|
|
{
|
|
return link;
|
|
}
|
|
}
|
|
link = link->bnext;
|
|
}
|
|
else if (mo->type == MT_MINOTAUR) // looking around minotaur
|
|
{
|
|
master = (mobj_t *)mo->special1;
|
|
if ((link->flags&MF_COUNTKILL) ||
|
|
(link->player && (link != master)))
|
|
{
|
|
if (!(link->flags&MF_SHOOTABLE))
|
|
{
|
|
link = link->bnext;
|
|
continue;
|
|
}
|
|
if (link->flags2&MF2_DORMANT)
|
|
{
|
|
link = link->bnext;
|
|
continue;
|
|
}
|
|
if ((link->type == MT_MINOTAUR) &&
|
|
(link->special1 == mo->special1))
|
|
{
|
|
link = link->bnext;
|
|
continue;
|
|
}
|
|
if(netgame && !deathmatch && link->player)
|
|
{
|
|
link = link->bnext;
|
|
continue;
|
|
}
|
|
if(P_CheckSight(mo, link))
|
|
{
|
|
return link;
|
|
}
|
|
}
|
|
link = link->bnext;
|
|
}
|
|
else if (mo->type == MT_MSTAFF_FX2) // bloodscourge
|
|
{
|
|
if ((link->flags&MF_COUNTKILL ||
|
|
(link->player && link != mo->target))
|
|
&& !(link->flags2&MF2_DORMANT))
|
|
{
|
|
if (!(link->flags&MF_SHOOTABLE))
|
|
{
|
|
link = link->bnext;
|
|
continue;
|
|
}
|
|
if(netgame && !deathmatch && link->player)
|
|
{
|
|
link = link->bnext;
|
|
continue;
|
|
}
|
|
else if(P_CheckSight(mo, link))
|
|
{
|
|
master = mo->target;
|
|
angle = R_PointToAngle2(master->x, master->y,
|
|
link->x, link->y) - master->angle;
|
|
angle >>= 24;
|
|
if (angle>226 || angle<30)
|
|
{
|
|
return link;
|
|
}
|
|
}
|
|
}
|
|
link = link->bnext;
|
|
}
|
|
else // spirits
|
|
{
|
|
if ((link->flags&MF_COUNTKILL ||
|
|
(link->player && link != mo->target))
|
|
&& !(link->flags2&MF2_DORMANT))
|
|
{
|
|
if (!(link->flags&MF_SHOOTABLE))
|
|
{
|
|
link = link->bnext;
|
|
continue;
|
|
}
|
|
if(netgame && !deathmatch && link->player)
|
|
{
|
|
link = link->bnext;
|
|
continue;
|
|
}
|
|
if (link == mo->target)
|
|
{
|
|
link = link->bnext;
|
|
continue;
|
|
}
|
|
else if(P_CheckSight(mo, link))
|
|
{
|
|
return link;
|
|
}
|
|
}
|
|
link = link->bnext;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|