Merge remote-tracking branch 'remotes/zdoom/master'

# Conflicts:
#	src/portal.h
#	src/r_defs.h
This commit is contained in:
Christoph Oelckers 2016-02-22 16:06:31 +01:00
commit e107d8ff48
38 changed files with 1304 additions and 704 deletions

View file

@ -40,6 +40,7 @@
#include "memarena.h"
#include "g_level.h"
#include "tflags.h"
#include "portal.h"
struct subsector_t;
class PClassAmmo;
@ -1182,24 +1183,13 @@ public:
}
fixedvec3 Pos() const
{
fixedvec3 ret = { X(), Y(), Z() };
return ret;
}
fixedvec3 PosRelative(AActor *other) const
{
fixedvec3 ret = { X(), Y(), Z() };
return ret;
}
fixedvec3 PosRelative(sector_t *sec) const
{
fixedvec3 ret = { X(), Y(), Z() };
return ret;
}
fixedvec3 PosRelative(line_t *line) const
{
fixedvec3 ret = { X(), Y(), Z() };
return ret;
return __pos;
}
fixedvec3 PosRelative(AActor *other) const;
fixedvec3 PosRelative(sector_t *sec) const;
fixedvec3 PosRelative(line_t *line) const;
fixed_t SoundX() const
{
return X();
@ -1385,11 +1375,6 @@ inline fixedvec2 Vec2Angle(fixed_t length, angle_t angle)
return ret;
}
inline fixedvec3 PosRelative(const fixedvec3 &pos, line_t *line, sector_t *refsec = NULL)
{
return pos;
}
void PrintMiscActorInfo(AActor * query);
AActor *P_LinePickActor(AActor *t1, angle_t angle, fixed_t distance, int pitch, ActorFlags actorMask, DWORD wallMask);

View file

@ -83,10 +83,12 @@ bool DBot::Move (ticcmd_t *cmd)
player->mo->movedir = DI_NODIR;
good = 0;
spechit_t spechit1;
line_t *ld;
while (spechit.Pop (ld))
while (spechit.Pop (spechit1))
{
ld = spechit1.line;
bool tryit = true;
if (ld->special == Door_LockedRaise && !P_CheckKeys (player->mo, ld->args[3], false))

View file

@ -81,16 +81,62 @@ union QWORD_UNION
typedef SDWORD fixed_t;
typedef DWORD dsfixed_t; // fixedpt used by span drawer
struct fixedvec3
{
fixed_t x, y, z;
};
struct fixedvec2
{
fixed_t x, y;
fixedvec2 &operator +=(const fixedvec2 &other)
{
x += other.x;
y += other.y;
return *this;
}
};
struct fixedvec3
{
fixed_t x, y, z;
fixedvec3 &operator +=(const fixedvec3 &other)
{
x += other.x;
y += other.y;
z += other.z;
return *this;
}
fixedvec3 &operator +=(const fixedvec2 &other)
{
x += other.x;
y += other.y;
return *this;
}
operator fixedvec2()
{
fixedvec2 ret = { x, y };
return ret;
}
};
inline fixedvec2 operator +(const fixedvec2 &v1, const fixedvec2 &v2)
{
fixedvec2 v = { v1.x + v2.x, v1.y + v2.y };
return v;
}
inline fixedvec3 operator +(const fixedvec3 &v1, const fixedvec3 &v2)
{
fixedvec3 v = { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z };
return v;
}
inline fixedvec3 operator +(const fixedvec3 &v1, const fixedvec2 &v2)
{
fixedvec3 v = { v1.x + v2.x, v1.y + v2.y, v1.z };
return v;
}
#define FIXED_MAX (signed)(0x7fffffff)
#define FIXED_MIN (signed)(0x80000000)

View file

@ -111,7 +111,7 @@ void A_PainShootSkull (AActor *self, angle_t angle, PClassActor *spawntype, int
if (!inportal) break;
// recalculate position and redo the check on the other side of the portal
pos = self->Vec3Offset(dist.x, dist.y, 8 * FRACUNIT, false);
pos = self->Vec3Offset(dist.x, dist.y, 8 * FRACUNIT);
src.x = pos.x - dist.x;
src.y = pos.y - dist.y;
@ -122,9 +122,9 @@ void A_PainShootSkull (AActor *self, angle_t angle, PClassActor *spawntype, int
// Check to see if the new Lost Soul's z value is above the
// ceiling of its new sector, or below the floor. If so, kill it.
if ((other->Z() >
(other->Sector->HighestCeiling(other) - other->height)) ||
(other->Z() < other->Sector->LowestFloor(other)))
if ((other->Top() >
(other->Sector->HighestCeilingAt(other))) ||
(other->Z() < other->Sector->LowestFloorAt(other)))
{
// kill it immediately
P_DamageMobj (other, self, self, TELEFRAG_DAMAGE, NAME_None);// ^

View file

@ -82,7 +82,7 @@ void AFastProjectile::Tick ()
if (tm.ceilingline &&
tm.ceilingline->backsector &&
tm.ceilingline->backsector->GetTexture(sector_t::ceiling) == skyflatnum &&
Z() >= tm.ceilingline->backsector->ceilingplane.ZatPoint (this))
Z() >= tm.ceilingline->backsector->ceilingplane.ZatPoint(PosRelative(tm.ceilingline)))
{
// Hack to prevent missiles exploding against the sky.
// Does not handle sky floors.

View file

@ -414,7 +414,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialPosition)
// Move item back to its original location
fixed_t _x, _y;
sector_t *sec;
_x = self->SpawnPoint[0];
_y = self->SpawnPoint[1];
@ -422,12 +421,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialPosition)
self->UnlinkFromWorld();
self->SetXY(_x, _y);
self->LinkToWorld(true);
sec = self->Sector;
self->dropoffz =
self->floorz = sec->floorplane.ZatPoint(_x, _y);
self->ceilingz = sec->ceilingplane.ZatPoint(_x, _y);
self->SetZ(self->floorz);
P_FindFloorCeiling(self, FFCF_ONLYSPAWNPOS);
self->SetZ(self->Sector->floorplane.ZatPoint(_x, _y));
P_FindFloorCeiling(self, FFCF_ONLYSPAWNPOS | FFCF_NOPORTALS); // no portal checks here so that things get spawned in this sector.
if (self->flags & MF_SPAWNCEILING)
{
@ -450,7 +445,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialPosition)
{
self->SetZ(self->SpawnPoint[2] + self->floorz);
}
// Redo floor/ceiling check, in case of 3D floors
// Redo floor/ceiling check, in case of 3D floors and portals
P_FindFloorCeiling(self, FFCF_SAMESECTOR | FFCF_ONLY3DFLOORS | FFCF_3DRESTRICT);
if (self->Z() < self->floorz)
{ // Do not reappear under the floor, even if that's where we were for the

View file

@ -659,7 +659,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain)
sector_t *sec = self->Sector;
if (self->Z() == sec->floorplane.ZatPoint(self))
if (self->Z() == sec->floorplane.ZatPoint(self) && sec->PortalBlocksMovement(sector_t::floor))
{
if (sec->special == Damage_InstantDeath)
{

View file

@ -34,7 +34,7 @@
//
//==========================================================================
FBoundingBox::FBoundingBox(fixed_t x, fixed_t y, fixed_t radius)
void FBoundingBox::setBox(fixed_t x, fixed_t y, fixed_t radius)
{
m_Box[BOXTOP] = (fixed_t)MIN<SQWORD>((SQWORD)y + radius, FIXED_MAX);
m_Box[BOXLEFT] = (fixed_t)MAX<SQWORD>((SQWORD)x - radius, FIXED_MIN);

View file

@ -43,7 +43,12 @@ public:
m_Box[BOXBOTTOM] = bottom;
}
FBoundingBox(fixed_t x, fixed_t y, fixed_t radius);
FBoundingBox(fixed_t x, fixed_t y, fixed_t radius)
{
setBox(x, y, radius);
}
void setBox(fixed_t x, fixed_t y, fixed_t radius);
void ClearBox ()
{

View file

@ -777,6 +777,8 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li
FTextureID highestfloorpic;
int highestfloorterrain = -1;
FTextureID lowestceilingpic;
sector_t *lowestceilingsec = NULL, *highestfloorsec = NULL;
secplane_t *highestfloorplanes[2] = { NULL, NULL };
highestfloorpic.SetInvalid();
lowestceilingpic.SetInvalid();
@ -800,6 +802,7 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li
{
lowestceiling = ff_bottom;
lowestceilingpic = *rover->bottom.texture;
lowestceilingsec = j == 0 ? linedef->frontsector : linedef->backsector;
}
if(ff_top > highestfloor && delta1 < delta2 && (!restrict || thing->Z() >= ff_top))
@ -807,6 +810,8 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li
highestfloor = ff_top;
highestfloorpic = *rover->top.texture;
highestfloorterrain = rover->model->GetTerrain(rover->top.isceiling);
highestfloorsec = j == 0 ? linedef->frontsector : linedef->backsector;
highestfloorplanes[j] = rover->top.plane;
}
if(ff_top > lowestfloor[j] && ff_top <= thing->Z() + thing->MaxStepHeight) lowestfloor[j] = ff_top;
}
@ -817,12 +822,24 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li
open.bottom = highestfloor;
open.floorpic = highestfloorpic;
open.floorterrain = highestfloorterrain;
open.bottomsec = highestfloorsec;
if (highestfloorplanes[0])
{
open.frontfloorplane = *highestfloorplanes[0];
if (open.frontfloorplane.c < 0) open.frontfloorplane.FlipVert();
}
if (highestfloorplanes[1])
{
open.backfloorplane = *highestfloorplanes[1];
if (open.backfloorplane.c < 0) open.backfloorplane.FlipVert();
}
}
if(lowestceiling < open.top)
{
open.top = lowestceiling;
open.ceilingpic = lowestceilingpic;
open.topsec = lowestceilingsec;
}
open.lowfloor = MIN(lowestfloor[0], lowestfloor[1]);

View file

@ -294,6 +294,8 @@ bool P_LineOpening_3dMidtex(AActor *thing, const line_t *linedef, FLineOpening &
open.abovemidtex = true;
open.floorpic = linedef->sidedef[0]->GetTexture(side_t::mid);
open.floorterrain = TerrainTypes[open.floorpic];
open.frontfloorplane.SetAtHeight(tt, sector_t::floor);
open.backfloorplane.SetAtHeight(tt, sector_t::floor);
}
// returns true if it touches the midtexture

View file

@ -76,7 +76,6 @@
#include "actorptrselect.h"
#include "farchive.h"
#include "decallib.h"
#include "portal.h"
#include "p_terrain.h"
#include "version.h"
#include "p_effect.h"
@ -4179,49 +4178,19 @@ bool DLevelScript::DoCheckActorTexture(int tid, AActor *activator, int string, b
// they're obviously not the same.
return 0;
}
int i, numff;
FTextureID secpic;
sector_t *sec = actor->Sector;
numff = sec->e->XFloor.ffloors.Size();
sector_t *resultsec;
F3DFloor *resffloor;
if (floor)
{
// Looking through planes from top to bottom
for (i = 0; i < numff; ++i)
{
F3DFloor *ff = sec->e->XFloor.ffloors[i];
if ((ff->flags & (FF_EXISTS | FF_SOLID)) == (FF_EXISTS | FF_SOLID) &&
actor->Z() >= ff->top.plane->ZatPoint(actor))
{ // This floor is beneath our feet.
secpic = *ff->top.texture;
break;
}
}
if (i == numff)
{ // Use sector's floor
secpic = sec->GetTexture(sector_t::floor);
}
actor->Sector->NextLowestFloorAt(actor, actor->Z(), 0, &resultsec, &resffloor);
secpic = resffloor ? *resffloor->top.texture : resultsec->planes[sector_t::floor].Texture;
}
else
{
fixed_t z = actor->Top();
// Looking through planes from bottom to top
for (i = numff-1; i >= 0; --i)
{
F3DFloor *ff = sec->e->XFloor.ffloors[i];
if ((ff->flags & (FF_EXISTS | FF_SOLID)) == (FF_EXISTS | FF_SOLID) &&
z <= ff->bottom.plane->ZatPoint(actor))
{ // This floor is above our eyes.
secpic = *ff->bottom.texture;
break;
}
}
if (i < 0)
{ // Use sector's ceiling
secpic = sec->GetTexture(sector_t::ceiling);
}
actor->Sector->NextHighestCeilingAt(actor, actor->Top(), 0, &resultsec, &resffloor);
secpic = resffloor ? *resffloor->bottom.texture : resultsec->planes[sector_t::ceiling].Texture;
}
return tex == TexMan[secpic];
}

View file

@ -17,7 +17,6 @@
#include "g_level.h"
#include "r_data/colormaps.h"
#include "gi.h"
#include "portal.h"
#include "p_spec.h"
// MACROS ------------------------------------------------------------------

View file

@ -2,63 +2,6 @@
#define P_CHECKPOS_H
//============================================================================
//
// This is a dynamic array which holds its first MAX_STATIC entries in normal
// variables to avoid constant allocations which this would otherwise
// require.
//
// When collecting touched portal groups the normal cases are either
// no portals == one group or
// two portals = two groups
//
// Anything with more can happen but far less infrequently, so this
// organization helps avoiding the overhead from heap allocations
// in the vast majority of situations.
//
//============================================================================
struct FPortalGroupArray
{
enum
{
MAX_STATIC = 2
};
FPortalGroupArray()
{
varused = 0;
}
void Clear()
{
data.Clear();
varused = 0;
}
void Add(DWORD num)
{
if (varused < MAX_STATIC) entry[varused++] = num;
else data.Push(num);
}
unsigned Size()
{
return varused + data.Size();
}
DWORD operator[](unsigned index)
{
return index < MAX_STATIC ? entry[index] : data[index - MAX_STATIC];
}
private:
DWORD entry[MAX_STATIC];
unsigned varused;
TArray<DWORD> data;
};
//============================================================================
//
// Used by P_CheckPosition and P_TryMove in place of the original
@ -95,7 +38,6 @@ struct FCheckPosition
bool DoRipping;
TMap<AActor*, bool> LastRipped;
FPortalGroupArray Groups;
int PushTime;
FCheckPosition(bool rip=false)

View file

@ -558,7 +558,7 @@ bool P_Move (AActor *actor)
else
{ // The monster just hit the floor, so trigger any actions.
if (actor->floorsector->SecActTarget != NULL &&
actor->floorz == actor->floorsector->floorplane.ZatPoint(actor))
actor->floorz == actor->floorsector->floorplane.ZatPoint(actor->PosRelative(actor->floorsector)))
{
actor->floorsector->SecActTarget->TriggerAction(actor, SECSPAC_HitFloor);
}
@ -612,18 +612,18 @@ bool P_Move (AActor *actor)
// Do NOT simply return false 1/4th of the time (causes monsters to
// back out when they shouldn't, and creates secondary stickiness).
line_t *ld;
spechit_t spec;
int good = 0;
if (!(actor->flags6 & MF6_NOTRIGGER))
{
while (spechit.Pop (ld))
while (spechit.Pop (spec))
{
// [RH] let monsters push lines, as well as use them
if (((actor->flags4 & MF4_CANUSEWALLS) && P_ActivateLine (ld, actor, 0, SPAC_Use)) ||
((actor->flags2 & MF2_PUSHWALL) && P_ActivateLine (ld, actor, 0, SPAC_Push)))
if (((actor->flags4 & MF4_CANUSEWALLS) && P_ActivateLine (spec.line, actor, 0, SPAC_Use)) ||
((actor->flags2 & MF2_PUSHWALL) && P_ActivateLine (spec.line, actor, 0, SPAC_Push)))
{
good |= ld == actor->BlockingLine ? 1 : 2;
good |= spec.line == actor->BlockingLine ? 1 : 2;
}
}
}
@ -868,8 +868,8 @@ void P_NewChaseDir(AActor * actor)
box.Bottom() < line->bbox[BOXTOP] &&
box.BoxOnLineSide(line) == -1)
{
fixed_t front = line->frontsector->floorplane.ZatPoint(actor);
fixed_t back = line->backsector->floorplane.ZatPoint(actor);
fixed_t front = line->frontsector->floorplane.ZatPoint(actor->PosRelative(line));
fixed_t back = line->backsector->floorplane.ZatPoint(actor->PosRelative(line));
angle_t angle;
// The monster must contact one of the two floors,

View file

@ -57,7 +57,6 @@
#include "d_net.h"
#include "d_event.h"
#include "gstrings.h"
#include "portal.h"
#include "po_man.h"
#include "d_player.h"
#include "r_utility.h"

View file

@ -240,7 +240,14 @@ AActor *P_RoughMonsterSearch (AActor *mo, int distance, bool onlyseekable=false)
// if within "tmfloorz - tmceilingz".
extern msecnode_t *sector_list; // phares 3/16/98
extern TArray<line_t *> spechit;
struct spechit_t
{
line_t *line;
fixedvec2 refpos;
};
extern TArray<spechit_t> spechit;
extern TArray<spechit_t> portalhit;
bool P_TestMobjLocation (AActor *mobj);
@ -287,6 +294,10 @@ enum
FFCF_SAMESECTOR = 2,
FFCF_ONLY3DFLOORS = 4, // includes 3D midtexes
FFCF_3DRESTRICT = 8, // ignore 3D midtexes and floors whose floorz are above thing's z
FFCF_NOPORTALS = 16, // ignore portals (considers them impassable.)
FFCF_NOFLOOR = 32,
FFCF_NOCEILING = 64,
FFCF_RESTRICTEDPORTAL = 128, // current values in the iterator's return are through a restricted portal type (i.e. some features are blocked.)
};
void P_FindFloorCeiling (AActor *actor, int flags=0);

