mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Condense all of the P_CheckSight copy-paste
For something for my next commit
This commit is contained in:
parent
d5b62886d2
commit
cb580031ca
1 changed files with 306 additions and 394 deletions
700
src/p_sight.c
700
src/p_sight.c
|
|
@ -27,13 +27,26 @@
|
||||||
// killough 4/19/98:
|
// killough 4/19/98:
|
||||||
// Convert LOS info to struct for reentrancy and efficiency of data locality
|
// Convert LOS info to struct for reentrancy and efficiency of data locality
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
fixed_t sightzstart, t2x, t2y; // eye z of looker
|
{
|
||||||
divline_t strace; // from t1 to t2
|
fixed_t sightzstart, t2x, t2y; // eye z of looker
|
||||||
fixed_t topslope, bottomslope; // slopes to top and bottom of target
|
divline_t strace; // from t1 to t2
|
||||||
|
fixed_t topslope, bottomslope; // slopes to top and bottom of target
|
||||||
fixed_t bbox[4];
|
fixed_t bbox[4];
|
||||||
|
|
||||||
|
mobj_t *compareThing; // Original thing
|
||||||
|
boolean alreadyHates; // For bot traversal, for if the bot is already in a sector it doesn't want to be
|
||||||
} los_t;
|
} los_t;
|
||||||
|
|
||||||
|
typedef boolean (*los_valid_t)(seg_t *, divline_t *, register los_t *);
|
||||||
|
typedef boolean (*los_valid_poly_t)(polyobj_t *, divline_t *, register los_t *);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
los_valid_t validate; // Validation function. If true, continue iterating for possible success. If false, end early with failure.
|
||||||
|
los_valid_poly_t validatePolyobj; // If not NULL, then we will also check polyobject lines using this func.
|
||||||
|
} los_funcs_t;
|
||||||
|
|
||||||
static INT32 sightcounts[2];
|
static INT32 sightcounts[2];
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
@ -103,23 +116,58 @@ static fixed_t P_InterceptVector2(divline_t *v2, divline_t *v1)
|
||||||
return frac;
|
return frac;
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean P_CrossSubsecPolyObj(polyobj_t *po, register los_t *los)
|
static boolean P_IsVisiblePolyObj(polyobj_t *po, divline_t *divl, register los_t *los)
|
||||||
{
|
{
|
||||||
size_t i;
|
sector_t *polysec = po->lines[0]->backsector;
|
||||||
sector_t *polysec;
|
fixed_t frac;
|
||||||
|
fixed_t topslope, bottomslope;
|
||||||
|
|
||||||
if (!(po->flags & POF_RENDERALL))
|
if (!(po->flags & POF_RENDERALL))
|
||||||
|
{
|
||||||
return true; // the polyobject isn't visible, so we can ignore it
|
return true; // the polyobject isn't visible, so we can ignore it
|
||||||
|
}
|
||||||
|
|
||||||
polysec = po->lines[0]->backsector;
|
// stop because it is not two sided
|
||||||
|
/*
|
||||||
|
if (!(po->flags & POF_TESTHEIGHT))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
frac = P_InterceptVector2(&los->strace, divl);
|
||||||
|
|
||||||
|
// get slopes of top and bottom of this polyobject line
|
||||||
|
topslope = FixedDiv(polysec->ceilingheight - los->sightzstart , frac);
|
||||||
|
bottomslope = FixedDiv(polysec->floorheight - los->sightzstart , frac);
|
||||||
|
|
||||||
|
if (topslope >= los->topslope && bottomslope <= los->bottomslope)
|
||||||
|
{
|
||||||
|
// view completely blocked
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: figure out if it's worth considering partially blocked cases or not?
|
||||||
|
// maybe to adjust los's top/bottom slopes if needed
|
||||||
|
/*
|
||||||
|
if (los->topslope <= los->bottomslope)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean P_CrossSubsecPolyObj(polyobj_t *po, register los_t *los, register los_funcs_t *funcs)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < po->numLines; ++i)
|
for (i = 0; i < po->numLines; ++i)
|
||||||
{
|
{
|
||||||
line_t *line = po->lines[i];
|
line_t *line = po->lines[i];
|
||||||
divline_t divl;
|
divline_t divl;
|
||||||
const vertex_t *v1,*v2;
|
const vertex_t *v1,*v2;
|
||||||
fixed_t frac;
|
|
||||||
fixed_t topslope, bottomslope;
|
|
||||||
|
|
||||||
// already checked other side?
|
// already checked other side?
|
||||||
if (line->validcount == validcount)
|
if (line->validcount == validcount)
|
||||||
|
|
@ -150,23 +198,195 @@ static boolean P_CrossSubsecPolyObj(polyobj_t *po, register los_t *los)
|
||||||
P_DivlineSide(los->t2x, los->t2y, &divl))
|
P_DivlineSide(los->t2x, los->t2y, &divl))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// stop because it is not two sided
|
if (funcs->validatePolyobj(po, &divl, los) == false)
|
||||||
//if (!(po->flags & POF_TESTHEIGHT))
|
{
|
||||||
//return false;
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
frac = P_InterceptVector2(&los->strace, &divl);
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// get slopes of top and bottom of this polyobject line
|
static boolean P_IsVisible(seg_t *seg, divline_t *divl, register los_t *los)
|
||||||
topslope = FixedDiv(polysec->ceilingheight - los->sightzstart , frac);
|
{
|
||||||
bottomslope = FixedDiv(polysec->floorheight - los->sightzstart , frac);
|
line_t *line = seg->linedef;
|
||||||
|
fixed_t popentop, popenbottom;
|
||||||
|
const sector_t *front, *back;
|
||||||
|
fixed_t frac;
|
||||||
|
fixed_t fracx, fracy;
|
||||||
|
fixed_t frontf, backf, frontc, backc;
|
||||||
|
|
||||||
if (topslope >= los->topslope && bottomslope <= los->bottomslope)
|
// stop because it is not two sided anyway
|
||||||
return false; // view completely blocked
|
if (!(line->flags & ML_TWOSIDED))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate fractional intercept (how far along we are divided by how far we are from t2)
|
||||||
|
frac = P_InterceptVector2(&los->strace, divl);
|
||||||
|
|
||||||
|
front = seg->frontsector;
|
||||||
|
back = seg->backsector;
|
||||||
|
// calculate position at intercept
|
||||||
|
fracx = los->strace.x + FixedMul(los->strace.dx, frac);
|
||||||
|
fracy = los->strace.y + FixedMul(los->strace.dy, frac);
|
||||||
|
// calculate sector heights
|
||||||
|
frontf = P_GetSectorFloorZAt (front, fracx, fracy);
|
||||||
|
frontc = P_GetSectorCeilingZAt(front, fracx, fracy);
|
||||||
|
backf = P_GetSectorFloorZAt (back , fracx, fracy);
|
||||||
|
backc = P_GetSectorCeilingZAt(back , fracx, fracy);
|
||||||
|
// crosses a two sided line
|
||||||
|
// no wall to block sight with?
|
||||||
|
if (frontf == backf && frontc == backc
|
||||||
|
&& !front->ffloors & !back->ffloors) // (and no FOFs)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// possible occluder
|
||||||
|
// because of ceiling height differences
|
||||||
|
popentop = min(frontc, backc);
|
||||||
|
|
||||||
|
// because of floor height differences
|
||||||
|
popenbottom = max(frontf, backf);
|
||||||
|
|
||||||
|
// quick test for totally closed doors
|
||||||
|
if (popenbottom >= popentop)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frontf != backf)
|
||||||
|
{
|
||||||
|
fixed_t slope = FixedDiv(popenbottom - los->sightzstart , frac);
|
||||||
|
if (slope > los->bottomslope)
|
||||||
|
los->bottomslope = slope;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frontc != backc)
|
||||||
|
{
|
||||||
|
fixed_t slope = FixedDiv(popentop - los->sightzstart , frac);
|
||||||
|
if (slope < los->topslope)
|
||||||
|
los->topslope = slope;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (los->topslope <= los->bottomslope)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Monster Iestyn: check FOFs!
|
||||||
|
if (front->ffloors || back->ffloors)
|
||||||
|
{
|
||||||
|
ffloor_t *rover;
|
||||||
|
fixed_t topslope, bottomslope;
|
||||||
|
fixed_t topz, bottomz;
|
||||||
|
// check front sector's FOFs first
|
||||||
|
for (rover = front->ffloors; rover; rover = rover->next)
|
||||||
|
{
|
||||||
|
if (!(rover->fofflags & FOF_EXISTS)
|
||||||
|
|| !(rover->fofflags & FOF_RENDERSIDES) || (rover->fofflags & (FOF_TRANSLUCENT|FOF_FOG)))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
topz = P_GetFFloorTopZAt (rover, fracx, fracy);
|
||||||
|
bottomz = P_GetFFloorBottomZAt(rover, fracx, fracy);
|
||||||
|
topslope = FixedDiv( topz - los->sightzstart, frac);
|
||||||
|
bottomslope = FixedDiv(bottomz - los->sightzstart, frac);
|
||||||
|
|
||||||
|
if (topslope >= los->topslope && bottomslope <= los->bottomslope)
|
||||||
|
{
|
||||||
|
return false; // view completely blocked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check back sector's FOFs as well
|
||||||
|
for (rover = back->ffloors; rover; rover = rover->next)
|
||||||
|
{
|
||||||
|
if (!(rover->fofflags & FOF_EXISTS)
|
||||||
|
|| !(rover->fofflags & FOF_RENDERSIDES) || (rover->fofflags & (FOF_TRANSLUCENT|FOF_FOG)))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
topz = P_GetFFloorTopZAt (rover, fracx, fracy);
|
||||||
|
bottomz = P_GetFFloorBottomZAt(rover, fracx, fracy);
|
||||||
|
topslope = FixedDiv( topz - los->sightzstart, frac);
|
||||||
|
bottomslope = FixedDiv(bottomz - los->sightzstart, frac);
|
||||||
|
|
||||||
|
if (topslope >= los->topslope && bottomslope <= los->bottomslope)
|
||||||
|
{
|
||||||
|
return false; // view completely blocked
|
||||||
|
}
|
||||||
|
}
|
||||||
// TODO: figure out if it's worth considering partially blocked cases or not?
|
// TODO: figure out if it's worth considering partially blocked cases or not?
|
||||||
// maybe to adjust los's top/bottom slopes if needed
|
// maybe to adjust los's top/bottom slopes if needed
|
||||||
//if (los->topslope <= los->bottomslope)
|
}
|
||||||
//return false;
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean P_CanTraceBlockingLine(seg_t *seg, divline_t *divl, register los_t *los)
|
||||||
|
{
|
||||||
|
line_t *line = seg->linedef;
|
||||||
|
|
||||||
|
(void)divl;
|
||||||
|
|
||||||
|
if (P_IsLineBlocking(line, los->compareThing) == true)
|
||||||
|
{
|
||||||
|
// This line will always block us
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (los->compareThing->player != NULL)
|
||||||
|
{
|
||||||
|
if (P_IsLineTripWire(line) == true && K_TripwirePass(los->compareThing->player) == false)
|
||||||
|
{
|
||||||
|
// Can't go through trip wire.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean P_CanBotTraverse(seg_t *seg, divline_t *divl, register los_t *los)
|
||||||
|
{
|
||||||
|
line_t *line = seg->linedef;
|
||||||
|
fixed_t maxstep = 0;
|
||||||
|
|
||||||
|
if (P_CanTraceBlockingLine(seg, divl, los) == false)
|
||||||
|
{
|
||||||
|
// Blocked, so obviously can't traverse either.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set openrange, opentop, openbottom
|
||||||
|
tm.x = los->compareThing->x;
|
||||||
|
tm.y = los->compareThing->y;
|
||||||
|
P_LineOpening(line, los->compareThing);
|
||||||
|
maxstep = P_GetThingStepUp(los->compareThing, tm.x, tm.y);
|
||||||
|
|
||||||
|
if ((openrange < los->compareThing->height) // doesn't fit
|
||||||
|
|| (opentop - los->compareThing->z < los->compareThing->height) // mobj is too high
|
||||||
|
|| (openbottom - los->compareThing->z > maxstep)) // too big a step up
|
||||||
|
{
|
||||||
|
// This line situationally blocks us
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (los->compareThing->player != NULL && los->alreadyHates == false)
|
||||||
|
{
|
||||||
|
// Treat damage sectors like walls, if you're not already in a bad sector.
|
||||||
|
vertex_t pos;
|
||||||
|
P_ClosestPointOnLine(los->compareThing->x, los->compareThing->y, line, &pos);
|
||||||
|
|
||||||
|
if (K_BotHatesThisSector(los->compareThing->player, line->frontsector, pos.x, pos.y)
|
||||||
|
|| K_BotHatesThisSector(los->compareThing->player, line->backsector, pos.x, pos.y))
|
||||||
|
{
|
||||||
|
// This line does not block us, but we don't want to be in it.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -177,11 +397,10 @@ static boolean P_CrossSubsecPolyObj(polyobj_t *po, register los_t *los)
|
||||||
//
|
//
|
||||||
// Returns true if strace crosses the given subsector successfully.
|
// Returns true if strace crosses the given subsector successfully.
|
||||||
//
|
//
|
||||||
static boolean P_CrossSubsector(size_t num, register los_t *los)
|
static boolean P_CrossSubsector(size_t num, register los_t *los, register los_funcs_t *funcs)
|
||||||
{
|
{
|
||||||
seg_t *seg;
|
seg_t *seg;
|
||||||
INT32 count;
|
INT32 count;
|
||||||
polyobj_t *po; // haleyjd 02/23/06
|
|
||||||
|
|
||||||
#ifdef RANGECHECK
|
#ifdef RANGECHECK
|
||||||
if (num >= numsubsectors)
|
if (num >= numsubsectors)
|
||||||
|
|
@ -192,30 +411,30 @@ static boolean P_CrossSubsector(size_t num, register los_t *los)
|
||||||
seg = segs + subsectors[num].firstline;
|
seg = segs + subsectors[num].firstline;
|
||||||
|
|
||||||
// haleyjd 02/23/06: check polyobject lines
|
// haleyjd 02/23/06: check polyobject lines
|
||||||
if ((po = subsectors[num].polyList))
|
if (funcs->validatePolyobj != NULL)
|
||||||
{
|
{
|
||||||
while (po)
|
polyobj_t *po;
|
||||||
|
|
||||||
|
if ((po = subsectors[num].polyList))
|
||||||
{
|
{
|
||||||
if (po->validcount != validcount)
|
while (po)
|
||||||
{
|
{
|
||||||
po->validcount = validcount;
|
if (po->validcount != validcount)
|
||||||
if (!P_CrossSubsecPolyObj(po, los))
|
{
|
||||||
return false;
|
po->validcount = validcount;
|
||||||
|
if (!P_CrossSubsecPolyObj(po, los, funcs))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
po = (polyobj_t *)(po->link.next);
|
||||||
}
|
}
|
||||||
po = (polyobj_t *)(po->link.next);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (count = subsectors[num].numlines; --count >= 0; seg++) // check lines
|
for (count = subsectors[num].numlines; --count >= 0; seg++) // check lines
|
||||||
{
|
{
|
||||||
line_t *line = seg->linedef;
|
line_t *line = seg->linedef;
|
||||||
|
const vertex_t *v1, *v2;
|
||||||
divline_t divl;
|
divline_t divl;
|
||||||
fixed_t popentop, popenbottom;
|
|
||||||
const sector_t *front, *back;
|
|
||||||
const vertex_t *v1,*v2;
|
|
||||||
fixed_t frac;
|
|
||||||
fixed_t frontf, backf, frontc, backc;
|
|
||||||
fixed_t fracx, fracy;
|
|
||||||
|
|
||||||
if (seg->glseg)
|
if (seg->glseg)
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -249,99 +468,9 @@ static boolean P_CrossSubsector(size_t num, register los_t *los)
|
||||||
P_DivlineSide(los->t2x, los->t2y, &divl))
|
P_DivlineSide(los->t2x, los->t2y, &divl))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// stop because it is not two sided anyway
|
if (funcs->validate(seg, &divl, los) == false)
|
||||||
if (!(line->flags & ML_TWOSIDED))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// calculate fractional intercept (how far along we are divided by how far we are from t2)
|
|
||||||
frac = P_InterceptVector2(&los->strace, &divl);
|
|
||||||
|
|
||||||
front = seg->frontsector;
|
|
||||||
back = seg->backsector;
|
|
||||||
// calculate position at intercept
|
|
||||||
fracx = los->strace.x + FixedMul(los->strace.dx, frac);
|
|
||||||
fracy = los->strace.y + FixedMul(los->strace.dy, frac);
|
|
||||||
// calculate sector heights
|
|
||||||
frontf = P_GetSectorFloorZAt (front, fracx, fracy);
|
|
||||||
frontc = P_GetSectorCeilingZAt(front, fracx, fracy);
|
|
||||||
backf = P_GetSectorFloorZAt (back , fracx, fracy);
|
|
||||||
backc = P_GetSectorCeilingZAt(back , fracx, fracy);
|
|
||||||
// crosses a two sided line
|
|
||||||
// no wall to block sight with?
|
|
||||||
if (frontf == backf && frontc == backc
|
|
||||||
&& !front->ffloors & !back->ffloors) // (and no FOFs)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// possible occluder
|
|
||||||
// because of ceiling height differences
|
|
||||||
popentop = min(frontc, backc);
|
|
||||||
|
|
||||||
// because of floor height differences
|
|
||||||
popenbottom = max(frontf, backf);
|
|
||||||
|
|
||||||
// quick test for totally closed doors
|
|
||||||
if (popenbottom >= popentop)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (frontf != backf)
|
|
||||||
{
|
{
|
||||||
fixed_t slope = FixedDiv(popenbottom - los->sightzstart , frac);
|
|
||||||
if (slope > los->bottomslope)
|
|
||||||
los->bottomslope = slope;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (frontc != backc)
|
|
||||||
{
|
|
||||||
fixed_t slope = FixedDiv(popentop - los->sightzstart , frac);
|
|
||||||
if (slope < los->topslope)
|
|
||||||
los->topslope = slope;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (los->topslope <= los->bottomslope)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Monster Iestyn: check FOFs!
|
|
||||||
if (front->ffloors || back->ffloors)
|
|
||||||
{
|
|
||||||
ffloor_t *rover;
|
|
||||||
fixed_t topslope, bottomslope;
|
|
||||||
fixed_t topz, bottomz;
|
|
||||||
// check front sector's FOFs first
|
|
||||||
for (rover = front->ffloors; rover; rover = rover->next)
|
|
||||||
{
|
|
||||||
if (!(rover->fofflags & FOF_EXISTS)
|
|
||||||
|| !(rover->fofflags & FOF_RENDERSIDES) || (rover->fofflags & (FOF_TRANSLUCENT|FOF_FOG)))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
topz = P_GetFFloorTopZAt (rover, fracx, fracy);
|
|
||||||
bottomz = P_GetFFloorBottomZAt(rover, fracx, fracy);
|
|
||||||
topslope = FixedDiv( topz - los->sightzstart, frac);
|
|
||||||
bottomslope = FixedDiv(bottomz - los->sightzstart, frac);
|
|
||||||
|
|
||||||
if (topslope >= los->topslope && bottomslope <= los->bottomslope)
|
|
||||||
return false; // view completely blocked
|
|
||||||
}
|
|
||||||
// check back sector's FOFs as well
|
|
||||||
for (rover = back->ffloors; rover; rover = rover->next)
|
|
||||||
{
|
|
||||||
if (!(rover->fofflags & FOF_EXISTS)
|
|
||||||
|| !(rover->fofflags & FOF_RENDERSIDES) || (rover->fofflags & (FOF_TRANSLUCENT|FOF_FOG)))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
topz = P_GetFFloorTopZAt (rover, fracx, fracy);
|
|
||||||
bottomz = P_GetFFloorBottomZAt(rover, fracx, fracy);
|
|
||||||
topslope = FixedDiv( topz - los->sightzstart, frac);
|
|
||||||
bottomslope = FixedDiv(bottomz - los->sightzstart, frac);
|
|
||||||
|
|
||||||
if (topslope >= los->topslope && bottomslope <= los->bottomslope)
|
|
||||||
return false; // view completely blocked
|
|
||||||
}
|
|
||||||
// TODO: figure out if it's worth considering partially blocked cases or not?
|
|
||||||
// maybe to adjust los's top/bottom slopes if needed
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -356,24 +485,32 @@ static boolean P_CrossSubsector(size_t num, register los_t *los)
|
||||||
//
|
//
|
||||||
// killough 4/20/98: rewritten to remove tail recursion, clean up, and optimize
|
// killough 4/20/98: rewritten to remove tail recursion, clean up, and optimize
|
||||||
|
|
||||||
static boolean P_CrossBSPNode(INT32 bspnum, register los_t *los)
|
static boolean P_CrossBSPNode(INT32 bspnum, register los_t *los, register los_funcs_t *funcs)
|
||||||
{
|
{
|
||||||
|
if (funcs->validate == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
while (!(bspnum & NF_SUBSECTOR))
|
while (!(bspnum & NF_SUBSECTOR))
|
||||||
{
|
{
|
||||||
register node_t *bsp = nodes + bspnum;
|
register node_t *bsp = nodes + bspnum;
|
||||||
INT32 side = P_DivlineSide(los->strace.x,los->strace.y,(divline_t *)bsp)&1;
|
INT32 side = P_DivlineSide(los->strace.x, los->strace.y, (divline_t *)bsp) & 1;
|
||||||
|
|
||||||
if (side == P_DivlineSide(los->t2x, los->t2y, (divline_t *) bsp))
|
if (side == P_DivlineSide(los->t2x, los->t2y, (divline_t *) bsp))
|
||||||
|
{
|
||||||
bspnum = bsp->children[side]; // doesn't touch the other side
|
bspnum = bsp->children[side]; // doesn't touch the other side
|
||||||
|
}
|
||||||
else // the partition plane is crossed here
|
else // the partition plane is crossed here
|
||||||
{
|
{
|
||||||
if (!P_CrossBSPNode(bsp->children[side], los))
|
if (!P_CrossBSPNode(bsp->children[side], los, funcs))
|
||||||
return 0; // cross the starting side
|
return false; // cross the starting side
|
||||||
else
|
else
|
||||||
bspnum = bsp->children[side^1]; // cross the ending side
|
bspnum = bsp->children[side ^ 1]; // cross the ending side
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
|
||||||
P_CrossSubsector((bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR), los);
|
return P_CrossSubsector((bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR), los, funcs);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
@ -387,6 +524,7 @@ boolean P_CheckSight(mobj_t *t1, mobj_t *t2)
|
||||||
const sector_t *s1, *s2;
|
const sector_t *s1, *s2;
|
||||||
size_t pnum;
|
size_t pnum;
|
||||||
los_t los;
|
los_t los;
|
||||||
|
los_funcs_t funcs;
|
||||||
|
|
||||||
// First check for trivial rejection.
|
// First check for trivial rejection.
|
||||||
if (!t1 || !t2)
|
if (!t1 || !t2)
|
||||||
|
|
@ -423,6 +561,9 @@ boolean P_CheckSight(mobj_t *t1, mobj_t *t2)
|
||||||
|
|
||||||
validcount++;
|
validcount++;
|
||||||
|
|
||||||
|
los.compareThing = t1;
|
||||||
|
los.alreadyHates = false;
|
||||||
|
|
||||||
los.topslope =
|
los.topslope =
|
||||||
(los.bottomslope = t2->z - (los.sightzstart =
|
(los.bottomslope = t2->z - (los.sightzstart =
|
||||||
t1->z + t1->height -
|
t1->z + t1->height -
|
||||||
|
|
@ -498,127 +639,19 @@ boolean P_CheckSight(mobj_t *t1, mobj_t *t2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
funcs.validate = &P_IsVisible;
|
||||||
|
funcs.validatePolyobj = &P_IsVisiblePolyObj;
|
||||||
|
|
||||||
// the head node is the last node output
|
// the head node is the last node output
|
||||||
return P_CrossBSPNode((INT32)numnodes - 1, &los);
|
return P_CrossBSPNode((INT32)numnodes - 1, &los, &funcs);
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// P_TraceBlockingLines
|
|
||||||
//
|
|
||||||
// Returns true if a straight line between t1 and t2 is unobstructed.
|
|
||||||
// Unlike P_CheckSight, simplifed down to only check for explicit blocking lines on the 2D plane.
|
|
||||||
// Intended for Kart waypoints.
|
|
||||||
// Might be better in it's own file?
|
|
||||||
//
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
fixed_t t2x, t2y;
|
|
||||||
divline_t strace; // from t1 to t2
|
|
||||||
fixed_t bbox[4];
|
|
||||||
mobj_t *compareThing;
|
|
||||||
boolean alreadyHates;
|
|
||||||
} traceblocking_t;
|
|
||||||
|
|
||||||
static boolean P_CrossBlockingSubsector(size_t num, register traceblocking_t *tb)
|
|
||||||
{
|
|
||||||
seg_t *seg;
|
|
||||||
INT32 count;
|
|
||||||
|
|
||||||
#ifdef RANGECHECK
|
|
||||||
if (num >= numsubsectors)
|
|
||||||
I_Error("P_CrossBlockingSubsector: ss %s with numss = %s\n", sizeu1(num), sizeu2(numsubsectors));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// haleyjd 02/23/06: this assignment should be after the above check
|
|
||||||
seg = segs + subsectors[num].firstline;
|
|
||||||
|
|
||||||
for (count = subsectors[num].numlines; --count >= 0; seg++) // check lines
|
|
||||||
{
|
|
||||||
line_t *line = seg->linedef;
|
|
||||||
divline_t divl;
|
|
||||||
const vertex_t *v1,*v2;
|
|
||||||
|
|
||||||
if (seg->glseg)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// already checked other side?
|
|
||||||
if (line->validcount == validcount)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
line->validcount = validcount;
|
|
||||||
|
|
||||||
// OPTIMIZE: killough 4/20/98: Added quick bounding-box rejection test
|
|
||||||
if (line->bbox[BOXLEFT ] > tb->bbox[BOXRIGHT ] ||
|
|
||||||
line->bbox[BOXRIGHT ] < tb->bbox[BOXLEFT ] ||
|
|
||||||
line->bbox[BOXBOTTOM] > tb->bbox[BOXTOP ] ||
|
|
||||||
line->bbox[BOXTOP] < tb->bbox[BOXBOTTOM])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
v1 = line->v1;
|
|
||||||
v2 = line->v2;
|
|
||||||
|
|
||||||
// line isn't crossed?
|
|
||||||
if (P_DivlineSide(v1->x, v1->y, &tb->strace) ==
|
|
||||||
P_DivlineSide(v2->x, v2->y, &tb->strace))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// stop because it is not two sided anyway
|
|
||||||
if (!(line->flags & ML_TWOSIDED))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
divl.dx = v2->x - (divl.x = v1->x);
|
|
||||||
divl.dy = v2->y - (divl.y = v1->y);
|
|
||||||
|
|
||||||
// line isn't crossed?
|
|
||||||
if (P_DivlineSide(tb->strace.x, tb->strace.y, &divl) ==
|
|
||||||
P_DivlineSide(tb->t2x, tb->t2y, &divl))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (P_IsLineBlocking(line, tb->compareThing) == true)
|
|
||||||
{
|
|
||||||
// This line will always block us
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tb->compareThing->player != NULL)
|
|
||||||
{
|
|
||||||
if (P_IsLineTripWire(line) == true && K_TripwirePass(tb->compareThing->player) == false)
|
|
||||||
{
|
|
||||||
// Can't go through trip wire.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// passed the subsector ok
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean P_CrossBSPNodeBlocking(INT32 bspnum, register traceblocking_t *tb)
|
|
||||||
{
|
|
||||||
while (!(bspnum & NF_SUBSECTOR))
|
|
||||||
{
|
|
||||||
register node_t *bsp = nodes + bspnum;
|
|
||||||
INT32 side = P_DivlineSide(tb->strace.x,tb->strace.y,(divline_t *)bsp)&1;
|
|
||||||
if (side == P_DivlineSide(tb->t2x, tb->t2y, (divline_t *) bsp))
|
|
||||||
bspnum = bsp->children[side]; // doesn't touch the other side
|
|
||||||
else // the partition plane is crossed here
|
|
||||||
{
|
|
||||||
if (!P_CrossBSPNodeBlocking(bsp->children[side], tb))
|
|
||||||
return false; // cross the starting side
|
|
||||||
else
|
|
||||||
bspnum = bsp->children[side^1]; // cross the ending side
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return P_CrossBlockingSubsector((bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR), tb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean P_TraceBlockingLines(mobj_t *t1, mobj_t *t2)
|
boolean P_TraceBlockingLines(mobj_t *t1, mobj_t *t2)
|
||||||
{
|
{
|
||||||
const sector_t *s1, *s2;
|
const sector_t *s1, *s2;
|
||||||
size_t pnum;
|
size_t pnum;
|
||||||
traceblocking_t tb;
|
los_t los;
|
||||||
|
los_funcs_t funcs;
|
||||||
|
|
||||||
// First check for trivial rejection.
|
// First check for trivial rejection.
|
||||||
if (!t1 || !t2)
|
if (!t1 || !t2)
|
||||||
|
|
@ -651,161 +684,38 @@ boolean P_TraceBlockingLines(mobj_t *t1, mobj_t *t2)
|
||||||
|
|
||||||
validcount++;
|
validcount++;
|
||||||
|
|
||||||
tb.strace.dx = (tb.t2x = t2->x) - (tb.strace.x = t1->x);
|
los.strace.dx = (los.t2x = t2->x) - (los.strace.x = t1->x);
|
||||||
tb.strace.dy = (tb.t2y = t2->y) - (tb.strace.y = t1->y);
|
los.strace.dy = (los.t2y = t2->y) - (los.strace.y = t1->y);
|
||||||
|
|
||||||
if (t1->x > t2->x)
|
if (t1->x > t2->x)
|
||||||
tb.bbox[BOXRIGHT] = t1->x, tb.bbox[BOXLEFT] = t2->x;
|
los.bbox[BOXRIGHT] = t1->x, los.bbox[BOXLEFT] = t2->x;
|
||||||
else
|
else
|
||||||
tb.bbox[BOXRIGHT] = t2->x, tb.bbox[BOXLEFT] = t1->x;
|
los.bbox[BOXRIGHT] = t2->x, los.bbox[BOXLEFT] = t1->x;
|
||||||
|
|
||||||
if (t1->y > t2->y)
|
if (t1->y > t2->y)
|
||||||
tb.bbox[BOXTOP] = t1->y, tb.bbox[BOXBOTTOM] = t2->y;
|
los.bbox[BOXTOP] = t1->y, los.bbox[BOXBOTTOM] = t2->y;
|
||||||
else
|
else
|
||||||
tb.bbox[BOXTOP] = t2->y, tb.bbox[BOXBOTTOM] = t1->y;
|
los.bbox[BOXTOP] = t2->y, los.bbox[BOXBOTTOM] = t1->y;
|
||||||
|
|
||||||
tb.compareThing = t1;
|
los.compareThing = t1;
|
||||||
tb.alreadyHates = false;
|
los.alreadyHates = false;
|
||||||
|
|
||||||
|
funcs.validate = &P_CanTraceBlockingLine;
|
||||||
|
|
||||||
// the head node is the last node output
|
// the head node is the last node output
|
||||||
return P_CrossBSPNodeBlocking((INT32)numnodes - 1, &tb);
|
return P_CrossBSPNode((INT32)numnodes - 1, &los, &funcs);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// ANOTHER version, this time for bot traversal.
|
// ANOTHER version, this time for bot traversal.
|
||||||
// (TODO: since we have so many versions of this function, the differences
|
|
||||||
// should maybe just be a function var that gets called?)
|
|
||||||
//
|
//
|
||||||
|
|
||||||
static boolean P_CrossBotTraversalSubsector(size_t num, register traceblocking_t *tb)
|
|
||||||
{
|
|
||||||
seg_t *seg;
|
|
||||||
INT32 count;
|
|
||||||
|
|
||||||
#ifdef RANGECHECK
|
|
||||||
if (num >= numsubsectors)
|
|
||||||
I_Error("P_CrossBotTraversalSubsector: ss %s with numss = %s\n", sizeu1(num), sizeu2(numsubsectors));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// haleyjd 02/23/06: this assignment should be after the above check
|
|
||||||
seg = segs + subsectors[num].firstline;
|
|
||||||
|
|
||||||
for (count = subsectors[num].numlines; --count >= 0; seg++) // check lines
|
|
||||||
{
|
|
||||||
line_t *line = seg->linedef;
|
|
||||||
divline_t divl;
|
|
||||||
const vertex_t *v1,*v2;
|
|
||||||
fixed_t maxstep = INT32_MAX;
|
|
||||||
|
|
||||||
if (seg->glseg)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// already checked other side?
|
|
||||||
if (line->validcount == validcount)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
line->validcount = validcount;
|
|
||||||
|
|
||||||
// OPTIMIZE: killough 4/20/98: Added quick bounding-box rejection test
|
|
||||||
if (line->bbox[BOXLEFT ] > tb->bbox[BOXRIGHT ] ||
|
|
||||||
line->bbox[BOXRIGHT ] < tb->bbox[BOXLEFT ] ||
|
|
||||||
line->bbox[BOXBOTTOM] > tb->bbox[BOXTOP ] ||
|
|
||||||
line->bbox[BOXTOP] < tb->bbox[BOXBOTTOM])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
v1 = line->v1;
|
|
||||||
v2 = line->v2;
|
|
||||||
|
|
||||||
// line isn't crossed?
|
|
||||||
if (P_DivlineSide(v1->x, v1->y, &tb->strace) ==
|
|
||||||
P_DivlineSide(v2->x, v2->y, &tb->strace))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// stop because it is not two sided anyway
|
|
||||||
if (!(line->flags & ML_TWOSIDED))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
divl.dx = v2->x - (divl.x = v1->x);
|
|
||||||
divl.dy = v2->y - (divl.y = v1->y);
|
|
||||||
|
|
||||||
// line isn't crossed?
|
|
||||||
if (P_DivlineSide(tb->strace.x, tb->strace.y, &divl) ==
|
|
||||||
P_DivlineSide(tb->t2x, tb->t2y, &divl))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (P_IsLineBlocking(line, tb->compareThing) == true)
|
|
||||||
{
|
|
||||||
// This line will always block us
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tb->compareThing->player != NULL)
|
|
||||||
{
|
|
||||||
if (P_IsLineTripWire(line) == true && K_TripwirePass(tb->compareThing->player) == false)
|
|
||||||
{
|
|
||||||
// Can't go through trip wire.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set openrange, opentop, openbottom
|
|
||||||
tm.x = tb->compareThing->x;
|
|
||||||
tm.y = tb->compareThing->y;
|
|
||||||
P_LineOpening(line, tb->compareThing);
|
|
||||||
maxstep = P_GetThingStepUp(tb->compareThing, tm.x, tm.y);
|
|
||||||
|
|
||||||
if ((openrange < tb->compareThing->height) // doesn't fit
|
|
||||||
|| (opentop - tb->compareThing->z < tb->compareThing->height) // mobj is too high
|
|
||||||
|| (openbottom - tb->compareThing->z > maxstep)) // too big a step up
|
|
||||||
{
|
|
||||||
// This line situationally blocks us
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tb->compareThing->player != NULL && tb->alreadyHates == false)
|
|
||||||
{
|
|
||||||
// Treat damage sectors like walls, if you're not already in a bad sector.
|
|
||||||
vertex_t pos;
|
|
||||||
P_ClosestPointOnLine(tb->compareThing->x, tb->compareThing->y, line, &pos);
|
|
||||||
|
|
||||||
if (K_BotHatesThisSector(tb->compareThing->player, line->frontsector, pos.x, pos.y)
|
|
||||||
|| K_BotHatesThisSector(tb->compareThing->player, line->backsector, pos.x, pos.y))
|
|
||||||
{
|
|
||||||
// This line does not block us, but we don't want to be in it.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// passed the subsector ok
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean P_CrossBSPNodeBotTraversal(INT32 bspnum, register traceblocking_t *tb)
|
|
||||||
{
|
|
||||||
while (!(bspnum & NF_SUBSECTOR))
|
|
||||||
{
|
|
||||||
register node_t *bsp = nodes + bspnum;
|
|
||||||
INT32 side = P_DivlineSide(tb->strace.x,tb->strace.y,(divline_t *)bsp)&1;
|
|
||||||
if (side == P_DivlineSide(tb->t2x, tb->t2y, (divline_t *) bsp))
|
|
||||||
bspnum = bsp->children[side]; // doesn't touch the other side
|
|
||||||
else // the partition plane is crossed here
|
|
||||||
{
|
|
||||||
if (!P_CrossBSPNodeBotTraversal(bsp->children[side], tb))
|
|
||||||
return false; // cross the starting side
|
|
||||||
else
|
|
||||||
bspnum = bsp->children[side^1]; // cross the ending side
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return P_CrossBotTraversalSubsector((bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR), tb);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean P_TraceBotTraversal(mobj_t *t1, mobj_t *t2)
|
boolean P_TraceBotTraversal(mobj_t *t1, mobj_t *t2)
|
||||||
{
|
{
|
||||||
const sector_t *s1, *s2;
|
const sector_t *s1, *s2;
|
||||||
size_t pnum;
|
size_t pnum;
|
||||||
traceblocking_t tb;
|
los_t los;
|
||||||
|
los_funcs_t funcs;
|
||||||
|
|
||||||
// First check for trivial rejection.
|
// First check for trivial rejection.
|
||||||
if (!t1 || !t2)
|
if (!t1 || !t2)
|
||||||
|
|
@ -838,33 +748,35 @@ boolean P_TraceBotTraversal(mobj_t *t1, mobj_t *t2)
|
||||||
|
|
||||||
validcount++;
|
validcount++;
|
||||||
|
|
||||||
tb.strace.dx = (tb.t2x = t2->x) - (tb.strace.x = t1->x);
|
los.strace.dx = (los.t2x = t2->x) - (los.strace.x = t1->x);
|
||||||
tb.strace.dy = (tb.t2y = t2->y) - (tb.strace.y = t1->y);
|
los.strace.dy = (los.t2y = t2->y) - (los.strace.y = t1->y);
|
||||||
|
|
||||||
if (t1->x > t2->x)
|
if (t1->x > t2->x)
|
||||||
tb.bbox[BOXRIGHT] = t1->x, tb.bbox[BOXLEFT] = t2->x;
|
los.bbox[BOXRIGHT] = t1->x, los.bbox[BOXLEFT] = t2->x;
|
||||||
else
|
else
|
||||||
tb.bbox[BOXRIGHT] = t2->x, tb.bbox[BOXLEFT] = t1->x;
|
los.bbox[BOXRIGHT] = t2->x, los.bbox[BOXLEFT] = t1->x;
|
||||||
|
|
||||||
if (t1->y > t2->y)
|
if (t1->y > t2->y)
|
||||||
tb.bbox[BOXTOP] = t1->y, tb.bbox[BOXBOTTOM] = t2->y;
|
los.bbox[BOXTOP] = t1->y, los.bbox[BOXBOTTOM] = t2->y;
|
||||||
else
|
else
|
||||||
tb.bbox[BOXTOP] = t2->y, tb.bbox[BOXBOTTOM] = t1->y;
|
los.bbox[BOXTOP] = t2->y, los.bbox[BOXBOTTOM] = t1->y;
|
||||||
|
|
||||||
tb.compareThing = t1;
|
los.compareThing = t1;
|
||||||
if (t1->player != NULL)
|
if (t1->player != NULL)
|
||||||
{
|
{
|
||||||
tb.alreadyHates = K_BotHatesThisSector(
|
los.alreadyHates = K_BotHatesThisSector(
|
||||||
t1->player, t1->subsector->sector,
|
t1->player, t1->subsector->sector,
|
||||||
t1->x, t1->y
|
t1->x, t1->y
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tb.alreadyHates = false;
|
los.alreadyHates = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
funcs.validate = &P_CanBotTraverse;
|
||||||
|
|
||||||
// the head node is the last node output
|
// the head node is the last node output
|
||||||
return P_CrossBSPNodeBotTraversal((INT32)numnodes - 1, &tb);
|
return P_CrossBSPNode((INT32)numnodes - 1, &los, &funcs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue