mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-29 07:22:05 +00:00
Merge remote-tracking branch 'remotes/zdoom/master'
# Conflicts: # src/portal.h # src/r_defs.h
This commit is contained in:
commit
e107d8ff48
38 changed files with 1304 additions and 704 deletions
29
src/actor.h
29
src/actor.h
|
@ -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);
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);// ^
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 ()
|
||||
{
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include "g_level.h"
|
||||
#include "r_data/colormaps.h"
|
||||
#include "gi.h"
|
||||
#include "portal.h"
|
||||
#include "p_spec.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
573
src/p_map.cpp
573
src/p_map.cpp
|
@ -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;
|
||||
|
|
306
src/p_maputl.cpp
306
src/p_maputl.cpp
|
@ -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
|
||||
|
|
159
src/p_maputl.h
159
src/p_maputl.h
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
#include "r_data/colormaps.h"
|
||||
#include "w_wad.h"
|
||||
#include "p_tags.h"
|
||||
#include "portal.h"
|
||||
#include "p_terrain.h"
|
||||
|
||||
//===========================================================================
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
74
src/portal.h
74
src/portal.h
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
146
src/r_defs.h
146
src/r_defs.h
|
@ -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
|
||||
|
|
|
@ -58,7 +58,6 @@
|
|||
#include "v_font.h"
|
||||
#include "r_data/colormaps.h"
|
||||
#include "farchive.h"
|
||||
#include "portal.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -52,7 +52,6 @@
|
|||
#include "r_3dfloors.h"
|
||||
#include "v_palette.h"
|
||||
#include "r_data/colormaps.h"
|
||||
#include "portal.h"
|
||||
|
||||
#define WALLYREPEAT 8
|
||||
|
||||
|
|
|
@ -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 ----------------------------------------------
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -3525,6 +3525,11 @@ FxReturnStatement::FxReturnStatement(FxVMFunctionCall *call, const FScriptPositi
|
|||
{
|
||||
}
|
||||
|
||||
FxReturnStatement::~FxReturnStatement()
|
||||
{
|
||||
SAFE_DELETE(Call);
|
||||
}
|
||||
|
||||
FxExpression *FxReturnStatement::Resolve(FCompileContext &ctx)
|
||||
{
|
||||
CHECKRESOLVED();
|
||||
|
|
Loading…
Reference in a new issue