View file

@ -63,7 +63,7 @@ CVAR(Bool, cl_bloodsplats, true, CVAR_ARCHIVE)
CVAR(Int, sv_smartaim, 0, CVAR_ARCHIVE | CVAR_SERVERINFO)
CVAR(Bool, cl_doautoaim, false, CVAR_ARCHIVE)
static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, bool windowcheck);
static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, fixedvec2 * posforwindowcheck = NULL);
static void SpawnShootDecal(AActor *t1, const FTraceResults &trace);
static void SpawnDeepSplash(AActor *t1, const FTraceResults &trace, AActor *puff,
fixed_t vx, fixed_t vy, fixed_t vz, fixed_t shootz, bool ffloor = false);
@ -75,11 +75,13 @@ static FRandom pr_crunch("DoCrunch");
// keep track of special lines as they are hit,
// but don't process them until the move is proven valid
TArray<line_t *> spechit;
TArray<spechit_t> spechit;
TArray<spechit_t> portalhit;
// Temporary holder for thing_sectorlist threads
msecnode_t* sector_list = NULL; // phares 3/16/98
//==========================================================================
//
// GetCoefficientClosestPointInLine24
@ -91,8 +93,9 @@ msecnode_t* sector_list = NULL; // phares 3/16/98
//
//==========================================================================
static fixed_t GetCoefficientClosestPointInLine24(line_t *ld, FCheckPosition &tm)
static inline fixed_t GetCoefficientClosestPointInLine24(line_t *ld, fixedvec2 pos)
{
#ifndef USE_FLOAT
// [EP] Use 64 bit integers in order to keep the exact result of the
// multiplication, because in the case the vertexes have both the
// distance coordinates equal to the map limit (32767 units, which is
@ -102,8 +105,8 @@ static fixed_t GetCoefficientClosestPointInLine24(line_t *ld, FCheckPosition &tm
// fixed_t notation, which is 1.52587890625e-05 in float notation), the
// product and the sum can be 1 in the worst case, which is very tiny.
SQWORD r_num = ((SQWORD(tm.x - ld->v1->x)*ld->dx) +
(SQWORD(tm.y - ld->v1->y)*ld->dy));
SQWORD r_num = ((SQWORD(pos.x - ld->v1->x)*ld->dx) +
(SQWORD(pos.y - ld->v1->y)*ld->dy));
// The denominator is always positive. Use this to avoid useless
// calculations.
@ -141,6 +144,48 @@ static fixed_t GetCoefficientClosestPointInLine24(line_t *ld, FCheckPosition &tm
// [EP] Having the last 24 bits all zero allows left shifting
// the numerator by 24 bits without overflow.
return (fixed_t)((r_num << 24) / r_den);
#else
double dx = ld->dx;
double dy = ld->dy;
return xs_CRoundToInt(((double)(pos.x - ld->v1->x) * dx + (double)(pos.y - ld->v1->y) * dy) / (dx*dx + dy*dy) * 16777216.f);
#endif
}
//==========================================================================
//
// FindRefPoint
//
// Finds the point on the line closest to the given coordinate
//
//==========================================================================
static inline fixedvec2 FindRefPoint(line_t *ld, fixedvec2 pos)
{
if (!((((ld->frontsector->floorplane.a | ld->frontsector->floorplane.b) |
(ld->backsector->floorplane.a | ld->backsector->floorplane.b) |
(ld->frontsector->ceilingplane.a | ld->frontsector->ceilingplane.b) |
(ld->backsector->ceilingplane.a | ld->backsector->ceilingplane.b)) == 0)
&& ld->backsector->e->XFloor.ffloors.Size() == 0 && ld->frontsector->e->XFloor.ffloors.Size() == 0))
{
fixed_t r = GetCoefficientClosestPointInLine24(ld, pos);
if (r <= 0)
{
pos.x = ld->v1->x;
pos.y = ld->v1->y;
}
else if (r >= (1 << 24))
{
pos.x = ld->v2->x;
pos.y = ld->v2->y;
}
else
{
pos.x = ld->v1->x + MulScale24(r, ld->dx);
pos.y = ld->v1->y + MulScale24(r, ld->dy);
}
}
return pos;
}
//==========================================================================
@ -150,9 +195,12 @@ static fixed_t GetCoefficientClosestPointInLine24(line_t *ld, FCheckPosition &tm
// only3d set means to only check against 3D floors and midtexes.
//
//==========================================================================
bool ffcf_verbose;
static bool PIT_FindFloorCeiling(line_t *ld, const FBoundingBox &box, FCheckPosition &tmf, int flags)
static bool PIT_FindFloorCeiling(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::CheckResult &cres, const FBoundingBox &box, FCheckPosition &tmf, int flags)
{
line_t *ld = cres.line;
if (box.Right() <= ld->bbox[BOXLEFT]
|| box.Left() >= ld->bbox[BOXRIGHT]
|| box.Top() <= ld->bbox[BOXBOTTOM]
@ -164,58 +212,44 @@ static bool PIT_FindFloorCeiling(line_t *ld, const FBoundingBox &box, FCheckPosi
// A line has been hit
if (ffcf_verbose)
{
Printf("Hit line %d at position %f,%f, group %d\n",
int(ld - lines), FIXED2FLOAT(cres.position.x), FIXED2FLOAT(cres.position.y), ld->frontsector->PortalGroup);
}
if (!ld->backsector)
{ // One sided line
return true;
}
fixed_t sx, sy;
fixedvec2 refpoint = FindRefPoint(ld, cres.position);
FLineOpening open;
// set openrange, opentop, openbottom
if ((((ld->frontsector->floorplane.a | ld->frontsector->floorplane.b) |
(ld->backsector->floorplane.a | ld->backsector->floorplane.b) |
(ld->frontsector->ceilingplane.a | ld->frontsector->ceilingplane.b) |
(ld->backsector->ceilingplane.a | ld->backsector->ceilingplane.b)) == 0)
&& ld->backsector->e->XFloor.ffloors.Size() == 0 && ld->frontsector->e->XFloor.ffloors.Size() == 0)
{
P_LineOpening(open, tmf.thing, ld, sx = tmf.x, sy = tmf.y, tmf.x, tmf.y, flags);
}
else
{ // Find the point on the line closest to the actor's center, and use
// that to calculate openings
double dx = ld->dx;
double dy = ld->dy;
fixed_t r = xs_CRoundToInt(((double)(tmf.x - ld->v1->x) * dx +
(double)(tmf.y - ld->v1->y) * dy) /
(dx*dx + dy*dy) * 16777216.f);
if (r <= 0)
{
P_LineOpening(open, tmf.thing, ld, sx = ld->v1->x, sy = ld->v1->y, tmf.x, tmf.y, flags);
}
else if (r >= (1 << 24))
{
P_LineOpening(open, tmf.thing, ld, sx = ld->v2->x, sy = ld->v2->y, tmf.thing->X(), tmf.thing->Y(), flags);
}
else
{
P_LineOpening(open, tmf.thing, ld, sx = ld->v1->x + MulScale24(r, ld->dx),
sy = ld->v1->y + MulScale24(r, ld->dy), tmf.x, tmf.y, flags);
}
}
P_LineOpening(open, tmf.thing, ld, refpoint.x, refpoint.y, cres.position.x, cres.position.y, flags);
// adjust floor / ceiling heights
if (!(flags & FFCF_NOCEILING))
{
if (open.top < tmf.ceilingz)
{
tmf.ceilingz = open.top;
if (open.topsec != NULL) tmf.floorsector = open.topsec;
if (ffcf_verbose) Printf(" Adjust ceilingz to %f\n", FIXED2FLOAT(open.top));
mit.StopUp();
}
}
if (!(flags & FFCF_NOFLOOR))
{
if (open.bottom > tmf.floorz)
{
tmf.floorz = open.bottom;
if (open.bottomsec != NULL) tmf.floorsector = open.bottomsec;
tmf.touchmidtex = open.touchmidtex;
tmf.abovemidtex = open.abovemidtex;
if (ffcf_verbose) Printf(" Adjust floorz to %f\n", FIXED2FLOAT(open.bottom));
if (tmf.floorz > tmf.dropoffz + tmf.thing->MaxDropOffHeight) mit.StopDown();
}
else if (open.bottom == tmf.floorz)
{
@ -223,63 +257,45 @@ static bool PIT_FindFloorCeiling(line_t *ld, const FBoundingBox &box, FCheckPosi
tmf.abovemidtex |= open.abovemidtex;
}
if (open.lowfloor < tmf.dropoffz)
if (open.lowfloor < tmf.dropoffz && open.lowfloor > FIXED_MIN)
{
tmf.dropoffz = open.lowfloor;
if (ffcf_verbose) Printf(" Adjust dropoffz to %f\n", FIXED2FLOAT(open.bottom));
if (tmf.floorz > tmf.dropoffz + tmf.thing->MaxDropOffHeight) mit.StopDown();
}
}
return true;
}
//==========================================================================
//
//
// calculates the actual floor and ceiling position at a given
// coordinate. Traverses through portals unless being told not to.
//
//==========================================================================
void P_GetFloorCeilingZ(FCheckPosition &tmf, int flags)
{
sector_t *sec;
if (!(flags & FFCF_ONLYSPAWNPOS))
{
sec = !(flags & FFCF_SAMESECTOR) ? P_PointInSector(tmf.x, tmf.y) : tmf.thing->Sector;
tmf.floorsector = sec;
tmf.ceilingsector = sec;
sector_t *sec = (!(flags & FFCF_SAMESECTOR) || tmf.thing->Sector == NULL)? P_PointInSector(tmf.x, tmf.y) : tmf.sector;
F3DFloor *ffc, *fff;
tmf.floorz = tmf.dropoffz = sec->floorplane.ZatPoint(tmf.x, tmf.y);
tmf.ceilingz = sec->ceilingplane.ZatPoint(tmf.x, tmf.y);
tmf.floorpic = sec->GetTexture(sector_t::floor);
tmf.floorterrain = sec->GetTerrain(sector_t::floor);
tmf.ceilingpic = sec->GetTexture(sector_t::ceiling);
tmf.ceilingz = sec->NextHighestCeilingAt(tmf.x, tmf.y, tmf.z + tmf.thing->height, flags, &tmf.ceilingsector, &ffc);
tmf.floorz = tmf.dropoffz = sec->NextLowestFloorAt(tmf.x, tmf.y, tmf.z, flags, tmf.thing->MaxStepHeight, &tmf.floorsector, &fff);
if (fff)
{
tmf.floorpic = *fff->top.texture;
tmf.floorterrain = fff->model->GetTerrain(fff->top.isceiling);
}
else
{
sec = tmf.thing->Sector;
tmf.floorpic = tmf.floorsector->GetTexture(sector_t::floor);
tmf.floorterrain = tmf.floorsector->GetTerrain(sector_t::floor);
}
tmf.ceilingpic = ffc ? *ffc->bottom.texture : tmf.ceilingsector->GetTexture(sector_t::ceiling);
tmf.sector = sec;
for (unsigned int i = 0; i<sec->e->XFloor.ffloors.Size(); i++)
{
F3DFloor* rover = sec->e->XFloor.ffloors[i];
if (!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue;
fixed_t ff_bottom = rover->bottom.plane->ZatPoint(tmf.x, tmf.y);
fixed_t ff_top = rover->top.plane->ZatPoint(tmf.x, tmf.y);
if (ff_top > tmf.floorz)
{
if (ff_top <= tmf.z || (!(flags & FFCF_3DRESTRICT) && (tmf.thing != NULL && ff_bottom < tmf.z && ff_top < tmf.z + tmf.thing->MaxStepHeight)))
{
tmf.dropoffz = tmf.floorz = ff_top;
tmf.floorpic = *rover->top.texture;
tmf.floorterrain = rover->model->GetTerrain(rover->top.isceiling);
}
}
if (ff_bottom <= tmf.ceilingz && ff_bottom > tmf.z + tmf.thing->height)
{
tmf.ceilingz = ff_bottom;
tmf.ceilingpic = *rover->bottom.texture;
}
}
}
//==========================================================================
@ -301,21 +317,13 @@ void P_FindFloorCeiling(AActor *actor, int flags)
{
flags |= FFCF_3DRESTRICT;
}
if (!(flags & FFCF_ONLYSPAWNPOS))
if (flags & FFCF_SAMESECTOR)
{
P_GetFloorCeilingZ(tmf, flags);
tmf.sector = actor->Sector;
}
else
{
tmf.ceilingsector = tmf.floorsector = actor->Sector;
P_GetFloorCeilingZ(tmf, flags);
assert(tmf.thing->Sector != NULL);
tmf.floorz = tmf.dropoffz = actor->floorz;
tmf.ceilingz = actor->ceilingz;
tmf.floorpic = actor->floorpic;
tmf.floorterrain = actor->floorterrain;
tmf.ceilingpic = actor->ceilingpic;
P_GetFloorCeilingZ(tmf, flags);
}
actor->floorz = tmf.floorz;
actor->dropoffz = tmf.dropoffz;
actor->ceilingz = tmf.ceilingz;
@ -324,47 +332,55 @@ void P_FindFloorCeiling(AActor *actor, int flags)
actor->floorsector = tmf.floorsector;
actor->ceilingpic = tmf.ceilingpic;
actor->ceilingsector = tmf.ceilingsector;
FBoundingBox box(tmf.x, tmf.y, actor->radius);
if (ffcf_verbose) Printf("Starting with ceilingz = %f, floorz = %f\n", FIXED2FLOAT(tmf.ceilingz), FIXED2FLOAT(tmf.floorz));
tmf.touchmidtex = false;
tmf.abovemidtex = false;
validcount++;
FBlockLinesIterator it(box);
line_t *ld;
FPortalGroupArray grouplist;
FMultiBlockLinesIterator mit(grouplist, actor);
FMultiBlockLinesIterator::CheckResult cres;
while ((ld = it.Next()))
// if we already have a valid floor/ceiling sector within the current sector,
// we do not need to iterate through plane portals to find a floor or ceiling.
if (actor->floorsector == actor->Sector) mit.StopDown();
if (actor->ceilingsector == actor->Sector) mit.StopUp();
while ((mit.Next(&cres)))
{
PIT_FindFloorCeiling(ld, box, tmf, flags);
PIT_FindFloorCeiling(mit, cres, mit.Box(), tmf, flags|cres.portalflags);
}
if (tmf.touchmidtex) tmf.dropoffz = tmf.floorz;
if (!(flags & FFCF_ONLYSPAWNPOS) || (tmf.abovemidtex && (tmf.floorz <= actor->Z())))
bool usetmf = !(flags & FFCF_ONLYSPAWNPOS) || (tmf.abovemidtex && (tmf.floorz <= actor->Z()));
// when actual floor or ceiling are beyond a portal plane we also need to use the result of the blockmap iterator, regardless of the flags being specified.
if (usetmf || tmf.floorsector->PortalGroup != actor->Sector->PortalGroup)
{
actor->floorz = tmf.floorz;
actor->dropoffz = tmf.dropoffz;
actor->ceilingz = tmf.ceilingz;
actor->floorpic = tmf.floorpic;
actor->floorterrain = tmf.floorterrain;
actor->floorsector = tmf.floorsector;
}
if (usetmf || tmf.ceilingsector->PortalGroup != actor->Sector->PortalGroup)
{
actor->ceilingz = tmf.ceilingz;
actor->ceilingpic = tmf.ceilingpic;
actor->ceilingsector = tmf.ceilingsector;
}
else
{
actor->floorsector = actor->ceilingsector = actor->Sector;
// [BB] Don't forget to update floorpic and ceilingpic.
if (actor->Sector != NULL)
{
actor->floorpic = actor->Sector->GetTexture(sector_t::floor);
actor->floorterrain = actor->Sector->GetTerrain(sector_t::floor);
actor->ceilingpic = actor->Sector->GetTexture(sector_t::ceiling);
}
}
}
// Debug CCMD for checking errors in the MultiBlockLinesIterator (needs to be removed when this code is complete)
CCMD(ffcf)
{
ffcf_verbose = true;
P_FindFloorCeiling(players[0].mo, 0);
ffcf_verbose = false;
}
//==========================================================================
//
// TELEPORT MOVE
@ -400,30 +416,31 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra
tmf.abovemidtex = false;
P_GetFloorCeilingZ(tmf, 0);
spechit.Clear();
bool StompAlwaysFrags = ((thing->flags2 & MF2_TELESTOMP) || (level.flags & LEVEL_MONSTERSTELEFRAG) || telefrag) && !(thing->flags7 & MF7_NOTELESTOMP);
FBoundingBox box(x, y, thing->radius);
FBlockLinesIterator it(box);
line_t *ld;
// P_LineOpening requires the thing's z to be the destination z in order to work.
fixed_t savedz = thing->Z();
thing->SetZ(z);
while ((ld = it.Next()))
FPortalGroupArray grouplist;
FMultiBlockLinesIterator mit(grouplist, x, y, z, thing->height, thing->radius);
FMultiBlockLinesIterator::CheckResult cres;
while (mit.Next(&cres))
{
PIT_FindFloorCeiling(ld, box, tmf, 0);
PIT_FindFloorCeiling(mit, cres, mit.Box(), tmf, 0);
}
thing->SetZ(savedz);
if (tmf.touchmidtex) tmf.dropoffz = tmf.floorz;
FBlockThingsIterator it2(FBoundingBox(x, y, thing->radius));
AActor *th;
FMultiBlockThingsIterator mit2(grouplist, x, y, z, thing->height, thing->radius);
FMultiBlockThingsIterator::CheckResult cres2;
while ((th = it2.Next()))
while (mit2.Next(&cres2))
{
AActor *th = cres2.thing;
if (!(th->flags & MF_SHOOTABLE))
continue;
@ -432,7 +449,7 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra
continue;
fixed_t blockdist = th->radius + tmf.thing->radius;
if (abs(th->X() - tmf.x) >= blockdist || abs(th->Y() - tmf.y) >= blockdist)
if (abs(th->X() - cres2.position.x) >= blockdist || abs(th->Y() - cres2.position.y) >= blockdist)
continue;
if ((th->flags2 | tmf.thing->flags2) & MF2_THRUACTORS)
@ -517,11 +534,14 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra
void P_PlayerStartStomp(AActor *actor, bool mononly)
{
AActor *th;
FBlockThingsIterator it(FBoundingBox(actor->X(), actor->Y(), actor->radius));
FPortalGroupArray grouplist;
FMultiBlockThingsIterator mit(grouplist, actor);
FMultiBlockThingsIterator::CheckResult cres;
while ((th = it.Next()))
while ((mit.Next(&cres)))
{
AActor *th = cres.thing;
if (!(th->flags & MF_SHOOTABLE))
continue;
@ -529,7 +549,8 @@ void P_PlayerStartStomp(AActor *actor, bool mononly)
if (th == actor || (th->player == actor->player && th->player != NULL))
continue;
if (!th->intersects(actor))
fixed_t blockdist = th->radius + actor->radius;
if (abs(th->X() - cres.position.x) >= blockdist || abs(th->Y() - cres.position.y) >= blockdist)
continue;
// only kill monsters and other players
@ -584,7 +605,7 @@ int P_GetFriction(const AActor *mo, int *frictionfactor)
int movefactor = ORIG_FRICTION_FACTOR;
fixed_t newfriction;
const msecnode_t *m;
const sector_t *sec;
sector_t *sec;
if (mo->IsNoClip2())
{
@ -627,6 +648,7 @@ int P_GetFriction(const AActor *mo, int *frictionfactor)
for (m = mo->touching_sectorlist; m; m = m->m_tnext)
{
sec = m->m_sector;
fixedvec3 pos = mo->PosRelative(sec);
// 3D floors must be checked, too
for (unsigned i = 0; i < sec->e->XFloor.ffloors.Size(); i++)
@ -637,13 +659,13 @@ int P_GetFriction(const AActor *mo, int *frictionfactor)
if (rover->flags & FF_SOLID)
{
// Must be standing on a solid floor
if (mo->Z() != rover->top.plane->ZatPoint(mo)) continue;
if (mo->Z() != rover->top.plane->ZatPoint(pos)) continue;
}
else if (rover->flags & FF_SWIMMABLE)
{
// Or on or inside a swimmable floor (e.g. in shallow water)
if (mo->Z() > rover->top.plane->ZatPoint(mo) ||
(mo->Top()) < rover->bottom.plane->ZatPoint(mo))
if (mo->Z() > rover->top.plane->ZatPoint(pos) ||
(mo->Top()) < rover->bottom.plane->ZatPoint(pos))
continue;
}
else
@ -664,9 +686,9 @@ int P_GetFriction(const AActor *mo, int *frictionfactor)
}
newfriction = secfriction(sec);
if ((newfriction < friction || friction == ORIG_FRICTION) &&
(mo->Z() <= sec->floorplane.ZatPoint(mo) ||
(mo->Z() <= sec->floorplane.ZatPoint(pos) ||
(sec->GetHeightSec() != NULL &&
mo->Z() <= sec->heightsec->floorplane.ZatPoint(mo))))
mo->Z() <= sec->heightsec->floorplane.ZatPoint(pos))))
{
friction = newfriction;
movefactor = secmovefac(sec);
@ -725,6 +747,7 @@ int P_GetMoveFactor(const AActor *mo, int *frictionp)
return movefactor;
}
//
// MOVEMENT ITERATOR FUNCTIONS
//
@ -739,8 +762,9 @@ int P_GetMoveFactor(const AActor *mo, int *frictionp)
//==========================================================================
static // killough 3/26/98: make static
bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm)
bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::CheckResult &cres, const FBoundingBox &box, FCheckPosition &tm)
{
line_t *ld = cres.line;
bool rail = false;
if (box.Right() <= ld->bbox[BOXLEFT]
@ -769,7 +793,7 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm)
P_DamageMobj(tm.thing, NULL, NULL, tm.thing->Mass >> 5, NAME_Melee);
}
tm.thing->BlockingLine = ld;
CheckForPushSpecial(ld, 0, tm.thing, false);
CheckForPushSpecial(ld, 0, tm.thing);
return false;
}
@ -782,7 +806,6 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm)
bool NotBlocked = ((tm.thing->flags3 & MF3_NOBLOCKMONST)
|| ((i_compatflags & COMPATF_NOBLOCKFRIENDS) && (tm.thing->flags & MF_FRIENDLY)));
fixedvec3 pos = tm.thing->PosRelative(ld);
if (!(Projectile) || (ld->flags & (ML_BLOCKEVERYTHING | ML_BLOCKPROJECTILE)))
{
if (ld->flags & ML_RAILING)
@ -801,91 +824,32 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm)
}
tm.thing->BlockingLine = ld;
// Calculate line side based on the actor's original position, not the new one.
CheckForPushSpecial(ld, P_PointOnLineSide(pos.x, pos.y, ld), tm.thing, false);
CheckForPushSpecial(ld, P_PointOnLineSide(cres.position.x, cres.position.y, ld), tm.thing);
return false;
}
}
// [RH] Steep sectors count as dropoffs (unless already in one)
fixedvec2 ref = FindRefPoint(ld, cres.position);
FLineOpening open;
P_LineOpening(open, tm.thing, ld, ref.x, ref.y, cres.position.x, cres.position.y, cres.portalflags);
// [RH] Steep sectors count as dropoffs, if the actor touches the boundary between a steep slope and something else
if (!(tm.thing->flags & MF_DROPOFF) &&
!(tm.thing->flags & (MF_NOGRAVITY | MF_NOCLIP)))
{
secplane_t frontplane, backplane;
// Check 3D floors as well
frontplane = P_FindFloorPlane(ld->frontsector, pos.x, pos.y, tm.thing->floorz);
backplane = P_FindFloorPlane(ld->backsector, pos.x, pos.y, tm.thing->floorz);
if (frontplane.c < STEEPSLOPE || backplane.c < STEEPSLOPE)
{
const msecnode_t *node = tm.thing->touching_sectorlist;
bool allow = false;
int count = 0;
while (node != NULL)
{
count++;
if (node->m_sector->floorplane.c < STEEPSLOPE)
{
allow = true;
break;
}
node = node->m_tnext;
}
if (!allow)
if ((open.frontfloorplane.c < STEEPSLOPE) != (open.backfloorplane.c < STEEPSLOPE))
{
// on the boundary of a steep slope
return false;
}
}
}
fixed_t sx = 0, sy = 0;
FLineOpening open;
// set openrange, opentop, openbottom
if ((((ld->frontsector->floorplane.a | ld->frontsector->floorplane.b) |
(ld->backsector->floorplane.a | ld->backsector->floorplane.b) |
(ld->frontsector->ceilingplane.a | ld->frontsector->ceilingplane.b) |
(ld->backsector->ceilingplane.a | ld->backsector->ceilingplane.b)) == 0)
&& ld->backsector->e->XFloor.ffloors.Size() == 0 && ld->frontsector->e->XFloor.ffloors.Size() == 0)
// If the floor planes on both sides match we should recalculate open.bottom at the actual position we are checking
// This is to avoid bumpy movement when crossing a linedef with the same slope on both sides.
if (open.frontfloorplane == open.backfloorplane)
{
P_LineOpening(open, tm.thing, ld, sx = tm.x, sy = tm.y, tm.x, tm.y);
}
else
{ // Find the point on the line closest to the actor's center, and use
// that to calculate openings
fixed_t r = GetCoefficientClosestPointInLine24(ld, tm);
/* Printf ("%d:%d: %d (%d %d %d %d) (%d %d %d %d)\n", level.time, ld-lines, r,
ld->frontsector->floorplane.a,
ld->frontsector->floorplane.b,
ld->frontsector->floorplane.c,
ld->frontsector->floorplane.ic,
ld->backsector->floorplane.a,
ld->backsector->floorplane.b,
ld->backsector->floorplane.c,
ld->backsector->floorplane.ic);*/
if (r <= 0)
{
P_LineOpening(open, tm.thing, ld, sx = ld->v1->x, sy = ld->v1->y, tm.x, tm.y);
}
else if (r >= (1 << 24))
{
P_LineOpening(open, tm.thing, ld, sx = ld->v2->x, sy = ld->v2->y, pos.x, pos.y);
}
else
{
P_LineOpening(open, tm.thing, ld, sx = ld->v1->x + MulScale24(r, ld->dx),
sy = ld->v1->y + MulScale24(r, ld->dy), tm.x, tm.y);
}
// the floorplane on both sides is identical with the current one
// so don't mess around with the z-position
if (ld->frontsector->floorplane == ld->backsector->floorplane &&
ld->frontsector->floorplane == tm.thing->Sector->floorplane &&
!ld->frontsector->e->XFloor.ffloors.Size() && !ld->backsector->e->XFloor.ffloors.Size() &&
!open.abovemidtex)
{
open.bottom = INT_MIN;
}
/* Printf (" %d %d %d\n", sx, sy, openbottom);*/
open.bottom = open.frontfloorplane.ZatPoint(cres.position.x, cres.position.y);
}
if (rail &&
@ -897,7 +861,7 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm)
// from either side. How long until somebody reports this as a bug and I'm
// forced to say, "It's not a bug. It's a feature?" Ugh.
(!(level.flags2 & LEVEL2_RAILINGHACK) ||
open.bottom == tm.thing->Sector->floorplane.ZatPoint(sx, sy)))
open.bottom == tm.thing->Sector->floorplane.ZatPoint(ref.x, ref.y)))
{
open.bottom += 32 * FRACUNIT;
}
@ -932,9 +896,18 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm)
tm.dropoffz = open.lowfloor;
// if contacted a special line, add it to the list
spechit_t spec;
if (ld->special)
{
spechit.Push(ld);
spec.line = ld;
spec.refpos = cres.position;
spechit.Push(spec);
}
if (ld->portalindex >= 0)
{
spec.line = ld;
spec.refpos = cres.position;
portalhit.Push(spec);
}
return true;
@ -1033,8 +1006,9 @@ static bool CanAttackHurt(AActor *victim, AActor *shooter)
//
//==========================================================================
bool PIT_CheckThing(AActor *thing, FCheckPosition &tm)
bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::CheckResult &cres, const FBoundingBox &box, FCheckPosition &tm)
{
AActor *thing = cres.thing;
fixed_t topz;
bool solid;
int damage;
@ -1046,9 +1020,8 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm)
if (!((thing->flags & (MF_SOLID | MF_SPECIAL | MF_SHOOTABLE)) || thing->flags6 & MF6_TOUCHY))
return true; // can't hit thing
fixedvec3 thingpos = thing->PosRelative(tm.thing);
fixed_t blockdist = thing->radius + tm.thing->radius;
if (abs(thingpos.x - tm.x) >= blockdist || abs(thingpos.y - tm.y) >= blockdist)
if (abs(thing->X() - cres.position.x) >= blockdist || abs(thing->Y() - cres.position.y) >= blockdist)
return true;
if ((thing->flags2 | tm.thing->flags2) & MF2_THRUACTORS)
@ -1059,6 +1032,13 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm)
tm.thing->BlockingMobj = thing;
topz = thing->Top();
// Both things overlap in x or y direction
bool unblocking = false;
// walking on other actors and unblocking is too messy through restricted portal types so disable it.
if (!(cres.portalflags & FFCF_RESTRICTEDPORTAL))
{
if (!(i_compatflags & COMPATF_NO_PASSMOBJ) && !(tm.thing->flags & (MF_FLOAT | MF_MISSILE | MF_SKULLFLY | MF_NOGRAVITY)) &&
(thing->flags & MF_SOLID) && (thing->flags4 & MF4_ACTLIKEBRIDGE))
{
@ -1080,29 +1060,27 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm)
}
}
// Both things overlap in x or y direction
bool unblocking = false;
if ((tm.FromPMove || tm.thing->player != NULL) && thing->flags&MF_SOLID)
if (((tm.FromPMove || tm.thing->player != NULL) && thing->flags&MF_SOLID))
{
fixedvec3 oldpos = tm.thing->PosRelative(thing);
// Both actors already overlap. To prevent them from remaining stuck allow the move if it
// takes them further apart or the move does not change the position (when called from P_ChangeSector.)
if (tm.x == tm.thing->X() && tm.y == tm.thing->Y())
if (oldpos.x == thing->X() && oldpos.y == thing->Y())
{
unblocking = true;
}
else if (abs(thingpos.x - tm.thing->X()) < (thing->radius+tm.thing->radius) &&
abs(thingpos.y - tm.thing->Y()) < (thing->radius+tm.thing->radius))
else if (abs(thing->X() - oldpos.x) < (thing->radius + tm.thing->radius) &&
abs(thing->Y() - oldpos.y) < (thing->radius + tm.thing->radius))
{
fixed_t newdist = thing->AproxDistance(tm.x, tm.y, tm.thing);
fixed_t olddist = thing->AproxDistance(tm.thing);
fixed_t newdist = thing->AproxDistance(cres.position.x, cres.position.y);
fixed_t olddist = thing->AproxDistance(oldpos.x, oldpos.y);
if (newdist > olddist)
{
// ... but not if they did not overlap in z-direction before but would after the move.
unblocking = !((tm.thing->Z() >= topz && tm.z < topz) ||
(tm.thing->Top() <= thingpos.z && tm.thing->Top() > thingpos.z));
// unblock only if there's already a vertical overlap (or both actors are flagged not to overlap)
unblocking = (tm.thing->Top() > thing->Z() && tm.thing->Z() < topz) || (tm.thing->flags3 & thing->flags3 & MF3_DONTOVERLAP);
}
}
}
}
@ -1136,7 +1114,7 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm)
// or different species if DONTHARMSPECIES
(!(thing->flags6 & MF6_DONTHARMSPECIES) || thing->GetSpecies() != tm.thing->GetSpecies()) &&
// touches vertically
topz >= tm.thing->Z() && tm.thing->Z() + tm.thing->height >= thingpos.z &&
topz >= tm.thing->Z() && tm.thing->Top() >= thing->Z() &&
// prevents lost souls from exploding when fired by pain elementals
(thing->master != tm.thing && tm.thing->master != thing))
// Difference with MBF: MBF hardcodes the LS/PE check and lets actors of the same species
@ -1239,11 +1217,11 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm)
}
// Check if it went over / under
if (tm.thing->Z() > thingpos.z + clipheight)
if (tm.thing->Z() > thing->Z() + clipheight)
{ // Over thing
return true;
}
if (tm.thing->Top() < thingpos.z)
if (tm.thing->Top() < thing->Z())
{ // Under thing
return true;
}
@ -1394,7 +1372,7 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm)
// [RH] The next condition is to compensate for the extra height
// that gets added by P_CheckPosition() so that you cannot pick
// up things that are above your true height.
&& thingpos.z < tm.thing->Top() - tm.thing->MaxStepHeight)
&& thing->Z() < tm.thing->Top() - tm.thing->MaxStepHeight)
{ // Can be picked up by tmthing
P_TouchSpecialThing(thing, tm.thing); // can remove thing
}
@ -1456,58 +1434,29 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo
tm.x = x;
tm.y = y;
tm.z = thing->Z();
newsec = P_PointInSector(x, y);
newsec = tm.sector = P_PointInSector(x, y);
tm.ceilingline = thing->BlockingLine = NULL;
// The base floor / ceiling is from the subsector that contains the point.
// Retrieve the base floor / ceiling from the target location.
// Any contacted lines the step closer together will adjust them.
tm.floorz = tm.dropoffz = newsec->floorplane.ZatPoint(x, y);
tm.ceilingz = newsec->ceilingplane.ZatPoint(x, y);
tm.floorpic = newsec->GetTexture(sector_t::floor);
tm.floorterrain = newsec->GetTerrain(sector_t::floor);
tm.floorsector = newsec;
tm.ceilingpic = newsec->GetTexture(sector_t::ceiling);
tm.ceilingsector = newsec;
if (!thing->IsNoClip2())
{
P_GetFloorCeilingZ(tm, FFCF_SAMESECTOR);
}
else
{
// With noclip2, we must ignore 3D floors and go right to the uppermost ceiling and lowermost floor.
tm.floorz = tm.dropoffz = newsec->LowestFloorAt(x, y, &tm.floorsector);
tm.ceilingz = newsec->HighestCeilingAt(x, y, &tm.ceilingsector);
tm.floorpic = tm.floorsector->GetTexture(sector_t::floor);
tm.floorterrain = tm.floorsector->GetTerrain(sector_t::floor);
tm.ceilingpic = tm.ceilingsector->GetTexture(sector_t::ceiling);
}
tm.touchmidtex = false;
tm.abovemidtex = false;
//Added by MC: Fill the tmsector.
tm.sector = newsec;
//Check 3D floors
if (!thing->IsNoClip2() && newsec->e->XFloor.ffloors.Size())
{
F3DFloor* rover;
fixed_t delta1;
fixed_t delta2;
int thingtop = thing->Z() + (thing->height == 0 ? 1 : thing->height);
for (unsigned i = 0; i<newsec->e->XFloor.ffloors.Size(); i++)
{
rover = newsec->e->XFloor.ffloors[i];
if (!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue;
fixed_t ff_bottom = rover->bottom.plane->ZatPoint(x, y);
fixed_t ff_top = rover->top.plane->ZatPoint(x, y);
delta1 = thing->Z() - (ff_bottom + ((ff_top - ff_bottom) / 2));
delta2 = thingtop - (ff_bottom + ((ff_top - ff_bottom) / 2));
if (ff_top > tm.floorz && abs(delta1) < abs(delta2))
{
tm.floorz = tm.dropoffz = ff_top;
tm.floorpic = *rover->top.texture;
tm.floorterrain = rover->model->GetTerrain(rover->top.isceiling);
}
if (ff_bottom < tm.ceilingz && abs(delta1) >= abs(delta2))
{
tm.ceilingz = ff_bottom;
tm.ceilingpic = *rover->bottom.texture;
}
}
}
validcount++;
spechit.Clear();
@ -1525,19 +1474,21 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo
tm.stepthing = NULL;
FBoundingBox box(x, y, thing->radius);
FPortalGroupArray pcheck;
FMultiBlockThingsIterator it2(pcheck, x, y, thing->Z(), thing->height, thing->radius);
FMultiBlockThingsIterator::CheckResult tcres;
while ((it2.Next(&tcres)))
{
FBlockThingsIterator it2(box);
AActor *th;
while ((th = it2.Next()))
{
if (!PIT_CheckThing(th, tm))
if (!PIT_CheckThing(it2, tcres, it2.Box(), tm))
{ // [RH] If a thing can be stepped up on, we need to continue checking
// other things in the blocks and see if we hit something that is
// definitely blocking. Otherwise, we need to check the lines, or we
// could end up stuck inside a wall.
AActor *BlockingMobj = thing->BlockingMobj;
if (BlockingMobj == NULL || (i_compatflags & COMPATF_NO_PASSMOBJ))
// If this blocks through a restricted line portal, it will always completely block.
if (BlockingMobj == NULL || (i_compatflags & COMPATF_NO_PASSMOBJ) || (tcres.portalflags & FFCF_RESTRICTEDPORTAL))
{ // Thing slammed into something; don't let it move now.
thing->height = realheight;
return false;
@ -1572,7 +1523,6 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo
}
}
}
}
// check lines
@ -1592,8 +1542,8 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo
if (actorsonly || (thing->flags & MF_NOCLIP))
return (thing->BlockingMobj = thingblocker) == NULL;
FBlockLinesIterator it(box);
line_t *ld;
FMultiBlockLinesIterator it(pcheck, x, y, thing->Z(), thing->height, thing->radius);
FMultiBlockLinesIterator::CheckResult lcres;
fixed_t thingdropoffz = tm.floorz;
//bool onthing = (thingdropoffz != tmdropoffz);
@ -1601,9 +1551,9 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo
bool good = true;
while ((ld = it.Next()))
while (it.Next(&lcres))
{
good &= PIT_CheckLine(ld, box, tm);
good &= PIT_CheckLine(it, lcres, it.Box(), tm);
}
if (!good)
{
@ -1696,12 +1646,16 @@ bool P_TestMobjZ(AActor *actor, bool quick, AActor **pOnmobj)
return true;
}
FBlockThingsIterator it(FBoundingBox(actor->X(), actor->Y(), actor->radius));
AActor *thing;
FPortalGroupArray check;
FMultiBlockThingsIterator it(check, actor, -1, true);
FMultiBlockThingsIterator::CheckResult cres;
while ((thing = it.Next()))
while (it.Next(&cres))
{
if (!thing->intersects(actor))
AActor *thing = cres.thing;
fixed_t blockdist = thing->radius + actor->radius;
if (abs(thing->X() - cres.position.x) >= blockdist || abs(thing->Y() - cres.position.y) >= blockdist)
{
continue;
}
@ -1808,17 +1762,18 @@ void P_FakeZMovement(AActor *mo)
//
//===========================================================================
static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, bool windowcheck)
static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, fixedvec2 *posforwindowcheck)
{
if (line->special && !(mobj->flags6 & MF6_NOTRIGGER))
{
if (windowcheck && !(ib_compatflags & BCOMPATF_NOWINDOWCHECK) && line->backsector != NULL)
if (posforwindowcheck && !(ib_compatflags & BCOMPATF_NOWINDOWCHECK) && line->backsector != NULL)
{ // Make sure this line actually blocks us and is not a window
// or similar construct we are standing inside of.
fixed_t fzt = line->frontsector->ceilingplane.ZatPoint(mobj);
fixed_t fzb = line->frontsector->floorplane.ZatPoint(mobj);
fixed_t bzt = line->backsector->ceilingplane.ZatPoint(mobj);
fixed_t bzb = line->backsector->floorplane.ZatPoint(mobj);
fixedvec3 pos = mobj->PosRelative(line);
fixed_t fzt = line->frontsector->ceilingplane.ZatPoint(*posforwindowcheck);
fixed_t fzb = line->frontsector->floorplane.ZatPoint(*posforwindowcheck);
fixed_t bzt = line->backsector->ceilingplane.ZatPoint(*posforwindowcheck);
fixed_t bzb = line->backsector->floorplane.ZatPoint(*posforwindowcheck);
if (fzt >= mobj->Top() && bzt >= mobj->Top() &&
fzb <= mobj->Z() && bzb <= mobj->Z())
{
@ -1829,8 +1784,8 @@ static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, bool windo
if (!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue;
fixed_t ff_bottom = rover->bottom.plane->ZatPoint(mobj);
fixed_t ff_top = rover->top.plane->ZatPoint(mobj);
fixed_t ff_bottom = rover->bottom.plane->ZatPoint(*posforwindowcheck);
fixed_t ff_top = rover->top.plane->ZatPoint(*posforwindowcheck);
if (ff_bottom < mobj->Top() && ff_top > mobj->Z())
{
@ -1880,7 +1835,6 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y,
fixed_t oldz;
int side;
int oldside;
line_t* ld;
sector_t* oldsec = thing->Sector; // [RH] for sector actions
sector_t* newsec;
@ -2135,12 +2089,13 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y,
// if any special lines were hit, do the effect
if (!(thing->flags & (MF_TELEPORT | MF_NOCLIP)))
{
while (spechit.Pop(ld))
spechit_t spec;
while (spechit.Pop(spec))
{
fixedvec3 thingpos = thing->PosRelative(ld);
line_t *ld = spec.line;
fixedvec3 oldrelpos = PosRelative(oldpos, ld, oldsector);
// see if the line was crossed
side = P_PointOnLineSide(thingpos.x, thingpos.y, ld);
side = P_PointOnLineSide(spec.refpos.x, spec.refpos.y, ld);
oldside = P_PointOnLineSide(oldrelpos.x, oldrelpos.y, ld);
if (side != oldside && ld->special && !(thing->flags6 & MF6_NOTRIGGER))
{
@ -2239,10 +2194,9 @@ pushline:
while (numSpecHitTemp > 0)
{
// see which lines were pushed
ld = spechit[--numSpecHitTemp];
fixedvec3 pos = thing->PosRelative(ld);
side = P_PointOnLineSide(pos.x, pos.y, ld);
CheckForPushSpecial(ld, side, thing, true);
spechit_t &spec = spechit[--numSpecHitTemp];
side = P_PointOnLineSide(spec.refpos.x, spec.refpos.y, spec.line);
CheckForPushSpecial(spec.line, side, thing, &spec.refpos);
}
}
return false;
@ -2760,15 +2714,16 @@ const secplane_t * P_CheckSlopeWalk(AActor *actor, fixed_t &xmove, fixed_t &ymov
return NULL;
}
fixedvec3 pos = actor->PosRelative(actor->floorsector);
const secplane_t *plane = &actor->floorsector->floorplane;
fixed_t planezhere = plane->ZatPoint(actor);
fixed_t planezhere = plane->ZatPoint(pos);
for (unsigned int i = 0; i<actor->floorsector->e->XFloor.ffloors.Size(); i++)
{
F3DFloor * rover = actor->floorsector->e->XFloor.ffloors[i];
if (!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue;
fixed_t thisplanez = rover->top.plane->ZatPoint(actor);
fixed_t thisplanez = rover->top.plane->ZatPoint(pos);
if (thisplanez>planezhere && thisplanez <= actor->Z() + actor->MaxStepHeight)
{
@ -2836,10 +2791,14 @@ const secplane_t * P_CheckSlopeWalk(AActor *actor, fixed_t &xmove, fixed_t &ymov
{
for (node = actor->touching_sectorlist; node; node = node->m_tnext)
{
const sector_t *sec = node->m_sector;
sector_t *sec = node->m_sector;
if (sec->floorplane.c >= STEEPSLOPE)
{
if (sec->floorplane.ZatPoint(destx, desty) >= actor->Z() - actor->MaxStepHeight)
fixedvec3 pos = actor->PosRelative(sec);
pos.x += xmove;
pos.y += ymove;
if (sec->floorplane.ZatPoint(pos) >= actor->Z() - actor->MaxStepHeight)
{
dopush = false;
break;

View file

@ -162,10 +162,28 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef,
front = linedef->frontsector;
back = linedef->backsector;
if (!(flags & FFCF_NOPORTALS) && !linedef->frontsector->PortalBlocksMovement(sector_t::ceiling) &&
linedef->backsector->SkyBoxes[sector_t::ceiling] &&
linedef->frontsector->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup == linedef->backsector->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup)
{
fc = bc = FIXED_MAX;
}
else
{
fc = front->ceilingplane.ZatPoint(x, y);
ff = front->floorplane.ZatPoint (x, y);
bc = back->ceilingplane.ZatPoint(x, y);
}
if (!(flags & FFCF_NOPORTALS) && !linedef->frontsector->PortalBlocksMovement(sector_t::floor) &&
linedef->backsector->SkyBoxes[sector_t::floor] &&
linedef->frontsector->SkyBoxes[sector_t::floor]->Sector->PortalGroup == linedef->backsector->SkyBoxes[sector_t::floor]->Sector->PortalGroup)
{
ff = bf = FIXED_MIN;
}
else
{
ff = front->floorplane.ZatPoint(x, y);
bf = back->floorplane.ZatPoint(x, y);
}
/*Printf ("]]]]]] %d %d\n", ff, bf);*/
@ -211,6 +229,8 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef,
open.floorterrain = back->GetTerrain(sector_t::floor);
open.lowfloor = ff;
}
open.frontfloorplane = front->floorplane;
open.backfloorplane = back->floorplane;
}
else
{ // Dummy stuff to have some sort of opening for the 3D checks to modify
@ -222,6 +242,8 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef,
open.floorterrain = -1;
open.bottom = FIXED_MIN;
open.lowfloor = FIXED_MAX;
open.frontfloorplane.SetAtHeight(FIXED_MIN, sector_t::floor);
open.backfloorplane.SetAtHeight(FIXED_MIN, sector_t::floor);
}
// Check 3D floors
@ -513,11 +535,15 @@ void AActor::SetOrigin (fixed_t ix, fixed_t iy, fixed_t iz, bool moving)
SetXYZ(ix, iy, iz);
if (moving) SetMovement(ix - X(), iy - Y(), iz - Z());
LinkToWorld ();
floorz = Sector->floorplane.ZatPoint (ix, iy);
ceilingz = Sector->ceilingplane.ZatPoint (ix, iy);
P_FindFloorCeiling(this, FFCF_ONLYSPAWNPOS);
}
//===========================================================================
//
// FBlockNode - allows to link actors into multiple blocks in the blockmap
//
//===========================================================================
FBlockNode *FBlockNode::FreeBlocks = NULL;
FBlockNode *FBlockNode::Create (AActor *who, int x, int y, int group)
@ -574,7 +600,7 @@ FBlockLinesIterator::FBlockLinesIterator(int _minx, int _miny, int _maxx, int _m
Reset();
}
FBlockLinesIterator::FBlockLinesIterator(const FBoundingBox &box)
void FBlockLinesIterator::init(const FBoundingBox &box)
{
validcount++;
maxy = GetSafeBlockY(box.Top() - bmaporgy);
@ -584,6 +610,10 @@ FBlockLinesIterator::FBlockLinesIterator(const FBoundingBox &box)
Reset();
}
FBlockLinesIterator::FBlockLinesIterator(const FBoundingBox &box)
{
init(box);
}
//===========================================================================
//
@ -683,6 +713,169 @@ line_t *FBlockLinesIterator::Next()
}
}
//===========================================================================
//
// FMultiBlockLinesIterator :: FMultiBlockLinesIterator
//
// An iterator that can check multiple portal groups.
//
//===========================================================================
FMultiBlockLinesIterator::FMultiBlockLinesIterator(FPortalGroupArray &check, AActor *origin, fixed_t checkradius)
: checklist(check)
{
checkpoint = origin->Pos();
if (!check.inited) P_CollectConnectedGroups(origin->Sector->PortalGroup, checkpoint, origin->Top(), checkradius, checklist);
checkpoint.z = checkradius == -1? origin->radius : checkradius;
basegroup = origin->Sector->PortalGroup;
Reset();
}
FMultiBlockLinesIterator::FMultiBlockLinesIterator(FPortalGroupArray &check, fixed_t checkx, fixed_t checky, fixed_t checkz, fixed_t checkh, fixed_t checkradius)
: checklist(check)
{
checkpoint.x = checkx;
checkpoint.y = checky;
checkpoint.z = checkz;
basegroup = P_PointInSector(checkx, checky)->PortalGroup;
if (!check.inited) P_CollectConnectedGroups(basegroup, checkpoint, checkz + checkh, checkradius, checklist);
checkpoint.z = checkradius;
Reset();
}
//===========================================================================
//
// Go up a ceiling portal
//
//===========================================================================
bool FMultiBlockLinesIterator::GoUp(fixed_t x, fixed_t y)
{
if (continueup)
{
sector_t *sector = P_PointInSector(x, y);
if (!sector->PortalBlocksMovement(sector_t::ceiling))
{
startIteratorForGroup(sector->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup);
portalflags = FFCF_NOFLOOR;
return true;
}
else continueup = false;
}
return false;
}
//===========================================================================
//
// Go down a floor portal
//
//===========================================================================
bool FMultiBlockLinesIterator::GoDown(fixed_t x, fixed_t y)
{
if (continuedown)
{
sector_t *sector = P_PointInSector(x, y);
if (!sector->PortalBlocksMovement(sector_t::floor))
{
startIteratorForGroup(sector->SkyBoxes[sector_t::floor]->Sector->PortalGroup);
portalflags = FFCF_NOCEILING;
return true;
}
else continuedown = false;
}
return false;
}
//===========================================================================
//
// Gets the next line - also manages switching between portal groups
//
//===========================================================================
bool FMultiBlockLinesIterator::Next(FMultiBlockLinesIterator::CheckResult *item)
{
line_t *line = blockIterator.Next();
if (line != NULL)
{
item->line = line;
item->position.x = offset.x;
item->position.y = offset.y;
item->portalflags = portalflags;
return true;
}
bool onlast = unsigned(index + 1) >= checklist.Size();
int nextflags = onlast ? 0 : checklist[index + 1] & FPortalGroupArray::FLAT;
if (portalflags == FFCF_NOFLOOR && nextflags != FPortalGroupArray::UPPER)
{
// if this is the last upper portal in the list, check if we need to go further up to find the real ceiling.
if (GoUp(offset.x, offset.y)) return Next(item);
}
else if (portalflags == FFCF_NOCEILING && nextflags != FPortalGroupArray::LOWER)
{
// if this is the last lower portal in the list, check if we need to go further down to find the real floor.
if (GoDown(offset.x, offset.y)) return Next(item);
}
if (onlast)
{
// We reached the end of the list. Check if we still need to check up- and downwards.
if (GoUp(checkpoint.x, checkpoint.y) ||
GoDown(checkpoint.x, checkpoint.y))
{
return Next(item);
}
return false;
}
index++;
startIteratorForGroup(checklist[index] & ~FPortalGroupArray::FLAT);
switch (nextflags)
{
case FPortalGroupArray::UPPER:
portalflags = FFCF_NOFLOOR;
break;
case FPortalGroupArray::LOWER:
portalflags = FFCF_NOCEILING;
break;
default:
portalflags = 0;
}
return Next(item);
}
//===========================================================================
//
// start iterating a new group
//
//===========================================================================
void FMultiBlockLinesIterator::startIteratorForGroup(int group)
{
offset = Displacements(basegroup, group);
offset.x += checkpoint.x;
offset.y += checkpoint.y;
bbox.setBox(offset.x, offset.y, checkpoint.z);
blockIterator.init(bbox);
}
//===========================================================================
//
// Resets the iterator
//
//===========================================================================
void FMultiBlockLinesIterator::Reset()
{
continueup = continueup = true;
index = -1;
portalflags = 0;
startIteratorForGroup(basegroup);
}
//===========================================================================
//
// FBlockThingsIterator :: FBlockThingsIterator
@ -709,8 +902,7 @@ FBlockThingsIterator::FBlockThingsIterator(int _minx, int _miny, int _maxx, int
Reset();
}
FBlockThingsIterator::FBlockThingsIterator(const FBoundingBox &box)
: DynHash(0)
void FBlockThingsIterator::init(const FBoundingBox &box)
{
maxy = GetSafeBlockY(box.Top() - bmaporgy);
miny = GetSafeBlockY(box.Bottom() - bmaporgy);
@ -852,6 +1044,108 @@ AActor *FBlockThingsIterator::Next(bool centeronly)
}
//===========================================================================
//
// FMultiBlockThingsIterator :: FMultiBlockThingsIterator
//
// An iterator that can check multiple portal groups.
//
//===========================================================================
FMultiBlockThingsIterator::FMultiBlockThingsIterator(FPortalGroupArray &check, AActor *origin, fixed_t checkradius, bool ignorerestricted)
: checklist(check)
{
checkpoint = origin->Pos();
if (!check.inited) P_CollectConnectedGroups(origin->Sector->PortalGroup, checkpoint, origin->Top(), checkradius, checklist);
checkpoint.z = checkradius == -1? origin->radius : checkradius;
basegroup = origin->Sector->PortalGroup;
Reset();
}
FMultiBlockThingsIterator::FMultiBlockThingsIterator(FPortalGroupArray &check, fixed_t checkx, fixed_t checky, fixed_t checkz, fixed_t checkh, fixed_t checkradius, bool ignorerestricted)
: checklist(check)
{
checkpoint.x = checkx;
checkpoint.y = checky;
checkpoint.z = checkz;
basegroup = P_PointInSector(checkx, checky)->PortalGroup;
if (!check.inited) P_CollectConnectedGroups(basegroup, checkpoint, checkz + checkh, checkradius, checklist);
checkpoint.z = checkradius;
Reset();
}
//===========================================================================
//
// Gets the next line - also manages switching between portal groups
//
//===========================================================================
bool FMultiBlockThingsIterator::Next(FMultiBlockThingsIterator::CheckResult *item)
{
AActor *thing = blockIterator.Next();
if (thing != NULL)
{
item->thing = thing;
item->position = checkpoint + Displacements(basegroup, thing->Sector->PortalGroup);
item->portalflags = portalflags;
return true;
}
bool onlast = unsigned(index + 1) >= checklist.Size();
int nextflags = onlast ? 0 : checklist[index + 1] & FPortalGroupArray::FLAT;
if (onlast)
{
return false;
}
index++;
startIteratorForGroup(checklist[index] & ~FPortalGroupArray::FLAT);
switch (nextflags)
{
case FPortalGroupArray::UPPER:
portalflags = FFCF_NOFLOOR;
break;
case FPortalGroupArray::LOWER:
portalflags = FFCF_NOCEILING;
break;
default:
portalflags = 0;
}
return Next(item);
}
//===========================================================================
//
// start iterating a new group
//
//===========================================================================
void FMultiBlockThingsIterator::startIteratorForGroup(int group)
{
fixedvec2 offset = Displacements(basegroup, group);
offset.x += checkpoint.x;
offset.y += checkpoint.y;
bbox.setBox(offset.x, offset.y, checkpoint.z);
blockIterator.init(bbox);
}
//===========================================================================
//
// Resets the iterator
//
//===========================================================================
void FMultiBlockThingsIterator::Reset()
{
index = -1;
portalflags = 0;
startIteratorForGroup(basegroup);
}
//===========================================================================
//
// FPathTraverse :: Intercepts

View file

@ -3,6 +3,7 @@
#include "r_defs.h"
#include "doomstat.h"
#include "m_bbox.h"
extern int validcount;
@ -98,6 +99,8 @@ struct FLineOpening
sector_t *topsec;
FTextureID ceilingpic;
FTextureID floorpic;
secplane_t frontfloorplane;
secplane_t backfloorplane;
int floorterrain;
bool touchmidtex;
bool abovemidtex;
@ -108,8 +111,76 @@ void P_LineOpening (FLineOpening &open, AActor *thing, const line_t *linedef, fi
class FBoundingBox;
struct polyblock_t;
//============================================================================
//
// This is a dynamic array which holds its first MAX_STATIC entries in normal
// variables to avoid constant allocations which this would otherwise
// require.
//
// When collecting touched portal groups the normal cases are either
// no portals == one group or
// two portals = two groups
//
// Anything with more can happen but far less infrequently, so this
// organization helps avoiding the overhead from heap allocations
// in the vast majority of situations.
//
//============================================================================
struct FPortalGroupArray
{
enum
{
LOWER = 0x4000,
UPPER = 0x8000,
FLAT = 0xc000,
};
enum
{
MAX_STATIC = 4
};
FPortalGroupArray()
{
varused = 0;
inited = false;
}
void Clear()
{
data.Clear();
varused = 0;
inited = false;
}
void Add(DWORD num)
{
if (varused < MAX_STATIC) entry[varused++] = (WORD)num;
else data.Push((WORD)num);
}
unsigned Size()
{
return varused + data.Size();
}
DWORD operator[](unsigned index)
{
return index < MAX_STATIC ? entry[index] : data[index - MAX_STATIC];
}
bool inited;
private:
WORD entry[MAX_STATIC];
BYTE varused;
TArray<WORD> data;
};
class FBlockLinesIterator
{
friend class FMultiBlockLinesIterator;
int minx, maxx;
int miny, maxy;
@ -120,6 +191,8 @@ class FBlockLinesIterator
void StartBlock(int x, int y);
FBlockLinesIterator() {}
void init(const FBoundingBox &box);
public:
FBlockLinesIterator(int minx, int miny, int maxx, int maxy, bool keepvalidcount = false);
FBlockLinesIterator(const FBoundingBox &box);
@ -127,6 +200,52 @@ public:
void Reset() { StartBlock(minx, miny); }
};
class FMultiBlockLinesIterator
{
FPortalGroupArray &checklist;
fixedvec3 checkpoint;
fixedvec2 offset;
short basegroup;
short portalflags;
short index;
bool continueup;
bool continuedown;
FBlockLinesIterator blockIterator;
FBoundingBox bbox;
bool GoUp(fixed_t x, fixed_t y);
bool GoDown(fixed_t x, fixed_t y);
void startIteratorForGroup(int group);
public:
struct CheckResult
{
line_t *line;
fixedvec3 position;
int portalflags;
};
FMultiBlockLinesIterator(FPortalGroupArray &check, AActor *origin, fixed_t checkradius = -1);
FMultiBlockLinesIterator(FPortalGroupArray &check, fixed_t checkx, fixed_t checky, fixed_t checkz, fixed_t checkh, fixed_t checkradius);
bool Next(CheckResult *item);
void Reset();
// for stopping group traversal through portals. Only the calling code can decide whether this is needed so this needs to be set from the outside.
void StopUp()
{
continueup = false;
}
void StopDown()
{
continuedown = false;
}
const FBoundingBox &Box() const
{
return bbox;
}
};
class FBlockThingsIterator
{
int minx, maxx;
@ -158,14 +277,52 @@ class FBlockThingsIterator
FBlockThingsIterator();
friend class FPathTraverse;
friend class FMultiBlockThingsIterator;
public:
FBlockThingsIterator(int minx, int miny, int maxx, int maxy);
FBlockThingsIterator(const FBoundingBox &box);
FBlockThingsIterator(const FBoundingBox &box)
{
init(box);
}
void init(const FBoundingBox &box);
AActor *Next(bool centeronly = false);
void Reset() { StartBlock(minx, miny); }
};
class FMultiBlockThingsIterator
{
FPortalGroupArray &checklist;
fixedvec3 checkpoint;
short basegroup;
short portalflags;
short index;
FBlockThingsIterator blockIterator;
FBoundingBox bbox;
void startIteratorForGroup(int group);
public:
struct CheckResult
{
AActor *thing;
fixedvec3 position;
int portalflags;
};
FMultiBlockThingsIterator(FPortalGroupArray &check, AActor *origin, fixed_t checkradius = -1, bool ignorerestricted = false);
FMultiBlockThingsIterator(FPortalGroupArray &check, fixed_t checkx, fixed_t checky, fixed_t checkz, fixed_t checkh, fixed_t checkradius, bool ignorerestricted = false);
bool Next(CheckResult *item);
void Reset();
const FBoundingBox &Box() const
{
return bbox;
}
};
class FPathTraverse
{
static TArray<intercept_t> intercepts;

View file

@ -2187,7 +2187,7 @@ explode:
if (tm.ceilingline &&
tm.ceilingline->backsector &&
tm.ceilingline->backsector->GetTexture(sector_t::ceiling) == skyflatnum &&
mo->Z() >= tm.ceilingline->backsector->ceilingplane.ZatPoint(mo))
mo->Z() >= tm.ceilingline->backsector->ceilingplane.ZatPoint(mo->PosRelative(tm.ceilingline)))
{
// Hack to prevent missiles exploding against the sky.
// Does not handle sky floors.
@ -3559,7 +3559,7 @@ void AActor::Tick ()
for (node = touching_sectorlist; node; node = node->m_tnext)
{
const sector_t *sec = node->m_sector;
sector_t *sec = node->m_sector;
fixed_t scrollx, scrolly;
if (level.Scrolls != NULL)
@ -3641,7 +3641,8 @@ void AActor::Tick ()
{
continue;
}
height = sec->floorplane.ZatPoint (this);
fixedvec3 pos = PosRelative(sec);
height = sec->floorplane.ZatPoint (pos);
if (Z() > height)
{
if (heightsec == NULL)
@ -3649,7 +3650,7 @@ void AActor::Tick ()
continue;
}
waterheight = heightsec->floorplane.ZatPoint (this);
waterheight = heightsec->floorplane.ZatPoint (pos);
if (waterheight > height && Z() >= waterheight)
{
continue;
@ -3690,7 +3691,7 @@ void AActor::Tick ()
floorplane = P_FindFloorPlane(floorsector, X(), Y(), floorz);
if (floorplane.c < STEEPSLOPE &&
floorplane.ZatPoint (this) <= floorz)
floorplane.ZatPoint (PosRelative(floorsector)) <= floorz)
{
const msecnode_t *node;
bool dopush = true;
@ -3702,7 +3703,7 @@ void AActor::Tick ()
const sector_t *sec = node->m_sector;
if (sec->floorplane.c >= STEEPSLOPE)
{
if (floorplane.ZatPoint (this) >= Z() - MaxStepHeight)
if (floorplane.ZatPoint (PosRelative(node->m_sector)) >= Z() - MaxStepHeight)
{
dopush = false;
break;
@ -4485,8 +4486,9 @@ void AActor::AdjustFloorClip ()
// do the floorclipping instead of the terrain type.
for (m = touching_sectorlist; m; m = m->m_tnext)
{
fixedvec3 pos = PosRelative(m->m_sector);
sector_t *hsec = m->m_sector->GetHeightSec();
if (hsec == NULL && m->m_sector->floorplane.ZatPoint (this) == Z())
if (hsec == NULL && m->m_sector->floorplane.ZatPoint (pos) == Z())
{
fixed_t clip = Terrains[m->m_sector->GetTerrain(sector_t::floor)].FootClip;
if (clip < shallowestclip)
@ -5356,7 +5358,7 @@ void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator)
}
if (bloodtype >= 1)
{
P_DrawSplash2 (40, x, y, z, R_PointToAngle2 (x, y, originator->X(), originator->Y()), 2, bloodcolor);
P_DrawSplash2 (40, x, y, z, 0u - originator->AngleTo(x, y), 2, bloodcolor);
}
}
@ -5396,7 +5398,7 @@ void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator)
}
if (bloodtype >= 1)
{
P_DrawSplash2 (100, x, y, z, R_PointToAngle2 (0, 0, originator->X() - x, originator->Y() - y), 2, bloodcolor);
P_DrawSplash2 (100, x, y, z, 0u - originator->AngleTo(x, y), 2, bloodcolor);
}
}
@ -5639,9 +5641,11 @@ bool P_HitFloor (AActor *thing)
return false;
// don't splash if landing on the edge above water/lava/etc....
fixedvec3 pos;
for (m = thing->touching_sectorlist; m; m = m->m_tnext)
{
if (thing->Z() == m->m_sector->floorplane.ZatPoint(thing))
pos = thing->PosRelative(m->m_sector);
if (thing->Z() == m->m_sector->floorplane.ZatPoint(pos.x, pos.y))
{
break;
}
@ -5653,9 +5657,9 @@ bool P_HitFloor (AActor *thing)
if (!(rover->flags & FF_EXISTS)) continue;
if (rover->flags & (FF_SOLID|FF_SWIMMABLE))
{
if (rover->top.plane->ZatPoint(thing) == thing->Z())
if (rover->top.plane->ZatPoint(pos.x, pos.y) == thing->Z())
{
return P_HitWater (thing, m->m_sector);
return P_HitWater (thing, m->m_sector, pos.x, pos.y, pos.z);
}
}
}
@ -5665,7 +5669,7 @@ bool P_HitFloor (AActor *thing)
return false;
}
return P_HitWater (thing, m->m_sector);
return P_HitWater (thing, m->m_sector, pos.x, pos.y, pos.z);
}
//---------------------------------------------------------------------------
@ -5678,12 +5682,15 @@ bool P_HitFloor (AActor *thing)
void P_CheckSplash(AActor *self, fixed_t distance)
{
if (self->Z() <= self->floorz + (distance<<FRACBITS) && self->floorsector == self->Sector && self->Sector->GetHeightSec() == NULL)
sector_t *floorsec;
self->Sector->LowestFloorAt(self, &floorsec);
if (self->Z() <= self->floorz + (distance<<FRACBITS) && self->floorsector == floorsec && self->Sector->GetHeightSec() == NULL && floorsec->heightsec == NULL)
{
// Explosion splashes never alert monsters. This is because A_Explode has
// a separate parameter for that so this would get in the way of proper
// behavior.
P_HitWater (self, self->Sector, self->X(), self->Y(), self->floorz, false, false);
fixedvec3 pos = self->PosRelative(floorsec);
P_HitWater (self, floorsec, pos.x, pos.y, self->floorz, false, false);
}
}

View file

@ -55,7 +55,6 @@
#include "p_lnspec.h"
#include "p_acs.h"
#include "p_terrain.h"
#include "portal.h"
static void CopyPlayer (player_t *dst, player_t *src, const char *name);
static void ReadOnePlayer (FArchive &arc, bool skipload);

View file

@ -31,6 +31,7 @@
#include "farchive.h"
#include "r_utility.h"
#include "a_sharedglobal.h"
#include "p_local.h"
#include "r_data/colormaps.h"
@ -805,7 +806,7 @@ int sector_t::GetCeilingLight () const
ASkyViewpoint *sector_t::GetSkyBox(int which)
{
if (SkyBoxes[which] != NULL) return SkyBoxes[which];
if (SkyBoxes[which] != NULL) return barrier_cast<ASkyViewpoint*>(SkyBoxes[which]);
if (MoreFlags & (SECF_NOFLOORSKYBOX << which)) return NULL;
return level.DefaultSkybox;
}
@ -873,7 +874,7 @@ int sector_t::GetTerrain(int pos) const
void sector_t::CheckPortalPlane(int plane)
{
ASkyViewpoint *portal = SkyBoxes[plane];
AActor *portal = SkyBoxes[plane];
if (!portal || portal->special1 != SKYBOX_LINKEDPORTAL) return;
fixed_t planeh = planes[plane].TexZ;
@ -882,7 +883,140 @@ void sector_t::CheckPortalPlane(int plane)
planes[plane].Flags = (planes[plane].Flags & ~PLANEF_OBSTRUCTED) | obstructed;
}
//===========================================================================
//
// Finds the highest ceiling at the given position, all portals considered
//
//===========================================================================
fixed_t sector_t::HighestCeilingAt(fixed_t x, fixed_t y, sector_t **resultsec)
{
sector_t *check = this;
fixed_t planeheight = FIXED_MIN;
// Continue until we find a blocking portal or a portal below where we actually are.
while (!check->PortalBlocksMovement(ceiling) && planeheight < check->SkyBoxes[ceiling]->threshold)
{
FDisplacement &disp = check->CeilingDisplacement();
x += disp.pos.x;
y += disp.pos.y;
planeheight = check->SkyBoxes[ceiling]->threshold;
check = P_PointInSector(x, y);
}
if (resultsec) *resultsec = check;
return check->ceilingplane.ZatPoint(x, y);
}
//===========================================================================
//
// Finds the lowest floor at the given position, all portals considered
//
//===========================================================================
fixed_t sector_t::LowestFloorAt(fixed_t x, fixed_t y, sector_t **resultsec)
{
sector_t *check = this;
fixed_t planeheight = FIXED_MAX;
// Continue until we find a blocking portal or a portal above where we actually are.
while (!check->PortalBlocksMovement(floor) && planeheight > check->SkyBoxes[floor]->threshold)
{
FDisplacement &disp = check->FloorDisplacement();
x += disp.pos.x;
y += disp.pos.y;
planeheight = check->SkyBoxes[floor]->threshold;
check = P_PointInSector(x, y);
}
if (resultsec) *resultsec = check;
return check->floorplane.ZatPoint(x, y);
}
fixed_t sector_t::NextHighestCeilingAt(fixed_t x, fixed_t y, fixed_t z, int flags, sector_t **resultsec, F3DFloor **resultffloor)
{
sector_t *sec = this;
fixed_t planeheight = FIXED_MIN;
while (true)
{
// Looking through planes from bottom to top
for (int i = sec->e->XFloor.ffloors.Size() - 1; i >= 0; --i)
{
F3DFloor *ff = sec->e->XFloor.ffloors[i];
fixed_t ffz = ff->bottom.plane->ZatPoint(x, y);
if ((ff->flags & (FF_EXISTS | FF_SOLID)) == (FF_EXISTS | FF_SOLID) && z <= ffz)
{ // This floor is above our eyes.
if (resultsec) *resultsec = sec;
if (resultffloor) *resultffloor = ff;
return ffz;
}
}
if ((flags & FFCF_NOPORTALS) || sec->PortalBlocksMovement(ceiling) || planeheight >= sec->SkyBoxes[ceiling]->threshold)
{ // Use sector's floor
if (resultffloor) *resultffloor = NULL;
if (resultsec) *resultsec = sec;
return sec->ceilingplane.ZatPoint(x, y);
}
else
{
FDisplacement &disp = sec->CeilingDisplacement();
x += disp.pos.x;
y += disp.pos.y;
planeheight = sec->SkyBoxes[ceiling]->threshold;
sec = P_PointInSector(x, y);
}
}
}
fixed_t sector_t::NextLowestFloorAt(fixed_t x, fixed_t y, fixed_t z, int flags, fixed_t steph, sector_t **resultsec, F3DFloor **resultffloor)
{
sector_t *sec = this;
fixed_t planeheight = FIXED_MAX;
while (true)
{
// Looking through planes from top to bottom
unsigned numff = sec->e->XFloor.ffloors.Size();
for (unsigned i = 0; i < numff; ++i)
{
F3DFloor *ff = sec->e->XFloor.ffloors[i];
fixed_t ffz = ff->top.plane->ZatPoint(x, y);
fixed_t ffb = ff->bottom.plane->ZatPoint(x, y);
// either with feet above the 3D floor or feet with less than 'stepheight' map units inside
if ((ff->flags & (FF_EXISTS | FF_SOLID)) == (FF_EXISTS | FF_SOLID))
{
if (z >= ffz || (!(flags & FFCF_3DRESTRICT) && (ffb < z && ffz < z + steph)))
{ // This floor is beneath our feet.
if (resultsec) *resultsec = sec;
if (resultffloor) *resultffloor = ff;
return ffz;
}
}
}
if ((flags & FFCF_NOPORTALS) || sec->PortalBlocksMovement(sector_t::floor) || planeheight <= sec->SkyBoxes[floor]->threshold)
{ // Use sector's floor
if (resultffloor) *resultffloor = NULL;
if (resultsec) *resultsec = sec;
return sec->floorplane.ZatPoint(x, y);
}
else
{
FDisplacement &disp = sec->FloorDisplacement();
x += disp.pos.x;
y += disp.pos.y;
planeheight = sec->SkyBoxes[floor]->threshold;
sec = P_PointInSector(x, y);
}
}
}
//===========================================================================
//
//
//
//===========================================================================
FArchive &operator<< (FArchive &arc, secspecial_t &p)
{
@ -908,6 +1042,11 @@ FArchive &operator<< (FArchive &arc, secspecial_t &p)
}
//===========================================================================
//
//
//
//===========================================================================
bool secplane_t::CopyPlaneIfValid (secplane_t *dest, const secplane_t *opp) const
{
@ -1085,4 +1224,3 @@ int side_t::GetLightLevel (bool foggy, int baselight, bool is3dlight, int *pfake
}
return baselight;
}

View file

@ -69,7 +69,6 @@
#include "po_man.h"
#include "r_renderer.h"
#include "r_data/colormaps.h"
#include "portal.h"
#include "p_blockmap.h"
#include "r_utility.h"
#include "p_spec.h"
@ -3393,12 +3392,12 @@ void P_FreeLevelData ()
FPolyObj::ClearAllSubsectorLinks(); // can't be done as part of the polyobj deletion process.
SN_StopAllSequences ();
DThinker::DestroyAllThinkers ();
P_ClearPortals();
tagManager.Clear();
level.total_monsters = level.total_items = level.total_secrets =
level.killed_monsters = level.found_items = level.found_secrets =
wminfo.maxfrags = 0;
linePortals.Clear();
FBehavior::StaticUnloadModules ();
if (vertexes != NULL)
{

View file

@ -67,7 +67,6 @@
#include "c_dispatch.h"
#include "r_sky.h"
#include "d_player.h"
#include "portal.h"
#include "p_maputl.h"
#include "p_blockmap.h"
#ifndef NO_EDATA
@ -440,7 +439,7 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector)
{
// Falling, not all the way down yet?
sector = player->mo->Sector;
if (player->mo->Z() != sector->floorplane.ZatPoint(player->mo)
if (player->mo->Z() != sector->LowestFloorAt(player->mo)
&& !player->mo->waterlevel)
{
return;
@ -480,7 +479,7 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector)
}
if (sector->Flags & SECF_DMGTERRAINFX)
{
P_HitWater(player->mo, sector, INT_MIN, INT_MIN, INT_MIN, false, true, true);
P_HitWater(player->mo, player->mo->Sector, INT_MIN, INT_MIN, INT_MIN, false, true, true);
}
}
}
@ -919,10 +918,11 @@ static void SetupFloorPortal (AStackPoint *point)
{
NActorIterator it (NAME_LowerStackLookOnly, point->tid);
sector_t *Sector = point->Sector;
Sector->SkyBoxes[sector_t::floor] = static_cast<ASkyViewpoint*>(it.Next());
if (Sector->SkyBoxes[sector_t::floor] != NULL && Sector->SkyBoxes[sector_t::floor]->bAlways)
ASkyViewpoint *skyv = static_cast<ASkyViewpoint*>(it.Next());
Sector->SkyBoxes[sector_t::floor] = skyv;
if (skyv != NULL && skyv->bAlways)
{
Sector->SkyBoxes[sector_t::floor]->Mate = point;
skyv->Mate = point;
if (Sector->GetAlpha(sector_t::floor) == OPAQUE)
Sector->SetAlpha(sector_t::floor, Scale (point->args[0], OPAQUE, 255));
}
@ -932,10 +932,11 @@ static void SetupCeilingPortal (AStackPoint *point)
{
NActorIterator it (NAME_UpperStackLookOnly, point->tid);
sector_t *Sector = point->Sector;
Sector->SkyBoxes[sector_t::ceiling] = static_cast<ASkyViewpoint*>(it.Next());
if (Sector->SkyBoxes[sector_t::ceiling] != NULL && Sector->SkyBoxes[sector_t::ceiling]->bAlways)
ASkyViewpoint *skyv = static_cast<ASkyViewpoint*>(it.Next());
Sector->SkyBoxes[sector_t::ceiling] = skyv;
if (skyv != NULL && skyv->bAlways)
{
Sector->SkyBoxes[sector_t::ceiling]->Mate = point;
skyv->Mate = point;
if (Sector->GetAlpha(sector_t::ceiling) == OPAQUE)
Sector->SetAlpha(sector_t::ceiling, Scale(point->args[0], OPAQUE, 255));
}
@ -968,7 +969,7 @@ static void SetPortal(sector_t *sector, int plane, ASkyViewpoint *portal, fixed_
// plane: 0=floor, 1=ceiling, 2=both
if (plane > 0)
{
if (sector->SkyBoxes[sector_t::ceiling] == NULL || !sector->SkyBoxes[sector_t::ceiling]->bAlways)
if (sector->SkyBoxes[sector_t::ceiling] == NULL || !barrier_cast<ASkyViewpoint*>(sector->SkyBoxes[sector_t::ceiling])->bAlways)
{
sector->SkyBoxes[sector_t::ceiling] = portal;
if (sector->GetAlpha(sector_t::ceiling) == OPAQUE)
@ -979,7 +980,7 @@ static void SetPortal(sector_t *sector, int plane, ASkyViewpoint *portal, fixed_
}
if (plane == 2 || plane == 0)
{
if (sector->SkyBoxes[sector_t::floor] == NULL || !sector->SkyBoxes[sector_t::floor]->bAlways)
if (sector->SkyBoxes[sector_t::floor] == NULL || !barrier_cast<ASkyViewpoint*>(sector->SkyBoxes[sector_t::floor])->bAlways)
{
sector->SkyBoxes[sector_t::floor] = portal;
}
@ -2326,6 +2327,7 @@ void DPusher::Tick ()
continue;
sector_t *hsec = sec->GetHeightSec();
fixedvec3 pos = thing->PosRelative(sec);
if (m_Type == p_wind)
{
if (hsec == NULL)
@ -2343,7 +2345,7 @@ void DPusher::Tick ()
}
else // special water sector
{
ht = hsec->floorplane.ZatPoint(thing);
ht = hsec->floorplane.ZatPoint(pos);
if (thing->Z() > ht) // above ground
{
xspeed = m_Xmag; // full force
@ -2372,7 +2374,7 @@ void DPusher::Tick ()
{ // special water sector
floor = &hsec->floorplane;
}
if (thing->Z() > floor->ZatPoint(thing))
if (thing->Z() > floor->ZatPoint(pos))
{ // above ground
xspeed = yspeed = 0; // no force
}

View file

@ -47,7 +47,6 @@
#include "r_data/colormaps.h"
#include "w_wad.h"
#include "p_tags.h"
#include "portal.h"
#include "p_terrain.h"
//===========================================================================

View file

@ -769,10 +769,9 @@ void APlayerPawn::PostBeginPlay()
// Voodoo dolls: restore original floorz/ceilingz logic
if (player == NULL || player->mo != this)
{
dropoffz = floorz = Sector->floorplane.ZatPoint(this);
ceilingz = Sector->ceilingplane.ZatPoint(this);
P_FindFloorCeiling(this, FFCF_ONLYSPAWNPOS);
P_FindFloorCeiling(this, FFCF_ONLYSPAWNPOS|FFCF_NOPORTALS);
SetZ(floorz);
P_FindFloorCeiling(this, FFCF_ONLYSPAWNPOS);
}
else
{

View file

@ -37,7 +37,6 @@
*/
#include "portal.h"
#include "p_local.h"
#include "p_lnspec.h"
#include "r_bsp.h"
@ -360,6 +359,20 @@ bool P_ChangePortal(line_t *ln, int thisid, int destid)
return res;
}
//============================================================================
//
// clears all portal dat for a new level start
//
//============================================================================
void P_ClearPortals()
{
Displacements.Create(1);
linePortals.Clear();
linkedPortals.Clear();
}
//============================================================================
//
// Calculate the intersection between two lines.
@ -774,13 +787,13 @@ static void AddDisplacementForPortal(AStackPoint *portal)
FDisplacement & disp = Displacements(thisgroup, othergroup);
if (!disp.isSet)
{
disp.x = portal->scaleX;
disp.y = portal->scaleY;
disp.pos.x = portal->scaleX;
disp.pos.y = portal->scaleY;
disp.isSet = true;
}
else
{
if (disp.x != portal->scaleX || disp.y != portal->scaleY)
if (disp.pos.x != portal->scaleX || disp.pos.y != portal->scaleY)
{
Printf("Portal between sectors %d and %d has displacement mismatch and will be disabled\n", portal->Sector->sectornum, portal->Mate->Sector->sectornum);
portal->special1 = portal->Mate->special1 = SKYBOX_PORTAL;
@ -810,13 +823,13 @@ static void AddDisplacementForPortal(FLinePortal *portal)
FDisplacement & disp = Displacements(thisgroup, othergroup);
if (!disp.isSet)
{
disp.x = portal->mXDisplacement;
disp.y = portal->mYDisplacement;
disp.pos.x = portal->mXDisplacement;
disp.pos.y = portal->mYDisplacement;
disp.isSet = true;
}
else
{
if (disp.x != portal->mXDisplacement || disp.y != portal->mYDisplacement)
if (disp.pos.x != portal->mXDisplacement || disp.pos.y != portal->mYDisplacement)
{
Printf("Portal between lines %d and %d has displacement mismatch\n", int(portal->mOrigin - lines), int(portal->mDestination - lines));
portal->mType = linePortals[portal->mDestination->portalindex].mType = PORTT_TELEPORT;
@ -857,15 +870,14 @@ static bool ConnectGroups()
FDisplacement &dispxz = Displacements(x, z);
if (dispxz.isSet)
{
if (dispxy.x + dispyz.x != dispxz.x || dispxy.y + dispyz.y != dispxz.y)
if (dispxy.pos.x + dispyz.pos.x != dispxz.pos.x || dispxy.pos.y + dispyz.pos.y != dispxz.pos.y)
{
bogus = true;
}
}
else
{
dispxz.x = dispxy.x + dispyz.x;
dispxz.y = dispxy.y + dispyz.y;
dispxz.pos = dispxy.pos + dispyz.pos;
dispxz.isSet = true;
dispxz.indirect = indirect;
changed = true;
@ -920,13 +932,15 @@ void P_CreateLinkedPortals()
}
if (orgs.Size() == 0)
{
// Create the 0->0 translation which is always needed.
Displacements.Create(1);
return;
}
for (int i = 0; i < numsectors; i++)
{
for (int j = 0; j < 2; j++)
{
ASkyViewpoint *box = sectors[i].SkyBoxes[j];
AActor *box = sectors[i].SkyBoxes[j];
if (box != NULL && box->special1 == SKYBOX_LINKEDPORTAL)
{
secplane_t &plane = j == 0 ? sectors[i].floorplane : sectors[i].ceilingplane;
@ -962,7 +976,7 @@ void P_CreateLinkedPortals()
{
for (int j = 0; j < 2; j++)
{
ASkyViewpoint *box = sectors[i].SkyBoxes[j];
ASkyViewpoint *box = barrier_cast<ASkyViewpoint*>(sectors[i].SkyBoxes[j]);
if (box != NULL)
{
if (box->special1 == SKYBOX_LINKEDPORTAL && sectors[i].PortalGroup == 0)
@ -995,7 +1009,7 @@ void P_CreateLinkedPortals()
FDisplacement &dispxy = Displacements(x, y);
FDisplacement &dispyx = Displacements(y, x);
if (dispxy.isSet && dispyx.isSet &&
(dispxy.x != -dispyx.x || dispxy.y != -dispyx.y))
(dispxy.pos.x != -dispyx.pos.x || dispxy.pos.y != -dispyx.pos.y))
{
int sec1 = -1, sec2 = -1;
for (int i = 0; i < numsectors && (sec1 == -1 || sec2 == -1); i++)
@ -1054,7 +1068,7 @@ void P_CreateLinkedPortals()
//
//============================================================================
bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortalGroupArray &out)
bool P_CollectConnectedGroups(int startgroup, const fixedvec3 &position, fixed_t upperz, fixed_t checkradius, FPortalGroupArray &out)
{
// Keep this temporary work stuff static. This function can never be called recursively
// and this would have to be reallocated for each call otherwise.
@ -1062,19 +1076,19 @@ bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortal
static TArray<FLinePortal*> foundPortals;
bool retval = false;
out.inited = true;
if (linkedPortals.Size() == 0)
{
// If there are no portals, all sectors are in group 0.
out.Add(0);
return false;
}
processMask.setSize(linkedPortals.Size());
processMask.clear();
foundPortals.Clear();
int thisgroup = actor->Sector->PortalGroup;
int thisgroup = startgroup;
processMask.setBit(thisgroup);
out.Add(thisgroup);
//out.Add(thisgroup);
for (unsigned i = 0; i < linkedPortals.Size(); i++)
{
@ -1083,7 +1097,7 @@ bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortal
FDisplacement &disp = Displacements(thisgroup, othergroup);
if (!disp.isSet) continue; // no connection.
FBoundingBox box(newx + disp.x, newy + disp.y, actor->radius);
FBoundingBox box(position.x + disp.pos.x, position.y + disp.pos.y, checkradius);
if (box.Right() <= ld->bbox[BOXLEFT]
|| box.Left() >= ld->bbox[BOXRIGHT]
@ -1111,27 +1125,27 @@ bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortal
}
}
}
sector_t *sec = P_PointInSector(newx, newy);
sector_t *sec = P_PointInSector(position.x, position.y);
sector_t *wsec = sec;
while (!wsec->PortalBlocksMovement(sector_t::ceiling) && actor->Top() > wsec->SkyBoxes[sector_t::ceiling]->threshold)
while (!wsec->PortalBlocksMovement(sector_t::ceiling) && upperz > wsec->SkyBoxes[sector_t::ceiling]->threshold)
{
sector_t *othersec = wsec->SkyBoxes[sector_t::ceiling]->Sector;
FDisplacement &disp = Displacements(actor->Sector->PortalGroup, othersec->PortalGroup);
fixed_t dx = newx + disp.x;
fixed_t dy = newx + disp.y;
FDisplacement &disp = Displacements(startgroup, othersec->PortalGroup);
fixed_t dx = position.x + disp.pos.x;
fixed_t dy = position.y + disp.pos.y;
processMask.setBit(othersec->PortalGroup);
out.Add(othersec->PortalGroup);
out.Add(othersec->PortalGroup|FPortalGroupArray::UPPER);
wsec = P_PointInSector(dx, dy); // get upper sector at the exact spot we want to check and repeat
retval = true;
}
wsec = sec;
while (!wsec->PortalBlocksMovement(sector_t::floor) && actor->Z() < wsec->SkyBoxes[sector_t::floor]->threshold)
while (!wsec->PortalBlocksMovement(sector_t::floor) && position.z < wsec->SkyBoxes[sector_t::floor]->threshold)
{
sector_t *othersec = wsec->SkyBoxes[sector_t::ceiling]->Sector;
FDisplacement &disp = Displacements(actor->Sector->PortalGroup, othersec->PortalGroup);
fixed_t dx = newx + disp.x;
fixed_t dy = newx + disp.y;
processMask.setBit(othersec->PortalGroup);
sector_t *othersec = wsec->SkyBoxes[sector_t::floor]->Sector;
FDisplacement &disp = Displacements(startgroup, othersec->PortalGroup);
fixed_t dx = position.x + disp.pos.x;
fixed_t dy = position.y + disp.pos.y;
processMask.setBit(othersec->PortalGroup|FPortalGroupArray::LOWER);
out.Add(othersec->PortalGroup);
wsec = P_PointInSector(dx, dy); // get lower sector at the exact spot we want to check and repeat
retval = true;
@ -1153,7 +1167,7 @@ CCMD(dumplinktable)
for (int y = 1; y < Displacements.size; y++)
{
FDisplacement &disp = Displacements(x, y);
Printf("%c%c(%6d, %6d)", TEXTCOLOR_ESCAPE, 'C' + disp.indirect, disp.x >> FRACBITS, disp.y >> FRACBITS);
Printf("%c%c(%6d, %6d)", TEXTCOLOR_ESCAPE, 'C' + disp.indirect, disp.pos.x >> FRACBITS, disp.pos.y >> FRACBITS);
}
Printf("\n");
}

View file

@ -3,11 +3,7 @@
#include "basictypes.h"
#include "v_video.h"
#include "r_defs.h"
#include "actor.h"
#include "p_local.h"
#include "m_bbox.h"
#include "a_sharedglobal.h"
struct FPortalGroupArray;
//============================================================================
@ -30,9 +26,14 @@ struct FPortalGroupArray;
struct FDisplacement
{
fixed_t x, y;
fixedvec2 pos;
bool isSet;
BYTE indirect; // just for illustration.
operator fixedvec2()
{
return pos;
}
};
struct FDisplacementTable
@ -40,6 +41,11 @@ struct FDisplacementTable
TArray<FDisplacement> data;
int size;
FDisplacementTable()
{
Create(1);
}
void Create(int numgroups)
{
data.Resize(numgroups*numgroups);
@ -49,6 +55,7 @@ struct FDisplacementTable
FDisplacement &operator()(int x, int y)
{
if (x == y) return data[0]; // shortcut for the most common case
return data[x + size*y];
}
};
@ -116,11 +123,12 @@ struct FLinePortal
extern TArray<FLinePortal> linePortals;
void P_ClearPortals();
void P_SpawnLinePortal(line_t* line);
void P_FinalizePortals();
bool P_ChangePortal(line_t *ln, int thisid, int destid);
void P_CreateLinkedPortals();
bool P_CollectConnectedGroups(AActor *actor, fixed_t newx, fixed_t newy, FPortalGroupArray &out);
bool P_CollectConnectedGroups(int startgroup, const fixedvec3 &position, fixed_t upperz, fixed_t checkradius, FPortalGroupArray &out);
void P_CollectLinkedPortals();
inline int P_NumPortalGroups()
{
@ -175,58 +183,4 @@ public:
/* new code */
fixed_t P_PointLineDistance(line_t* line, fixed_t x, fixed_t y);
//============================================================================
//
// some wrappers around the portal data.
//
//============================================================================
// returns true if the portal is crossable by actors
inline bool line_t::isLinePortal() const
{
return portalindex >= linePortals.Size() ? false : !!(linePortals[portalindex].mFlags & PORTF_PASSABLE);
}
// returns true if the portal needs to be handled by the renderer
inline bool line_t::isVisualPortal() const
{
return portalindex >= linePortals.Size() ? false : !!(linePortals[portalindex].mFlags & PORTF_VISIBLE);
}
inline line_t *line_t::getPortalDestination() const
{
return portalindex >= linePortals.Size() ? (line_t*)NULL : linePortals[portalindex].mDestination;
}
inline int line_t::getPortalAlignment() const
{
return portalindex >= linePortals.Size() ? 0 : linePortals[portalindex].mAlign;
}
inline bool sector_t::PortalBlocksView(int plane)
{
if (SkyBoxes[plane] == NULL) return true;
if (SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return false;
return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
}
inline bool sector_t::PortalBlocksSight(int plane)
{
if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true;
return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
}
inline bool sector_t::PortalBlocksMovement(int plane)
{
if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true;
return !!(planes[plane].Flags & (PLANEF_NOPASS | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
}
inline bool sector_t::PortalBlocksSound(int plane)
{
if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true;
return !!(planes[plane].Flags & (PLANEF_BLOCKSOUND | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
}
#endif

View file

@ -56,7 +56,6 @@
#include "r_sky.h"
#include "po_man.h"
#include "r_data/colormaps.h"
#include "portal.h"
seg_t* curline;
side_t* sidedef;

View file

@ -25,7 +25,7 @@
#include "tarray.h"
#include <stddef.h>
#include "portal.h"
#include "r_defs.h"
// The 3072 below is just an arbitrary value picked to avoid
// drawing lines the player is too close to that would overflow

View file

@ -58,6 +58,7 @@ enum
};
extern size_t MaxDrawSegs;
struct FDisplacement;
enum
@ -273,6 +274,16 @@ struct secplane_t
return ic < 0 ? d : -d;
}
fixed_t ZatPoint(const fixedvec2 &spot) const
{
return FixedMul(ic, -d - DMulScale16(a, spot.x, b, spot.y));
}
fixed_t ZatPoint(const fixedvec3 &spot) const
{
return FixedMul(ic, -d - DMulScale16(a, spot.x, b, spot.y));
}
// Returns the value of z at (x,y)
fixed_t ZatPoint (fixed_t x, fixed_t y) const
{
@ -365,6 +376,21 @@ struct secplane_t
return -TMulScale16 (a, v->x, b, v->y, z, c);
}
void SetAtHeight(fixed_t height, int ceiling)
{
a = b = 0;
if (ceiling)
{
c = ic = -FRACUNIT;
d = height;
}
else
{
c = ic = FRACUNIT;
d = -height;
}
}
bool CopyPlaneIfValid (secplane_t *dest, const secplane_t *opp) const;
};
@ -755,17 +781,6 @@ struct sector_t
return pos == floor? floorplane:ceilingplane;
}
fixed_t HighestCeiling(AActor *a) const
{
return ceilingplane.ZatPoint(a);
}
fixed_t LowestFloor(AActor *a) const
{
return floorplane.ZatPoint(a);
}
bool isSecret() const
{
return !!(Flags & SECF_SECRET);
@ -792,10 +807,41 @@ struct sector_t
Flags &= ~SECF_SPECIALFLAGS;
}
bool PortalBlocksView(int plane);
bool PortalBlocksSight(int plane);
bool PortalBlocksMovement(int plane);
bool PortalBlocksSound(int plane);
bool PortalBlocksView(int plane)
{
if (SkyBoxes[plane] == NULL) return true;
if (SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return false;
return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
}
bool PortalBlocksSight(int plane)
{
if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true;
return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
}
bool PortalBlocksMovement(int plane)
{
if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true;
return !!(planes[plane].Flags & (PLANEF_NOPASS | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
}
bool PortalBlocksSound(int plane)
{
if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true;
return !!(planes[plane].Flags & (PLANEF_BLOCKSOUND | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
}
// These may only be called if the portal has been validated
FDisplacement &FloorDisplacement()
{
return Displacements(PortalGroup, SkyBoxes[sector_t::floor]->Sector->PortalGroup);
}
FDisplacement &CeilingDisplacement()
{
return Displacements(PortalGroup, SkyBoxes[sector_t::ceiling]->Sector->PortalGroup);
}
int GetTerrain(int pos) const;
@ -804,6 +850,32 @@ struct sector_t
void SetSpecial(const secspecial_t *spec);
bool PlaneMoving(int pos);
// Portal-aware height calculation
fixed_t HighestCeilingAt(fixed_t x, fixed_t y, sector_t **resultsec = NULL);
fixed_t LowestFloorAt(fixed_t x, fixed_t y, sector_t **resultsec = NULL);
fixed_t HighestCeilingAt(AActor *a, sector_t **resultsec = NULL)
{
return HighestCeilingAt(a->X(), a->Y(), resultsec);
}
fixed_t LowestFloorAt(AActor *a, sector_t **resultsec = NULL)
{
return LowestFloorAt(a->X(), a->Y(), resultsec);
}
fixed_t NextHighestCeilingAt(fixed_t x, fixed_t y, fixed_t z, int flags = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL);
fixed_t NextLowestFloorAt(fixed_t x, fixed_t y, fixed_t z, int flags = 0, fixed_t steph = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL);
fixed_t NextHighestCeilingAt(AActor *a, fixed_t z, int flags = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL)
{
return NextHighestCeilingAt(a->X(), a->Y(), z, flags, resultsec, resultffloor);
}
fixed_t NextLowestFloorAt(AActor *a, fixed_t z, int flags, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL)
{
return NextLowestFloorAt(a->X(), a->Y(), z, flags, a->MaxStepHeight, resultsec, resultffloor);
}
// Member variables
fixed_t CenterFloor () const { return floorplane.ZatPoint (soundorg[0], soundorg[1]); }
@ -888,7 +960,7 @@ struct sector_t
// [RH] The sky box to render for this sector. NULL means use a
// regular sky.
TObjPtr<ASkyViewpoint> SkyBoxes[2];
TObjPtr<AActor> SkyBoxes[2];
int PortalGroup;
int sectornum; // for comparing sector copies
@ -1107,11 +1179,26 @@ struct line_t
TObjPtr<ASkyViewpoint> skybox;
// returns true if the portal is crossable by actors
bool isLinePortal() const;
bool isLinePortal() const
{
return portalindex >= linePortals.Size() ? false : !!(linePortals[portalindex].mFlags & PORTF_PASSABLE);
}
// returns true if the portal needs to be handled by the renderer
bool isVisualPortal() const;
line_t *getPortalDestination() const;
int getPortalAlignment() const;
bool isVisualPortal() const
{
return portalindex >= linePortals.Size() ? false : !!(linePortals[portalindex].mFlags & PORTF_VISIBLE);
}
line_t *getPortalDestination() const
{
return portalindex >= linePortals.Size() ? (line_t*)NULL : linePortals[portalindex].mDestination;
}
int getPortalAlignment() const
{
return portalindex >= linePortals.Size() ? 0 : linePortals[portalindex].mAlign;
}
};
// phares 3/14/98
@ -1278,5 +1365,24 @@ inline sector_t *P_PointInSector(fixed_t x, fixed_t y)
return P_PointInSubsector(x, y)->sector;
}
inline fixedvec3 AActor::PosRelative(AActor *other) const
{
return __pos + Displacements(Sector->PortalGroup, other->Sector->PortalGroup);
}
inline fixedvec3 AActor::PosRelative(sector_t *sec) const
{
return __pos + Displacements(Sector->PortalGroup, sec->PortalGroup);
}
inline fixedvec3 AActor::PosRelative(line_t *line) const
{
return __pos + Displacements(Sector->PortalGroup, line->frontsector->PortalGroup);
}
inline fixedvec3 PosRelative(const fixedvec3 &pos, line_t *line, sector_t *refsec = NULL)
{
return pos + Displacements(refsec->PortalGroup, line->frontsector->PortalGroup);
}
#endif

View file

@ -58,7 +58,6 @@
#include "v_font.h"
#include "r_data/colormaps.h"
#include "farchive.h"
#include "portal.h"
// MACROS ------------------------------------------------------------------

View file

@ -58,7 +58,6 @@
#include "r_3dfloors.h"
#include "v_palette.h"
#include "r_data/colormaps.h"
#include "portal.h"
#ifdef _MSC_VER
#pragma warning(disable:4244)

View file

@ -52,7 +52,6 @@
#include "r_3dfloors.h"
#include "v_palette.h"
#include "r_data/colormaps.h"
#include "portal.h"
#define WALLYREPEAT 8

View file

@ -34,7 +34,6 @@
#include "doomstat.h"
#include "m_random.h"
#include "m_bbox.h"
#include "portal.h"
#include "r_sky.h"
#include "st_stuff.h"
#include "c_cvars.h"
@ -57,7 +56,7 @@
#include "farchive.h"
#include "r_utility.h"
#include "d_player.h"
#include "portal.h"
#include "p_local.h"
// EXTERNAL DATA DECLARATIONS ----------------------------------------------

View file

@ -900,6 +900,7 @@ class FxReturnStatement : public FxExpression
public:
FxReturnStatement(FxVMFunctionCall *call, const FScriptPosition &pos);
~FxReturnStatement();
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
VMFunction *GetDirectFunction();

View file

@ -3525,6 +3525,11 @@ FxReturnStatement::FxReturnStatement(FxVMFunctionCall *call, const FScriptPositi
{
}
FxReturnStatement::~FxReturnStatement()
{
SAFE_DELETE(Call);
}
FxExpression *FxReturnStatement::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();