- added GZDoom's 3D floor physics code. This is not active yet so anything compiled from this code won't have any support for it!

SVN r1351 (trunk)
This commit is contained in:
Christoph Oelckers 2009-01-04 15:00:29 +00:00
parent f7148b6b40
commit 78933df10d
21 changed files with 1892 additions and 122 deletions

View file

@ -1,4 +1,6 @@
January 4, 2009 (Changes by Graf Zahl) January 4, 2009 (Changes by Graf Zahl)
- added GZDoom's 3D floor physics code. This is not active yet so anything
compiled from this code won't have any support for it!
- Used new functionality to avoid moving the puff around in SpawnDeepSplash. - Used new functionality to avoid moving the puff around in SpawnDeepSplash.
- Fixed: P_RailAttack used the shooting actor or a default puff for some splash - Fixed: P_RailAttack used the shooting actor or a default puff for some splash
related actions. It should use the puff type passed to it as a parameter instead. related actions. It should use the puff type passed to it as a parameter instead.

View file

@ -2188,7 +2188,7 @@ void Net_DoCommand (int type, BYTE **stream, int player)
{ {
DImpactDecal::StaticCreate (s, DImpactDecal::StaticCreate (s,
trace.X, trace.Y, trace.Z, trace.X, trace.Y, trace.Z,
sides + trace.Line->sidenum[trace.Side]); sides + trace.Line->sidenum[trace.Side], NULL);
} }
} }
} }

View file

@ -2879,6 +2879,10 @@ void G_SerializeLevel (FArchive &arc, bool hubLoad)
P_SerializePlayers (arc, hubLoad); P_SerializePlayers (arc, hubLoad);
P_SerializeSounds (arc); P_SerializeSounds (arc);
if (arc.IsLoading()) for(i=0;i<numsectors;i++)
{
P_Recalculate3DFloors(&sectors[i]);
}
} }
// Archives the current level // Archives the current level

View file

@ -131,7 +131,8 @@ void DBaseDecal::Serialize (FArchive &arc)
<< Translation << Translation
<< PicNum << PicNum
<< RenderFlags << RenderFlags
<< RenderStyle; << RenderStyle
<< Sector;
} }
void DBaseDecal::SerializeChain (FArchive &arc, DBaseDecal **first) void DBaseDecal::SerializeChain (FArchive &arc, DBaseDecal **first)
@ -207,7 +208,7 @@ void DBaseDecal::SetShade (int r, int g, int b)
} }
// Returns the texture the decal stuck to. // Returns the texture the decal stuck to.
FTextureID DBaseDecal::StickToWall (side_t *wall, fixed_t x, fixed_t y) FTextureID DBaseDecal::StickToWall (side_t *wall, fixed_t x, fixed_t y, F3DFloor * ffloor)
{ {
// Stick the decal at the end of the chain so it appears on top // Stick the decal at the end of the chain so it appears on top
DBaseDecal *next, **prev; DBaseDecal *next, **prev;
@ -262,7 +263,7 @@ FTextureID DBaseDecal::StickToWall (side_t *wall, fixed_t x, fixed_t y)
Z -= back->GetPlaneTexZ(sector_t::floor); Z -= back->GetPlaneTexZ(sector_t::floor);
tex = wall->GetTexture(side_t::bottom); tex = wall->GetTexture(side_t::bottom);
} }
else else if (back->ceilingplane.ZatPoint (x, y) <= Z)
{ {
RenderFlags |= RF_RELUPPER|RF_CLIPUPPER; RenderFlags |= RF_RELUPPER|RF_CLIPUPPER;
if (line->flags & ML_DONTPEGTOP) if (line->flags & ML_DONTPEGTOP)
@ -271,7 +272,31 @@ FTextureID DBaseDecal::StickToWall (side_t *wall, fixed_t x, fixed_t y)
Z -= back->GetPlaneTexZ(sector_t::ceiling); Z -= back->GetPlaneTexZ(sector_t::ceiling);
tex = wall->GetTexture(side_t::top); tex = wall->GetTexture(side_t::top);
} }
#ifdef _3DFLOORS
else if (ffloor) // this is a 3d-floor segment - do this only if we know which one!
{
Sector=ffloor->model;
RenderFlags |= RF_RELMID|RF_CLIPMID;
if (line->flags & ML_DONTPEGBOTTOM)
Z -= Sector->GetPlaneTexZ(sector_t::floor);
else
Z -= Sector->GetPlaneTexZ(sector_t::ceiling);
if (ffloor->flags & FF_UPPERTEXTURE)
{
tex = wall->GetTexture(side_t::top);
}
else if (ffloor->flags & FF_LOWERTEXTURE)
{
tex = wall->GetTexture(side_t::bottom);
}
else
{
tex = sides[ffloor->master->sidenum[0]].GetTexture(side_t::mid);
}
}
#endif
else return FNullTextureID();
CalcFracPos (wall, x, y); CalcFracPos (wall, x, y);
return tex; return tex;
@ -406,7 +431,7 @@ static side_t *NextWall (const side_t *wall)
return NULL; return NULL;
} }
void DBaseDecal::SpreadLeft (fixed_t r, vertex_t *v1, side_t *feelwall) void DBaseDecal::SpreadLeft (fixed_t r, vertex_t *v1, side_t *feelwall, F3DFloor * ffloor)
{ {
fixed_t ldx, ldy; fixed_t ldx, ldy;
@ -426,7 +451,7 @@ void DBaseDecal::SpreadLeft (fixed_t r, vertex_t *v1, side_t *feelwall)
x += Scale (r, ldx, wallsize); x += Scale (r, ldx, wallsize);
y += Scale (r, ldy, wallsize); y += Scale (r, ldy, wallsize);
r = wallsize + startr; r = wallsize + startr;
SpreadSource->CloneSelf (SpreadTemplate, x, y, SpreadZ, feelwall); SpreadSource->CloneSelf (SpreadTemplate, x, y, SpreadZ, feelwall, ffloor);
SpreadStack.Push (feelwall); SpreadStack.Push (feelwall);
side_t *nextwall = NextWall (feelwall); side_t *nextwall = NextWall (feelwall);
@ -444,13 +469,13 @@ void DBaseDecal::SpreadLeft (fixed_t r, vertex_t *v1, side_t *feelwall)
vertex_t *v2; vertex_t *v2;
GetWallStuff (nextwall, v2, ldx, ldy); GetWallStuff (nextwall, v2, ldx, ldy);
SpreadLeft (startr, v2, nextwall); SpreadLeft (startr, v2, nextwall, ffloor);
} }
} }
} }
} }
void DBaseDecal::SpreadRight (fixed_t r, side_t *feelwall, fixed_t wallsize) void DBaseDecal::SpreadRight (fixed_t r, side_t *feelwall, fixed_t wallsize, F3DFloor * ffloor)
{ {
vertex_t *v1; vertex_t *v1;
fixed_t x, y, ldx, ldy; fixed_t x, y, ldx, ldy;
@ -473,7 +498,7 @@ void DBaseDecal::SpreadRight (fixed_t r, side_t *feelwall, fixed_t wallsize)
} }
if (i == -1) if (i == -1)
{ {
SpreadRight (r, nextwall, wallsize); SpreadRight (r, nextwall, wallsize, ffloor);
} }
} }
@ -485,12 +510,12 @@ void DBaseDecal::SpreadRight (fixed_t r, side_t *feelwall, fixed_t wallsize)
x -= Scale (r, ldx, wallsize); x -= Scale (r, ldx, wallsize);
y -= Scale (r, ldy, wallsize); y -= Scale (r, ldy, wallsize);
r = DecalRight - r; r = DecalRight - r;
SpreadSource->CloneSelf (SpreadTemplate, x, y, SpreadZ, feelwall); SpreadSource->CloneSelf (SpreadTemplate, x, y, SpreadZ, feelwall, ffloor);
SpreadStack.Push (feelwall); SpreadStack.Push (feelwall);
} }
} }
void DBaseDecal::Spread (const FDecalTemplate *tpl, side_t *wall, fixed_t x, fixed_t y, fixed_t z) void DBaseDecal::Spread (const FDecalTemplate *tpl, side_t *wall, fixed_t x, fixed_t y, fixed_t z, F3DFloor * ffloor)
{ {
FTexture *tex; FTexture *tex;
vertex_t *v1; vertex_t *v1;
@ -510,21 +535,21 @@ void DBaseDecal::Spread (const FDecalTemplate *tpl, side_t *wall, fixed_t x, fix
SpreadZ = z; SpreadZ = z;
// Try spreading left first // Try spreading left first
SpreadLeft (rorg - DecalLeft, v1, wall); SpreadLeft (rorg - DecalLeft, v1, wall, ffloor);
SpreadStack.Clear (); SpreadStack.Clear ();
// Then try spreading right // Then try spreading right
SpreadRight (rorg + DecalRight, wall, SpreadRight (rorg + DecalRight, wall,
Length (lines[wall->linenum].dx, lines[wall->linenum].dy)); Length (lines[wall->linenum].dx, lines[wall->linenum].dy), ffloor);
SpreadStack.Clear (); SpreadStack.Clear ();
} }
DBaseDecal *DBaseDecal::CloneSelf (const FDecalTemplate *tpl, fixed_t ix, fixed_t iy, fixed_t iz, side_t *wall) const DBaseDecal *DBaseDecal::CloneSelf (const FDecalTemplate *tpl, fixed_t ix, fixed_t iy, fixed_t iz, side_t *wall, F3DFloor * ffloor) const
{ {
DBaseDecal *decal = new DBaseDecal(iz); DBaseDecal *decal = new DBaseDecal(iz);
if (decal != NULL) if (decal != NULL)
{ {
decal->StickToWall (wall, ix, iy); decal->StickToWall (wall, ix, iy, ffloor);
tpl->ApplyToDecal (decal, wall); tpl->ApplyToDecal (decal, wall);
decal->AlphaColor = AlphaColor; decal->AlphaColor = AlphaColor;
decal->RenderFlags = (decal->RenderFlags & RF_DECALMASK) | decal->RenderFlags = (decal->RenderFlags & RF_DECALMASK) |
@ -598,7 +623,7 @@ void DImpactDecal::CheckMax ()
} }
} }
DImpactDecal *DImpactDecal::StaticCreate (const char *name, fixed_t x, fixed_t y, fixed_t z, side_t *wall, PalEntry color) DImpactDecal *DImpactDecal::StaticCreate (const char *name, fixed_t x, fixed_t y, fixed_t z, side_t *wall, F3DFloor * ffloor, PalEntry color)
{ {
if (cl_maxdecals > 0) if (cl_maxdecals > 0)
{ {
@ -606,13 +631,13 @@ DImpactDecal *DImpactDecal::StaticCreate (const char *name, fixed_t x, fixed_t y
if (tpl != NULL && (tpl = tpl->GetDecal()) != NULL) if (tpl != NULL && (tpl = tpl->GetDecal()) != NULL)
{ {
return StaticCreate (tpl, x, y, z, wall, color); return StaticCreate (tpl, x, y, z, wall, ffloor, color);
} }
} }
return NULL; return NULL;
} }
DImpactDecal *DImpactDecal::StaticCreate (const FDecalTemplate *tpl, fixed_t x, fixed_t y, fixed_t z, side_t *wall, PalEntry color) DImpactDecal *DImpactDecal::StaticCreate (const FDecalTemplate *tpl, fixed_t x, fixed_t y, fixed_t z, side_t *wall, F3DFloor * ffloor, PalEntry color)
{ {
DImpactDecal *decal = NULL; DImpactDecal *decal = NULL;
if (tpl != NULL && cl_maxdecals > 0 && !(wall->Flags & WALLF_NOAUTODECALS)) if (tpl != NULL && cl_maxdecals > 0 && !(wall->Flags & WALLF_NOAUTODECALS))
@ -625,12 +650,12 @@ DImpactDecal *DImpactDecal::StaticCreate (const FDecalTemplate *tpl, fixed_t x,
// If the default color of the lower decal is the same as the main decal's // If the default color of the lower decal is the same as the main decal's
// apply the custom color as well. // apply the custom color as well.
if (tpl->ShadeColor == tpl_low->ShadeColor) lowercolor=0; if (tpl->ShadeColor == tpl_low->ShadeColor) lowercolor=0;
StaticCreate (tpl_low, x, y, z, wall, lowercolor); StaticCreate (tpl_low, x, y, z, wall, ffloor, lowercolor);
} }
DImpactDecal::CheckMax(); DImpactDecal::CheckMax();
decal = new DImpactDecal (z); decal = new DImpactDecal (z);
FTextureID stickypic = decal->StickToWall (wall, x, y); FTextureID stickypic = decal->StickToWall (wall, x, y, ffloor);
FTexture *tex = TexMan[stickypic]; FTexture *tex = TexMan[stickypic];
if (tex != NULL && tex->bNoDecals) if (tex != NULL && tex->bNoDecals)
@ -655,18 +680,18 @@ DImpactDecal *DImpactDecal::StaticCreate (const FDecalTemplate *tpl, fixed_t x,
} }
// Spread decal to nearby walls if it does not all fit on this one // Spread decal to nearby walls if it does not all fit on this one
decal->Spread (tpl, wall, x, y, z); decal->Spread (tpl, wall, x, y, z, ffloor);
} }
return decal; return decal;
} }
DBaseDecal *DImpactDecal::CloneSelf (const FDecalTemplate *tpl, fixed_t ix, fixed_t iy, fixed_t iz, side_t *wall) const DBaseDecal *DImpactDecal::CloneSelf (const FDecalTemplate *tpl, fixed_t ix, fixed_t iy, fixed_t iz, side_t *wall, F3DFloor * ffloor) const
{ {
DImpactDecal::CheckMax(); DImpactDecal::CheckMax();
DImpactDecal *decal = new DImpactDecal(iz); DImpactDecal *decal = new DImpactDecal(iz);
if (decal != NULL) if (decal != NULL)
{ {
decal->StickToWall (wall, ix, iy); decal->StickToWall (wall, ix, iy, ffloor);
tpl->ApplyToDecal (decal, wall); tpl->ApplyToDecal (decal, wall);
decal->AlphaColor = AlphaColor; decal->AlphaColor = AlphaColor;
decal->RenderFlags = (decal->RenderFlags & RF_DECALMASK) | decal->RenderFlags = (decal->RenderFlags & RF_DECALMASK) |
@ -751,12 +776,12 @@ void ADecal::BeginPlay ()
{ {
decal = new DBaseDecal (this); decal = new DBaseDecal (this);
wall = sides + trace.Line->sidenum[trace.Side]; wall = sides + trace.Line->sidenum[trace.Side];
decal->StickToWall (wall, trace.X, trace.Y); decal->StickToWall (wall, trace.X, trace.Y, trace.ffloor);
tpl->ApplyToDecal (decal, wall); tpl->ApplyToDecal (decal, wall);
// Spread decal to nearby walls if it does not all fit on this one // Spread decal to nearby walls if it does not all fit on this one
if (cl_spreaddecals) if (cl_spreaddecals)
{ {
decal->Spread (tpl, wall, trace.X, trace.Y, z); decal->Spread (tpl, wall, trace.X, trace.Y, z, trace.ffloor);
} }
} }
else else

View file

@ -7,6 +7,7 @@
class FDecalTemplate; class FDecalTemplate;
struct vertex_t; struct vertex_t;
struct side_t; struct side_t;
struct F3DFloor;
extern void P_SpawnDirt (AActor *actor, fixed_t radius); extern void P_SpawnDirt (AActor *actor, fixed_t radius);
@ -23,11 +24,11 @@ public:
void Serialize (FArchive &arc); void Serialize (FArchive &arc);
void Destroy (); void Destroy ();
FTextureID StickToWall (side_t *wall, fixed_t x, fixed_t y); FTextureID StickToWall (side_t *wall, fixed_t x, fixed_t y, F3DFloor * ffloor);
fixed_t GetRealZ (const side_t *wall) const; fixed_t GetRealZ (const side_t *wall) const;
void SetShade (DWORD rgb); void SetShade (DWORD rgb);
void SetShade (int r, int g, int b); void SetShade (int r, int g, int b);
void Spread (const FDecalTemplate *tpl, side_t *wall, fixed_t x, fixed_t y, fixed_t z); void Spread (const FDecalTemplate *tpl, side_t *wall, fixed_t x, fixed_t y, fixed_t z, F3DFloor * ffloor);
void GetXY (side_t *side, fixed_t &x, fixed_t &y) const; void GetXY (side_t *side, fixed_t &x, fixed_t &y) const;
static void SerializeChain (FArchive &arc, DBaseDecal **firstptr); static void SerializeChain (FArchive &arc, DBaseDecal **firstptr);
@ -43,14 +44,15 @@ public:
FTextureID PicNum; FTextureID PicNum;
DWORD RenderFlags; DWORD RenderFlags;
FRenderStyle RenderStyle; FRenderStyle RenderStyle;
sector_t * Sector; // required for 3D floors
protected: protected:
virtual DBaseDecal *CloneSelf (const FDecalTemplate *tpl, fixed_t x, fixed_t y, fixed_t z, side_t *wall) const; virtual DBaseDecal *CloneSelf (const FDecalTemplate *tpl, fixed_t x, fixed_t y, fixed_t z, side_t *wall, F3DFloor * ffloor) const;
void CalcFracPos (side_t *wall, fixed_t x, fixed_t y); void CalcFracPos (side_t *wall, fixed_t x, fixed_t y);
void Remove (); void Remove ();
static void SpreadLeft (fixed_t r, vertex_t *v1, side_t *feelwall); static void SpreadLeft (fixed_t r, vertex_t *v1, side_t *feelwall, F3DFloor * ffloor);
static void SpreadRight (fixed_t r, side_t *feelwall, fixed_t wallsize); static void SpreadRight (fixed_t r, side_t *feelwall, fixed_t wallsize, F3DFloor * ffloor);
}; };
class DImpactDecal : public DBaseDecal class DImpactDecal : public DBaseDecal
@ -60,8 +62,8 @@ public:
DImpactDecal (fixed_t z); DImpactDecal (fixed_t z);
DImpactDecal (side_t *wall, const FDecalTemplate *templ); DImpactDecal (side_t *wall, const FDecalTemplate *templ);
static DImpactDecal *StaticCreate (const char *name, fixed_t x, fixed_t y, fixed_t z, side_t *wall, PalEntry color=0); static DImpactDecal *StaticCreate (const char *name, fixed_t x, fixed_t y, fixed_t z, side_t *wall, F3DFloor * ffloor, PalEntry color=0);
static DImpactDecal *StaticCreate (const FDecalTemplate *tpl, fixed_t x, fixed_t y, fixed_t z, side_t *wall, PalEntry color=0); static DImpactDecal *StaticCreate (const FDecalTemplate *tpl, fixed_t x, fixed_t y, fixed_t z, side_t *wall, F3DFloor * ffloor, PalEntry color=0);
void BeginPlay (); void BeginPlay ();
void Destroy (); void Destroy ();
@ -70,7 +72,7 @@ public:
static void SerializeTime (FArchive &arc); static void SerializeTime (FArchive &arc);
protected: protected:
DBaseDecal *CloneSelf (const FDecalTemplate *tpl, fixed_t x, fixed_t y, fixed_t z, side_t *wall) const; DBaseDecal *CloneSelf (const FDecalTemplate *tpl, fixed_t x, fixed_t y, fixed_t z, side_t *wall, F3DFloor * ffloor) const;
static void CheckMax (); static void CheckMax ();
private: private:

678
src/p_3dfloors.cpp Normal file
View file

@ -0,0 +1,678 @@
/*
** p_3dfloor.cpp
**
** 3D-floor handling
**
**---------------------------------------------------------------------------
** Copyright 2005-2008 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
** 4. Full disclosure of the entire project's source code, except for third
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#ifdef _3DFLOORS
#include "templates.h"
#include "p_local.h"
#include "p_lnspec.h"
#include "w_wad.h"
#include "sc_man.h"
#include "v_palette.h"
#include "g_level.h"
//==========================================================================
//
// 3D Floors
//
//==========================================================================
//==========================================================================
//
// Add one 3D floor to the sector
//
//==========================================================================
static void P_Add3DFloor(sector_t* sec, sector_t* sec2, line_t* master, int flags,int transluc)
{
F3DFloor* ffloor;
unsigned i;
for(i = 0; i < sec2->e->XFloor.attached.Size(); i++) if(sec2->e->XFloor.attached[i] == sec) return;
sec2->e->XFloor.attached.Push(sec);
//Add the floor
ffloor = new F3DFloor;
ffloor->top.model = ffloor->bottom.model = ffloor->model = sec2;
ffloor->target = sec;
if (!(flags&FF_THINFLOOR))
{
ffloor->bottom.plane = &sec2->floorplane;
ffloor->bottom.texture = &sec2->planes[sector_t::floor].Texture;
ffloor->bottom.texheight = &sec2->planes[sector_t::floor].TexZ;
ffloor->bottom.isceiling = false;
}
else
{
ffloor->bottom.plane = &sec2->ceilingplane;
ffloor->bottom.texture = &sec2->planes[sector_t::ceiling].Texture;
ffloor->bottom.texheight = &sec2->planes[sector_t::ceiling].TexZ;
ffloor->bottom.isceiling = true;
}
if (!(flags&FF_FIX))
{
ffloor->top.plane = &sec2->ceilingplane;
ffloor->top.texture = &sec2->planes[sector_t::ceiling].Texture;
ffloor->top.texheight = &sec2->planes[sector_t::ceiling].TexZ;
ffloor->toplightlevel = &sec2->lightlevel;
ffloor->top.isceiling = true;
}
else // FF_FIX is a special case to patch rendering holes
{
ffloor->top.plane = &sec->floorplane;
ffloor->top.texture = &sec2->planes[sector_t::floor].Texture;
ffloor->top.texheight = &sec2->planes[sector_t::floor].TexZ;
ffloor->toplightlevel = &sec->lightlevel;
ffloor->top.isceiling = false;
ffloor->top.model = sec;
}
// Hacks for Vavoom's idiotic implementation
if (flags&FF_INVERTSECTOR)
{
// switch the planes
F3DFloor::planeref sp = ffloor->top;
ffloor->top=ffloor->bottom;
ffloor->bottom=sp;
if (flags&FF_SWIMMABLE)
{
// Vavoom floods the lower part if it is swimmable.
// fortunately this plane won't be rendered - otherwise this wouldn't work...
ffloor->bottom.plane=&sec->floorplane;
ffloor->bottom.model=sec;
}
}
ffloor->flags = flags;
ffloor->master = master;
ffloor->alpha = transluc;
// The engine cannot handle sloped translucent floors. Sorry
if (ffloor->top.plane->a || ffloor->top.plane->b || ffloor->bottom.plane->a || ffloor->bottom.plane->b)
{
ffloor->alpha = FRACUNIT;
}
sec->e->XFloor.ffloors.Push(ffloor);
}
//==========================================================================
//
// Creates all 3D floors defined by one linedef
//
//==========================================================================
static int P_Set3DFloor(line_t * line, int param,int param2, int alpha)
{
int s,i;
int flags;
int tag=line->args[0];
sector_t * sec = line->frontsector, * ss;
for (s=-1; (s = P_FindSectorFromTag(tag,s)) >= 0;)
{
ss=&sectors[s];
if (param==0)
{
flags=FF_EXISTS|FF_RENDERALL|FF_SOLID|FF_INVERTSECTOR;
for (i=0;i<sec->linecount;i++)
{
line_t * l=sec->lines[i];
alpha=255;
if (l->special==Sector_SetContents && l->frontsector==sec)
{
alpha=clamp<int>(l->args[1], 0, 100);
if (l->args[2] & 1) flags &= ~FF_SOLID;
if (l->args[2] & 2) flags |= FF_SEETHROUGH;
if (l->args[2] & 4) flags |= FF_SHOOTTHROUGH;
if (l->args[2] & 8) flags |= FF_ADDITIVETRANS;
if (alpha!=100) flags|=FF_TRANSLUCENT;//|FF_BOTHPLANES|FF_ALLSIDES;
if (l->args[0])
{
// Yes, Vavoom's 3D-floor definitions suck!
static DWORD vavoomcolors[]={
0, 0x101080, 0x801010, 0x108010, 0x287020, 0xf0f010};
flags|=FF_SWIMMABLE|FF_BOTHPLANES|FF_ALLSIDES|FF_FLOOD;
l->frontsector->ColorMap = GetSpecialLights (l->frontsector->ColorMap->Color,
vavoomcolors[l->args[0]],
l->frontsector->ColorMap->Desaturate);
}
alpha=(alpha*255)/100;
break;
}
}
}
else if (param==4)
{
flags=FF_EXISTS|FF_RENDERPLANES|FF_INVERTPLANES|FF_NOSHADE|FF_FIX;
alpha=255;
}
else
{
static const int defflags[]= {0,
FF_SOLID,
FF_SWIMMABLE|FF_BOTHPLANES|FF_ALLSIDES|FF_SHOOTTHROUGH|FF_SEETHROUGH,
FF_SHOOTTHROUGH|FF_SEETHROUGH,
};
flags = defflags[param&3] | FF_EXISTS|FF_RENDERALL;
if (param&4) flags |= FF_ALLSIDES|FF_BOTHPLANES;
if (param&16) flags ^= FF_SEETHROUGH;
if (param&32) flags ^= FF_SHOOTTHROUGH;
if (param2&1) flags |= FF_NOSHADE;
if (param2&2) flags |= FF_DOUBLESHADOW;
if (param2&4) flags |= FF_FOG;
if (param2&8) flags |= FF_THINFLOOR;
if (param2&16) flags |= FF_UPPERTEXTURE;
if (param2&32) flags |= FF_LOWERTEXTURE;
if (param2&64) flags |= FF_ADDITIVETRANS|FF_TRANSLUCENT;
// if flooding is used the floor must be non-solid and is automatically made shootthrough and seethrough
if ((param2&128) && !(flags & FF_SOLID)) flags |= FF_FLOOD|FF_SEETHROUGH|FF_SHOOTTHROUGH;
if (param2&512) flags |= FF_FADEWALLS;
FTextureID tex = sides[line->sidenum[0]].GetTexture(side_t::top);
if (!tex.Exists() && alpha<255)
{
alpha=clamp(-tex.GetIndex(), 0, 255);
}
if (alpha==0) flags&=~(FF_RENDERALL|FF_BOTHPLANES|FF_ALLSIDES);
else if (alpha!=255) flags|=FF_TRANSLUCENT;
}
P_Add3DFloor(ss, sec, line, flags, alpha);
}
// To be 100% safe this should be done even if the alpha by texture value isn't used.
if (!sides[line->sidenum[0]].GetTexture(side_t::top).isValid())
sides[line->sidenum[0]].SetTexture(side_t::top, FNullTextureID());
return 1;
}
//==========================================================================
//
// P_PlayerOnSpecial3DFloor
// Checks to see if a player is standing on or is inside a 3D floor (water)
// and applies any specials..
//
//==========================================================================
void P_PlayerOnSpecial3DFloor(player_t* player)
{
sector_t * sector = player->mo->Sector;
for(unsigned i=0;i<sector->e->XFloor.ffloors.Size();i++)
{
F3DFloor* rover=sector->e->XFloor.ffloors[i];
if (!(rover->flags & FF_EXISTS)) continue;
if (rover->flags & FF_FIX) continue;
// Check the 3D floor's type...
if(rover->flags & FF_SOLID)
{
// Player must be on top of the floor to be affected...
if(player->mo->z != rover->top.plane->ZatPoint(player->mo->x, player->mo->y)) continue;
}
else
{
//Water and DEATH FOG!!! heh
if (player->mo->z > rover->top.plane->ZatPoint(player->mo->x, player->mo->y) ||
(player->mo->z + player->mo->height) < rover->bottom.plane->ZatPoint(player->mo->x, player->mo->y))
continue;
}
if (rover->model->special || rover->model->damage) P_PlayerInSpecialSector(player, rover->model);
break;
}
}
//==========================================================================
//
// P_CheckFor3DFloorHit
// Checks whether the player's feet touch a solid 3D floor in the sector
//
//==========================================================================
bool P_CheckFor3DFloorHit(AActor * mo)
{
sector_t * sector = mo->Sector;
if ((mo->player && (mo->player->cheats & CF_PREDICTING))) return false;
for(unsigned i=0;i<sector->e->XFloor.ffloors.Size();i++)
{
F3DFloor* rover=sector->e->XFloor.ffloors[i];
if (!(rover->flags & FF_EXISTS)) continue;
if(rover->flags & FF_SOLID && rover->model->SecActTarget)
{
if(mo->z == rover->top.plane->ZatPoint(mo->x, mo->y))
{
rover->model->SecActTarget->TriggerAction (mo, SECSPAC_HitFloor);
return true;
}
}
}
return false;
}
//==========================================================================
//
// P_CheckFor3DCeilingHit
// Checks whether the player's head touches a solid 3D floor in the sector
//
//==========================================================================
bool P_CheckFor3DCeilingHit(AActor * mo)
{
sector_t * sector = mo->Sector;
if ((mo->player && (mo->player->cheats & CF_PREDICTING))) return false;
for(unsigned i=0;i<sector->e->XFloor.ffloors.Size();i++)
{
F3DFloor* rover=sector->e->XFloor.ffloors[i];
if (!(rover->flags & FF_EXISTS)) continue;
if(rover->flags & FF_SOLID && rover->model->SecActTarget)
{
if(mo->z+mo->height == rover->bottom.plane->ZatPoint(mo->x, mo->y))
{
rover->model->SecActTarget->TriggerAction (mo, SECSPAC_HitCeiling);
return true;
}
}
}
return false;
}
//==========================================================================
//
// P_Recalculate3DFloors
//
// This function sorts the ffloors by height and creates the lightlists
// that the given sector uses to light floors/ceilings/walls according to the 3D floors.
//
//==========================================================================
#define CenterSpot(sec) (vertex_t*)&(sec)->soundorg[0]
void P_Recalculate3DFloors(sector_t * sector)
{
F3DFloor * rover;
F3DFloor * pick;
unsigned pickindex;
F3DFloor * clipped=NULL;
fixed_t clipped_top;
fixed_t clipped_bottom=0;
fixed_t maxheight, minheight;
unsigned i, j;
lightlist_t newlight;
TArray<F3DFloor*> & ffloors=sector->e->XFloor.ffloors;
TArray<lightlist_t> & lightlist = sector->e->XFloor.lightlist;
// Sort the floors top to bottom for quicker access here and later
// Translucent and swimmable floors are split if they overlap with solid ones.
if (ffloors.Size()>1)
{
TArray<F3DFloor*> oldlist;
oldlist = ffloors;
ffloors.Clear();
// first delete the old dynamic stuff
for(i=0;i<oldlist.Size();i++)
{
F3DFloor * rover=oldlist[i];
if (rover->flags&FF_DYNAMIC)
{
delete rover;
oldlist.Delete(i);
i--;
continue;
}
if (rover->flags&FF_CLIPPED)
{
rover->flags&=~FF_CLIPPED;
rover->flags|=FF_EXISTS;
}
}
while (oldlist.Size())
{
pick=oldlist[0];
fixed_t height=pick->top.plane->ZatPoint(CenterSpot(sector));
// find highest starting ffloor - intersections are not supported!
pickindex=0;
for (j=1;j<oldlist.Size();j++)
{
fixed_t h2=oldlist[j]->top.plane->ZatPoint(CenterSpot(sector));
if (h2>height)
{
pick=oldlist[j];
pickindex=j;
height=h2;
}
}
oldlist.Delete(pickindex);
if (pick->flags&(FF_SWIMMABLE|FF_TRANSLUCENT) && pick->flags&FF_EXISTS)
{
clipped=pick;
clipped_top=height;
clipped_bottom=pick->bottom.plane->ZatPoint(CenterSpot(sector));
ffloors.Push(pick);
}
else if (clipped && clipped_bottom<height)
{
// translucent floor above must be clipped to this one!
F3DFloor * dyn=new F3DFloor;
*dyn=*clipped;
clipped->flags|=FF_CLIPPED;
clipped->flags&=~FF_EXISTS;
dyn->flags|=FF_DYNAMIC;
dyn->bottom=pick->top;
ffloors.Push(dyn);
ffloors.Push(pick);
fixed_t pick_bottom=pick->bottom.plane->ZatPoint(CenterSpot(sector));
if (pick_bottom<=clipped_bottom)
{
clipped=NULL;
}
else
{
// the translucent part extends below the clipper
dyn=new F3DFloor;
*dyn=*clipped;
dyn->flags|=FF_DYNAMIC|FF_EXISTS;
dyn->top=pick->bottom;
ffloors.Push(dyn);
}
}
else
{
clipped=NULL;
ffloors.Push(pick);
}
}
}
// having the floors sorted makes this routine significantly simpler
// Only some overlapping cases with FF_DOUBLESHADOW might create anomalies
// but these are clearly undefined.
if(ffloors.Size())
{
lightlist.Resize(1);
lightlist[0].plane = sector->ceilingplane;
lightlist[0].p_lightlevel = &sector->lightlevel;
lightlist[0].caster = NULL;
lightlist[0].p_extra_colormap = &sector->ColorMap;
lightlist[0].flags = 0;
maxheight = sector->CenterCeiling();
minheight = sector->CenterFloor();
for(i = 0; i < ffloors.Size(); i++)
{
rover=ffloors[i];
if ( !(rover->flags & FF_EXISTS) || rover->flags & FF_NOSHADE )
continue;
fixed_t ff_top=rover->top.plane->ZatPoint(CenterSpot(sector));
if (ff_top < minheight) break; // reached the floor
if (ff_top < maxheight)
{
newlight.plane = *rover->top.plane;
newlight.p_lightlevel = rover->toplightlevel;
newlight.caster = rover;
newlight.p_extra_colormap=&rover->model->ColorMap;
newlight.flags = rover->flags;
lightlist.Push(newlight);
}
else if (i==0)
{
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(CenterSpot(sector));
if (ff_bottom<maxheight)
{
// this segment begins over the ceiling and extends beyond it
lightlist[0].p_lightlevel = rover->toplightlevel;
lightlist[0].caster = rover;
lightlist[0].p_extra_colormap=&rover->model->ColorMap;
lightlist[0].flags = rover->flags;
}
}
if (rover->flags&FF_DOUBLESHADOW)
{
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(CenterSpot(sector));
if(ff_bottom < maxheight && ff_bottom>minheight)
{
newlight.caster = rover;
newlight.plane = *rover->bottom.plane;
if (lightlist.Size()>1)
{
newlight.p_lightlevel = lightlist[lightlist.Size()-2].p_lightlevel;
newlight.p_extra_colormap = lightlist[lightlist.Size()-2].p_extra_colormap;
}
else
{
newlight.p_lightlevel = &sector->lightlevel;
newlight.p_extra_colormap = &sector->ColorMap;
}
newlight.flags = rover->flags;
lightlist.Push(newlight);
}
}
}
}
}
void P_RecalculateAttached3DFloors(sector_t * sec)
{
extsector_t::xfloor &x = sec->e->XFloor;
for(unsigned int i=0; i<x.attached.Size(); i++)
{
P_Recalculate3DFloors(x.attached[i]);
}
P_Recalculate3DFloors(sec);
}
//==========================================================================
//
//
//
//==========================================================================
lightlist_t * P_GetPlaneLight(sector_t * sector, secplane_t * plane, bool underside)
{
unsigned i;
TArray<lightlist_t> &lightlist = sector->e->XFloor.lightlist;
fixed_t planeheight=plane->ZatPoint(CenterSpot(sector));
if(underside) planeheight--;
for(i = 1; i < lightlist.Size(); i++)
if (lightlist[i].plane.ZatPoint(CenterSpot(sector)) <= planeheight)
return &lightlist[i - 1];
return &lightlist[lightlist.Size() - 1];
}
//==========================================================================
//
// Extended P_LineOpening
//
//==========================================================================
void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *linedef,
fixed_t x, fixed_t y, fixed_t refx, fixed_t refy)
{
if(thing)
{
fixed_t thingbot, thingtop;
thingbot = thing->z;
thingtop = thingbot + thing->height;
extsector_t::xfloor *xf[2] = {&linedef->frontsector->e->XFloor, &linedef->backsector->e->XFloor};
// Check for 3D-floors in the sector (mostly identical to what Legacy does here)
if(xf[0]->ffloors.Size() || xf[1]->ffloors.Size())
{
fixed_t lowestceiling = open.top;
fixed_t highestfloor = open.bottom;
fixed_t lowestfloor[2] = {
linedef->frontsector->floorplane.ZatPoint(x, y),
linedef->backsector->floorplane.ZatPoint(x, y) };
FTextureID highestfloorpic;
FTextureID lowestceilingpic;
highestfloorpic.SetInvalid();
lowestceilingpic.SetInvalid();
thingtop = thing->z + (thing->height==0? 1:thing->height);
for(int j=0;j<2;j++)
{
// Check for frontsector's 3D-floors
for(unsigned i=0;i<xf[j]->ffloors.Size();i++)
{
F3DFloor *rover = xf[j]->ffloors[i];
if (!(rover->flags&FF_EXISTS)) continue;
if (!(rover->flags & FF_SOLID)) continue;
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(x, y);
fixed_t ff_top=rover->top.plane->ZatPoint(x, y);
fixed_t delta1 = abs(thingbot - ((ff_bottom + ff_top) / 2));
fixed_t delta2 = abs(thingtop - ((ff_bottom + ff_top) / 2));
if(ff_bottom < lowestceiling && delta1 >= delta2)
{
lowestceiling = ff_bottom;
lowestceilingpic = *rover->bottom.texture;
}
if(ff_top > highestfloor && delta1 < delta2)
{
highestfloor = ff_top;
highestfloorpic = *rover->top.texture;
}
if(ff_top > lowestfloor[j] && ff_top <= thing->z) lowestfloor[j] = ff_top;
}
}
if(highestfloor > open.bottom)
{
open.bottom = highestfloor;
open.floorpic = highestfloorpic;
}
if(lowestceiling < open.top)
{
open.top = lowestceiling;
open.ceilingpic = lowestceilingpic;
}
open.lowfloor = MIN(lowestfloor[0], lowestfloor[1]);
}
}
}
//==========================================================================
//
// Spawns 3D floors
//
//==========================================================================
void P_Spawn3DFloors (void)
{
static int flagvals[] = {128+512, 2+512, 512};
int i;
line_t * line;
for (i=0,line=lines;i<numlines;i++,line++)
{
switch(line->special)
{
case ExtraFloor_LightOnly:
// Note: I am spawning both this and ZDoom's ExtraLight data
// I don't want to mess with both at the same time during rendering
// so inserting this into the 3D-floor table as well seemed to be
// the best option.
//
// This does not yet handle case 0 properly!
if (line->args[1] < 0 || line->args[1] > 2) line->args[1] = 0;
P_Set3DFloor(line, 3, flagvals[line->args[1]], 0);
break;
case Sector_Set3DFloor:
if (line->args[1]&8)
{
line->id = line->args[4];
}
else
{
line->args[0]+=256*line->args[4];
line->args[4]=0;
}
P_Set3DFloor(line, line->args[1]&~8, line->args[2], line->args[3]);
break;
default:
continue;
}
line->special=0;
line->args[0] = line->args[1] = line->args[2] = line->args[3] = line->args[4] = 0;
}
}
#endif

138
src/p_3dfloors.h Normal file
View file

@ -0,0 +1,138 @@
#ifndef __SECTORE_H
#define __SECTORE_H
//#define _3DFLOORS
#ifdef _3DFLOORS
// 3D floor flags. Most are the same as in Legacy but I added some for EDGE's and Vavoom's features as well.
typedef enum
{
FF_EXISTS = 0x1, //MAKE SURE IT'S VALID
FF_SOLID = 0x2, //Does it clip things?
FF_RENDERSIDES = 0x4, //Render the sides?
FF_RENDERPLANES = 0x8, //Render the floor/ceiling?
FF_RENDERALL = 0xC, //Render everything?
FF_SWIMMABLE = 0x10, //Can we swim?
FF_NOSHADE = 0x20, //Does it mess with the lighting?
FF_BOTHPLANES = 0x200, //Render both planes all the time?
FF_TRANSLUCENT = 0x800, //See through!
FF_FOG = 0x1000, //Fog "brush"?
FF_INVERTPLANES = 0x2000, //Reverse the plane visibility rules?
FF_ALLSIDES = 0x4000, //Render inside and outside sides?
FF_INVERTSIDES = 0x8000, //Only render inside sides?
FF_DOUBLESHADOW = 0x10000,//Make two lightlist entries to reset light?
FF_UPPERTEXTURE = 0x20000,
FF_LOWERTEXTURE = 0x40000,
FF_THINFLOOR = 0x80000, // EDGE
FF_SCROLLY = 0x100000, // EDGE - not yet implemented!!!
FF_FIX = 0x200000, // use floor of model sector as floor and floor of real sector as ceiling
FF_INVERTSECTOR = 0x400000, // swap meaning of sector planes
FF_DYNAMIC = 0x800000, // created by partitioning another 3D-floor due to overlap
FF_CLIPPED = 0x1000000, // split into several dynamic ffloors
FF_SEETHROUGH = 0x2000000,
FF_SHOOTTHROUGH = 0x4000000,
FF_FADEWALLS = 0x8000000, // Applies real fog to walls and doesn't blend the view
FF_ADDITIVETRANS = 0x10000000, // Render this floor with additive translucency
FF_FLOOD = 0x20000000, // extends towards the next lowest flooding or solid 3D floor or the bottom of the sector
} ffloortype_e;
struct secplane_t;
struct F3DFloor
{
struct planeref
{
secplane_t * plane;
const FTextureID * texture;
const fixed_t * texheight;
sector_t * model;
bool isceiling;
};
planeref bottom;
planeref top;
unsigned char *toplightlevel;
fixed_t delta;
int flags;
line_t* master;
sector_t * model;
sector_t * target;
int lastlight;
int alpha;
};
struct FDynamicColormap;
struct lightlist_t
{
secplane_t plane;
unsigned char * p_lightlevel;
FDynamicColormap ** p_extra_colormap;
int flags;
F3DFloor* caster;
};
class player_s;
void P_PlayerOnSpecial3DFloor(player_t* player);
void P_Get3DFloorAndCeiling(AActor * thing, sector_t * sector, fixed_t * floorz, fixed_t * ceilingz, int * floorpic);
bool P_CheckFor3DFloorHit(AActor * mo);
bool P_CheckFor3DCeilingHit(AActor * mo);
void P_Recalculate3DFloors(sector_t *);
void P_RecalculateAttached3DFloors(sector_t * sec);
lightlist_t * P_GetPlaneLight(sector_t * , secplane_t * plane, bool underside);
void P_Spawn3DFloors( void );
struct FLineOpening;
void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *linedef,
fixed_t x, fixed_t y, fixed_t refx, fixed_t refy);
#else
// Dummy definitions for disabled 3D floor code
struct F3DFloor
{
int dummy;
};
struct lightlist_t
{
int dummy;
};
class player_s;
inline void P_PlayerOnSpecial3DFloor(player_t* player) {}
inline void P_Get3DFloorAndCeiling(AActor * thing, sector_t * sector, fixed_t * floorz, fixed_t * ceilingz, int * floorpic) {}
inline bool P_CheckFor3DFloorHit(AActor * mo) { return false; }
inline bool P_CheckFor3DCeilingHit(AActor * mo) { return false; }
inline void P_Recalculate3DFloors(sector_t *) {}
inline void P_RecalculateAttached3DFloors(sector_t * sec) {}
inline lightlist_t * P_GetPlaneLight(sector_t * , secplane_t * plane, bool underside) { return NULL; }
inline void P_Spawn3DFloors( void ) {}
struct FLineOpening;
inline void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *linedef,
fixed_t x, fixed_t y, fixed_t refx, fixed_t refy) {}
#endif
#endif

View file

@ -366,8 +366,8 @@ bool P_CheckPosition (AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm);
bool P_CheckPosition (AActor *thing, fixed_t x, fixed_t y); bool P_CheckPosition (AActor *thing, fixed_t x, fixed_t y);
AActor *P_CheckOnmobj (AActor *thing); AActor *P_CheckOnmobj (AActor *thing);
void P_FakeZMovement (AActor *mo); void P_FakeZMovement (AActor *mo);
bool P_TryMove (AActor* thing, fixed_t x, fixed_t y, bool dropoff, bool onfloor, FCheckPosition &tm); bool P_TryMove (AActor* thing, fixed_t x, fixed_t y, bool dropoff, const secplane_t * onfloor, FCheckPosition &tm);
bool P_TryMove (AActor* thing, fixed_t x, fixed_t y, bool dropoff, bool onfloor = false); bool P_TryMove (AActor* thing, fixed_t x, fixed_t y, bool dropoff, const secplane_t * onfloor = NULL);
bool P_TeleportMove (AActor* thing, fixed_t x, fixed_t y, fixed_t z, bool telefrag); // [RH] Added z and telefrag parameters bool P_TeleportMove (AActor* thing, fixed_t x, fixed_t y, fixed_t z, bool telefrag); // [RH] Added z and telefrag parameters
void P_PlayerStartStomp (AActor *actor); // [RH] Stomp on things for a newly spawned player void P_PlayerStartStomp (AActor *actor); // [RH] Stomp on things for a newly spawned player
void P_SlideMove (AActor* mo, fixed_t tryx, fixed_t tryy, int numsteps); void P_SlideMove (AActor* mo, fixed_t tryx, fixed_t tryy, int numsteps);
@ -407,7 +407,7 @@ int P_GetFriction(const AActor *mo, int *frictionfactor);
bool Check_Sides(AActor *, int, int); // phares bool Check_Sides(AActor *, int, int); // phares
// [RH] // [RH]
bool P_CheckSlopeWalk (AActor *actor, fixed_t &xmove, fixed_t &ymove); const secplane_t * P_CheckSlopeWalk (AActor *actor, fixed_t &xmove, fixed_t &ymove);
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// //

View file

@ -106,10 +106,11 @@ static bool PIT_FindFloorCeiling (line_t *ld, const FBoundingBox &box, FCheckPos
FLineOpening open; FLineOpening open;
// set openrange, opentop, openbottom // set openrange, opentop, openbottom
if (((ld->frontsector->floorplane.a | ld->frontsector->floorplane.b) | if ((((ld->frontsector->floorplane.a | ld->frontsector->floorplane.b) |
(ld->backsector->floorplane.a | ld->backsector->floorplane.b) | (ld->backsector->floorplane.a | ld->backsector->floorplane.b) |
(ld->frontsector->ceilingplane.a | ld->frontsector->ceilingplane.b) | (ld->frontsector->ceilingplane.a | ld->frontsector->ceilingplane.b) |
(ld->backsector->ceilingplane.a | ld->backsector->ceilingplane.b)) == 0) (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); P_LineOpening (open, tmf.thing, ld, sx=tmf.x, sy=tmf.y, tmf.x, tmf.y);
} }
@ -165,7 +166,7 @@ static bool PIT_FindFloorCeiling (line_t *ld, const FBoundingBox &box, FCheckPos
// //
//========================================================================== //==========================================================================
void P_FindFloorCeiling (AActor *actor, bool onlymidtex) void P_FindFloorCeiling (AActor *actor, bool onlyspawnpos)
{ {
sector_t *sec; sector_t *sec;
FCheckPosition tmf; FCheckPosition tmf;
@ -196,7 +197,7 @@ void P_FindFloorCeiling (AActor *actor, bool onlymidtex)
if (tmf.touchmidtex) tmf.dropoffz = tmf.floorz; if (tmf.touchmidtex) tmf.dropoffz = tmf.floorz;
if (!onlymidtex || (tmf.touchmidtex && (tmf.floorz <= actor->z))) if (!onlyspawnpos || (tmf.touchmidtex && (tmf.floorz <= actor->z)))
{ {
actor->floorz = tmf.floorz; actor->floorz = tmf.floorz;
actor->dropoffz = tmf.dropoffz; actor->dropoffz = tmf.dropoffz;
@ -206,6 +207,28 @@ void P_FindFloorCeiling (AActor *actor, bool onlymidtex)
actor->ceilingpic = tmf.ceilingpic; actor->ceilingpic = tmf.ceilingpic;
actor->ceilingsector = tmf.ceilingsector; actor->ceilingsector = tmf.ceilingsector;
} }
#ifdef _3DFLOORS
// also check 3D floors at the spawn position if the result from the block lines iterator cannot be used.
if (onlyspawnpos)
{
for(unsigned int i=0;i<actor->Sector->e->XFloor.ffloors.Size();i++)
{
F3DFloor* rover=actor->Sector->e->XFloor.ffloors[i];
if (!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue;
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(actor->x, actor->y);
fixed_t ff_top=rover->top.plane->ZatPoint(actor->x, actor->y);
fixed_t delta1 = actor->z - (ff_bottom + ((ff_top-ff_bottom)/2));
fixed_t delta2 = actor->z + (actor->height? actor->height:1) - (ff_bottom + ((ff_top-ff_bottom)/2));
if (ff_top > actor->floorz && abs(delta1) < abs(delta2)) actor->floorz = ff_top;
if (ff_bottom < actor->ceilingz && abs(delta1) >= abs(delta2)) actor->ceilingz = ff_bottom;
}
}
#endif
} }
// //
@ -406,6 +429,26 @@ int P_GetFriction (const AActor *mo, int *frictionfactor)
for (m = mo->touching_sectorlist; m; m = m->m_tnext) for (m = mo->touching_sectorlist; m; m = m->m_tnext)
{ {
sec = m->m_sector; sec = m->m_sector;
#ifdef _3DFLOORS
// 3D floors must be checked, too
for(unsigned i=0;i<sec->e->XFloor.ffloors.Size();i++)
{
F3DFloor * rover=sec->e->XFloor.ffloors[i];
if (!(rover->flags&FF_EXISTS)) continue;
if(!(rover->flags & FF_SOLID)) continue;
// Player must be on top of the floor to be affected...
if(mo->z != rover->top.plane->ZatPoint(mo->x,mo->y)) continue;
fixed_t newfriction=secfriction(rover->model);
if (newfriction<friction)
{
friction = newfriction;
movefactor = secmovefac(rover->model);
}
}
#endif
if (!(sec->special & FRICTION_MASK) && if (!(sec->special & FRICTION_MASK) &&
Terrains[TerrainTypes[sec->GetTexture(sector_t::floor)]].Friction == 0) Terrains[TerrainTypes[sec->GetTexture(sector_t::floor)]].Friction == 0)
{ {
@ -559,10 +602,11 @@ bool PIT_CheckLine (line_t *ld, const FBoundingBox &box, FCheckPosition &tm)
FLineOpening open; FLineOpening open;
// set openrange, opentop, openbottom // set openrange, opentop, openbottom
if (((ld->frontsector->floorplane.a | ld->frontsector->floorplane.b) | if ((((ld->frontsector->floorplane.a | ld->frontsector->floorplane.b) |
(ld->backsector->floorplane.a | ld->backsector->floorplane.b) | (ld->backsector->floorplane.a | ld->backsector->floorplane.b) |
(ld->frontsector->ceilingplane.a | ld->frontsector->ceilingplane.b) | (ld->frontsector->ceilingplane.a | ld->frontsector->ceilingplane.b) |
(ld->backsector->ceilingplane.a | ld->backsector->ceilingplane.b)) == 0) (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, tm.thing, ld, sx=tm.x, sy=tm.y, tm.x, tm.y); P_LineOpening (open, tm.thing, ld, sx=tm.x, sy=tm.y, tm.x, tm.y);
} }
@ -596,6 +640,15 @@ bool PIT_CheckLine (line_t *ld, const FBoundingBox &box, FCheckPosition &tm)
P_LineOpening (open, tm.thing, ld, sx=ld->v1->x + MulScale24 (r, ld->dx), 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); 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.bottom=INT_MIN;
}
/* Printf (" %d %d %d\n", sx, sy, openbottom);*/ /* Printf (" %d %d %d\n", sx, sy, openbottom);*/
} }
@ -1049,6 +1102,39 @@ bool P_CheckPosition (AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm)
//Added by MC: Fill the tmsector. //Added by MC: Fill the tmsector.
tm.sector = newsec; tm.sector = newsec;
#ifdef _3DFLOORS
//Check 3D floors
if(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;
}
if(ff_bottom < tm.ceilingz && abs(delta1) >= abs(delta2))
{
tm.ceilingz = ff_bottom;
tm.ceilingpic = *rover->bottom.texture;
}
}
}
#endif
validcount++; validcount++;
spechit.Clear (); spechit.Clear ();
@ -1335,7 +1421,7 @@ static void CheckForPushSpecial (line_t *line, int side, AActor *mobj)
// //
bool P_TryMove (AActor *thing, fixed_t x, fixed_t y, bool P_TryMove (AActor *thing, fixed_t x, fixed_t y,
bool dropoff, // killough 3/15/98: allow dropoff as option bool dropoff, // killough 3/15/98: allow dropoff as option
bool onfloor, // [RH] Let P_TryMove keep the thing on the floor const secplane_t *onfloor, // [RH] Let P_TryMove keep the thing on the floor
FCheckPosition &tm) FCheckPosition &tm)
{ {
fixed_t oldx; fixed_t oldx;
@ -1351,7 +1437,7 @@ bool P_TryMove (AActor *thing, fixed_t x, fixed_t y,
oldz = thing->z; oldz = thing->z;
if (onfloor) if (onfloor)
{ {
thing->z = thing->floorsector->floorplane.ZatPoint (x, y); thing->z = onfloor->ZatPoint (x, y);
} }
if (!P_CheckPosition (thing, x, y, tm)) if (!P_CheckPosition (thing, x, y, tm))
{ {
@ -1679,7 +1765,7 @@ pushline:
bool P_TryMove (AActor *thing, fixed_t x, fixed_t y, bool P_TryMove (AActor *thing, fixed_t x, fixed_t y,
bool dropoff, // killough 3/15/98: allow dropoff as option bool dropoff, // killough 3/15/98: allow dropoff as option
bool onfloor) // [RH] Let P_TryMove keep the thing on the floor const secplane_t *onfloor) // [RH] Let P_TryMove keep the thing on the floor
{ {
FCheckPosition tm; FCheckPosition tm;
return P_TryMove(thing, x, y, dropoff, onfloor, tm); return P_TryMove(thing, x, y, dropoff, onfloor, tm);
@ -1959,7 +2045,7 @@ void FSlide::SlideMove (AActor *mo, fixed_t tryx, fixed_t tryy, int numsteps)
fixed_t trailx, traily; fixed_t trailx, traily;
fixed_t newx, newy; fixed_t newx, newy;
fixed_t xmove, ymove; fixed_t xmove, ymove;
bool walkplane; const secplane_t * walkplane;
int hitcount; int hitcount;
hitcount = 3; hitcount = 3;
@ -2075,26 +2161,64 @@ void P_SlideMove (AActor *mo, fixed_t tryx, fixed_t tryy, int numsteps)
// //
//============================================================================ //============================================================================
bool P_CheckSlopeWalk (AActor *actor, fixed_t &xmove, fixed_t &ymove) const secplane_t * P_CheckSlopeWalk (AActor *actor, fixed_t &xmove, fixed_t &ymove)
{ {
static secplane_t copyplane;
if (actor->flags & MF_NOGRAVITY) if (actor->flags & MF_NOGRAVITY)
{ {
return false; return NULL;
} }
const secplane_t *plane = &actor->floorsector->floorplane; const secplane_t *plane = &actor->floorsector->floorplane;
fixed_t planezhere = plane->ZatPoint (actor->x, actor->y); fixed_t planezhere = plane->ZatPoint (actor->x, actor->y);
#ifdef _3DFLOORS
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->x, actor->y);
if (thisplanez>planezhere && thisplanez<=actor->z + actor->MaxStepHeight)
{
copyplane = *rover->top.plane;
if (copyplane.c<0) copyplane.FlipVert();
plane = &copyplane;
planezhere=thisplanez;
}
}
if (actor->floorsector != actor->Sector)
{
for(unsigned int i=0;i<actor->Sector->e->XFloor.ffloors.Size();i++)
{
F3DFloor * rover= actor->Sector->e->XFloor.ffloors[i];
if(!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue;
fixed_t thisplanez = rover->top.plane->ZatPoint(actor->x, actor->y);
if (thisplanez>planezhere && thisplanez<=actor->z + actor->MaxStepHeight)
{
copyplane = *rover->top.plane;
if (copyplane.c<0) copyplane.FlipVert();
plane = &copyplane;
planezhere=thisplanez;
}
}
}
#endif
if (actor->floorsector != actor->Sector) if (actor->floorsector != actor->Sector)
{ {
// this additional check prevents sliding on sloped dropoffs // this additional check prevents sliding on sloped dropoffs
if (planezhere>actor->floorz+4*FRACUNIT) if (planezhere>actor->floorz+4*FRACUNIT)
return false; return NULL;
} }
if (actor->z - planezhere > FRACUNIT) if (actor->z - planezhere > FRACUNIT)
{ // not on floor { // not on floor
return false; return NULL;
} }
if ((plane->a | plane->b) != 0) if ((plane->a | plane->b) != 0)
@ -2112,7 +2236,7 @@ bool P_CheckSlopeWalk (AActor *actor, fixed_t &xmove, fixed_t &ymove)
{ // Can't climb up slopes of ~45 degrees or more { // Can't climb up slopes of ~45 degrees or more
if (actor->flags & MF_NOCLIP) if (actor->flags & MF_NOCLIP)
{ {
return (actor->floorsector == actor->Sector); return (actor->floorsector == actor->Sector) ? plane : NULL;
} }
else else
{ {
@ -2139,7 +2263,7 @@ bool P_CheckSlopeWalk (AActor *actor, fixed_t &xmove, fixed_t &ymove)
xmove = actor->momx = plane->a * 2; xmove = actor->momx = plane->a * 2;
ymove = actor->momy = plane->b * 2; ymove = actor->momy = plane->b * 2;
} }
return false; return (actor->floorsector == actor->Sector) ? plane : NULL;
} }
} }
// Slide the desired location along the plane's normal // Slide the desired location along the plane's normal
@ -2148,7 +2272,7 @@ bool P_CheckSlopeWalk (AActor *actor, fixed_t &xmove, fixed_t &ymove)
desty -= FixedMul (plane->b, t); desty -= FixedMul (plane->b, t);
xmove = destx - actor->x; xmove = destx - actor->x;
ymove = desty - actor->y; ymove = desty - actor->y;
return (actor->floorsector == actor->Sector); return (actor->floorsector == actor->Sector) ? plane : NULL;
} }
else if (t > 0) else if (t > 0)
{ // Desired location is in front of (above) the plane { // Desired location is in front of (above) the plane
@ -2159,11 +2283,11 @@ bool P_CheckSlopeWalk (AActor *actor, fixed_t &xmove, fixed_t &ymove)
desty += FixedMul (plane->b, t); desty += FixedMul (plane->b, t);
xmove = destx - actor->x; xmove = destx - actor->x;
ymove = desty - actor->y; ymove = desty - actor->y;
return (actor->floorsector == actor->Sector);//(plane->c >= STEEPSLOPE); return (actor->floorsector == actor->Sector) ? plane : NULL;
} }
} }
} }
return false; return NULL;
} }
//============================================================================ //============================================================================
@ -2360,11 +2484,126 @@ struct aim_t
angle_t pitch_friend, pitch_other; angle_t pitch_friend, pitch_other;
bool notsmart; bool notsmart;
bool check3d; bool check3d;
#ifdef _3DFLOORS
sector_t * lastsector;
secplane_t * lastfloorplane;
secplane_t * lastceilingplane;
bool crossedffloors;
bool AimTraverse3DFloors(const divline_t &trace, intercept_t * in);
#endif
void AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy); void AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy);
}; };
#ifdef _3DFLOORS
//============================================================================
//
// AimTraverse3DFloors
//
//============================================================================
bool aim_t::AimTraverse3DFloors(const divline_t &trace, intercept_t * in)
{
sector_t * nextsector;
secplane_t * nexttopplane, * nextbottomplane;
line_t * li=in->d.line;
nextsector=NULL;
nexttopplane=nextbottomplane=NULL;
if(li->frontsector->e->XFloor.ffloors.Size() || li->backsector->e->XFloor.ffloors.Size())
{
int frontflag;
F3DFloor* rover;
int highpitch, lowpitch;
fixed_t trX = trace.x + FixedMul (trace.dx, in->frac);
fixed_t trY = trace.y + FixedMul (trace.dy, in->frac);
fixed_t dist = FixedMul (attackrange, in->frac);
int dir = aimpitch < 0 ? 1 : aimpitch > 0 ? -1 : 0;
frontflag = P_PointOnLineSide(shootthing->x, shootthing->y, li);
// 3D floor check. This is not 100% accurate but normally sufficient when
// combined with a final sight check
for(int i=1;i<=2;i++)
{
sector_t * s=i==1? li->frontsector:li->backsector;
for(unsigned k=0;k<s->e->XFloor.ffloors.Size();k++)
{
crossedffloors=true;
rover=s->e->XFloor.ffloors[k];
if((rover->flags & FF_SHOOTTHROUGH) || !(rover->flags & FF_EXISTS)) continue;
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(trX, trY);
fixed_t ff_top=rover->top.plane->ZatPoint(trX, trY);
highpitch = -(int)R_PointToAngle2 (0, shootz, dist, ff_top);
lowpitch = -(int)R_PointToAngle2 (0, shootz, dist, ff_bottom);
if (highpitch<=toppitch)
{
// blocks completely
if (lowpitch>=bottompitch) return false;
// blocks upper edge of view
if (lowpitch>toppitch)
{
toppitch=lowpitch;
if (frontflag!=i-1)
{
nexttopplane=rover->bottom.plane;
}
}
}
else if (lowpitch>=bottompitch)
{
// blocks lower edge of view
if (highpitch<bottompitch)
{
bottompitch=highpitch;
if (frontflag!=i-1)
{
nextbottomplane=rover->top.plane;
}
}
}
// trace is leaving a sector with a 3d-floor
if (frontflag==i-1)
{
if (s==lastsector)
{
// upper slope intersects with this 3d-floor
if (rover->bottom.plane==lastceilingplane && lowpitch > toppitch)
{
toppitch=lowpitch;
}
// lower slope intersects with this 3d-floor
if (rover->top.plane==lastfloorplane && highpitch < bottompitch)
{
bottompitch=highpitch;
}
}
}
if (toppitch >= bottompitch) return false; // stop
}
}
}
lastsector=nextsector;
lastceilingplane=nexttopplane;
lastfloorplane=nextbottomplane;
return true;
}
#endif
//============================================================================ //============================================================================
// //
// PTR_AimTraverse // PTR_AimTraverse
@ -2416,6 +2655,9 @@ void aim_t::AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t e
if (toppitch >= bottompitch) if (toppitch >= bottompitch)
return; // stop return; // stop
#ifdef _3DFLOORS
if (!AimTraverse3DFloors(it.Trace(), in)) return;
#endif
continue; // shot continues continue; // shot continues
} }
@ -2437,6 +2679,34 @@ void aim_t::AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t e
} }
dist = FixedMul (attackrange, in->frac); dist = FixedMul (attackrange, in->frac);
#ifdef _3DFLOORS
// we must do one last check whether the trace has crossed a 3D floor
if (lastsector==th->Sector && th->Sector->e->XFloor.ffloors.Size())
{
if (lastceilingplane)
{
fixed_t ff_top=lastceilingplane->ZatPoint(th->x, th->y);
fixed_t pitch = -(int)R_PointToAngle2 (0, shootz, dist, ff_top);
// upper slope intersects with this 3d-floor
if (pitch > toppitch)
{
toppitch=pitch;
}
}
if (lastfloorplane)
{
fixed_t ff_bottom=lastfloorplane->ZatPoint(th->x, th->y);
fixed_t pitch = -(int)R_PointToAngle2 (0, shootz, dist, ff_bottom);
// lower slope intersects with this 3d-floor
if (pitch < bottompitch)
{
bottompitch=pitch;
}
}
}
#endif
// check angles to see if the thing can be aimed at // check angles to see if the thing can be aimed at
thingtoppitch = -(int)R_PointToAngle2 (0, shootz, dist, th->z + th->height); thingtoppitch = -(int)R_PointToAngle2 (0, shootz, dist, th->z + th->height);
@ -2449,6 +2719,27 @@ void aim_t::AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t e
if (thingbottompitch < toppitch) if (thingbottompitch < toppitch)
continue; // shot under the thing continue; // shot under the thing
#ifdef _3DFLOORS
if (crossedffloors)
{
// if 3D floors were in the way do an extra visibility check for safety
if (!P_CheckSight(shootthing, th, 1))
{
// the thing can't be seen so we can safely exclude its range from our aiming field
if (thingtoppitch<toppitch)
{
if (thingbottompitch>toppitch) toppitch=thingbottompitch;
}
else if (thingbottompitch>bottompitch)
{
if (thingtoppitch<bottompitch) bottompitch=thingtoppitch;
}
if (toppitch < bottompitch) continue;
else return;
}
}
#endif
// this thing can be hit! // this thing can be hit!
if (thingtoppitch < toppitch) if (thingtoppitch < toppitch)
thingtoppitch = toppitch; thingtoppitch = toppitch;
@ -2568,6 +2859,25 @@ fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor **p
// Information for tracking crossed 3D floors // Information for tracking crossed 3D floors
aim.aimpitch=t1->pitch; aim.aimpitch=t1->pitch;
#ifdef _3DFLOORS
aim.crossedffloors=t1->Sector->e->XFloor.ffloors.Size()!=0;
aim.lastsector=t1->Sector;
aim.lastfloorplane=aim.lastceilingplane=NULL;
// set initial 3d-floor info
for(unsigned i=0;i<t1->Sector->e->XFloor.ffloors.Size();i++)
{
F3DFloor * rover=t1->Sector->e->XFloor.ffloors[i];
fixed_t bottomz=rover->bottom.plane->ZatPoint(t1->x, t1->y);
if (bottomz>=t1->z+t1->height) aim.lastceilingplane=rover->bottom.plane;
bottomz=rover->top.plane->ZatPoint(t1->x, t1->y);
if (bottomz<=t1->z) aim.lastfloorplane=rover->top.plane;
}
#endif
aim.AimTraverse (t1->x, t1->y, x2, y2); aim.AimTraverse (t1->x, t1->y, x2, y2);
if (!aim.linetarget) if (!aim.linetarget)
@ -2916,6 +3226,7 @@ void P_TraceBleed (int damage, fixed_t x, fixed_t y, fixed_t z, AActor *actor, a
DImpactDecal::StaticCreate (bloodType, DImpactDecal::StaticCreate (bloodType,
bleedtrace.X, bleedtrace.Y, bleedtrace.Z, bleedtrace.X, bleedtrace.Y, bleedtrace.Z,
sides + bleedtrace.Line->sidenum[bleedtrace.Side], sides + bleedtrace.Line->sidenum[bleedtrace.Side],
bleedtrace.ffloor,
bloodcolor); bloodcolor);
} }
} }
@ -4124,7 +4435,56 @@ bool P_ChangeSector (sector_t *sector, int crunch, int amt, int floorOrCeil, boo
cpos.movemidtex = false; cpos.movemidtex = false;
cpos.sector = sector; cpos.sector = sector;
// [RH] Use different functions for the four different types of sector movement. #ifdef _3DFLOORS
// Also process all sectors that have 3D floors transferred from the
// changed sector.
if(sector->e->XFloor.attached.Size())
{
unsigned i;
sector_t* sec;
// Use different functions for the four different types of sector movement.
// for 3D-floors the meaning of floor and ceiling is inverted!!!
if (floorOrCeil == 1)
{
iterator = (amt >= 0) ? PIT_FloorRaise : PIT_FloorDrop;
}
else
{
iterator = (amt >=0) ? PIT_CeilingRaise : PIT_CeilingLower;
}
for(i = 0; i < sector->e->XFloor.attached.Size(); i ++)
{
sec = sector->e->XFloor.attached[i];
P_Recalculate3DFloors(sec); // Must recalculate the 3d floor and light lists
// no thing checks for attached sectors because of heightsec
if (sec->heightsec==sector) continue;
for (n=sec->touching_thinglist; n; n=n->m_snext) n->visited = false;
do
{
for (n=sec->touching_thinglist; n; n=n->m_snext)
{
if (!n->visited)
{
n->visited = true;
if (!(n->m_thing->flags&MF_NOBLOCKMAP)) iterator(n->m_thing, &cpos);
break;
}
}
}
while (n);
}
}
P_Recalculate3DFloors(sector); // Must recalculate the 3d floor and light lists
#endif
// [RH] Use different functions for the four different types of sector
// movement. Also update the soundorg's z-coordinate for 3D sound.
switch (floorOrCeil) switch (floorOrCeil)
{ {
case 0: case 0:
@ -4497,13 +4857,15 @@ void SpawnShootDecal (AActor *t1, const FTraceResults &trace)
if (decalbase != NULL) if (decalbase != NULL)
{ {
DImpactDecal::StaticCreate (decalbase->GetDecal (), DImpactDecal::StaticCreate (decalbase->GetDecal (),
trace.X, trace.Y, trace.Z, sides + trace.Line->sidenum[trace.Side]); trace.X, trace.Y, trace.Z, sides + trace.Line->sidenum[trace.Side], trace.ffloor);
} }
} }
static void SpawnDeepSplash (AActor *t1, const FTraceResults &trace, AActor *puff, static void SpawnDeepSplash (AActor *t1, const FTraceResults &trace, AActor *puff,
fixed_t vx, fixed_t vy, fixed_t vz, fixed_t shootz) fixed_t vx, fixed_t vy, fixed_t vz, fixed_t shootz)
{ {
if (!trace.CrossedWater->heightsec) return;
fixed_t num, den, hitdist; fixed_t num, den, hitdist;
const secplane_t *plane = &trace.CrossedWater->heightsec->floorplane; const secplane_t *plane = &trace.CrossedWater->heightsec->floorplane;

View file

@ -197,6 +197,12 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef,
open.lowfloor = ff; open.lowfloor = ff;
} }
// Check 3D floors
if (actor != NULL)
{
P_LineOpening_XFloors(open, actor, linedef, x, y, refx, refy);
}
if (actor != NULL && linedef->frontsector != NULL && linedef->backsector != NULL && if (actor != NULL && linedef->frontsector != NULL && linedef->backsector != NULL &&
linedef->flags & ML_3DMIDTEX) linedef->flags & ML_3DMIDTEX)
{ {

View file

@ -1066,8 +1066,31 @@ void P_ExplodeMissile (AActor *mo, line_t *line, AActor *target)
y = line->v1->y + MulScale30 (line->dy, frac); y = line->v1->y + MulScale30 (line->dy, frac);
z = mo->z; z = mo->z;
F3DFloor * ffloor=NULL;
#ifdef _3DFLOORS
if (line->sidenum[side^1]!=NO_SIDE)
{
sector_t * backsector=sides[line->sidenum[side^1]].sector;
extsector_t::xfloor &xf = backsector->e->XFloor;
// find a 3D-floor to stick to
for(unsigned int i=0;i<xf.ffloors.Size();i++)
{
F3DFloor * rover=xf.ffloors[i];
if ((rover->flags&(FF_EXISTS|FF_SOLID|FF_RENDERSIDES))==(FF_EXISTS|FF_SOLID|FF_RENDERSIDES))
{
if (z<=rover->top.plane->ZatPoint(x, y) && z>=rover->bottom.plane->ZatPoint( x, y))
{
ffloor=rover;
break;
}
}
}
}
#endif
DImpactDecal::StaticCreate (base->GetDecal (), DImpactDecal::StaticCreate (base->GetDecal (),
x, y, z, sides + line->sidenum[side]); x, y, z, sides + line->sidenum[side], ffloor);
} }
} }
} }
@ -1318,7 +1341,7 @@ void P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly)
fixed_t ptryx, ptryy; fixed_t ptryx, ptryy;
player_t *player; player_t *player;
fixed_t xmove, ymove; fixed_t xmove, ymove;
bool walkplane; const secplane_t * walkplane;
static const int windTab[3] = {2048*5, 2048*10, 2048*25}; static const int windTab[3] = {2048*5, 2048*10, 2048*25};
int steps, step, totalsteps; int steps, step, totalsteps;
fixed_t startx, starty; fixed_t startx, starty;
@ -1723,6 +1746,18 @@ explode:
{ {
if (mo->dropoffz != mo->floorz) // 3DMidtex or other special cases that must be excluded if (mo->dropoffz != mo->floorz) // 3DMidtex or other special cases that must be excluded
{ {
#ifdef _3DFLOORS
unsigned i;
for(i=0;i<mo->Sector->e->XFloor.ffloors.Size();i++)
{
// Sliding around on 3D floors looks extremely bad so
// if the floor comes from one in the current sector stop sliding the corpse!
F3DFloor * rover=mo->Sector->e->XFloor.ffloors[i];
if (!(rover->flags&FF_EXISTS)) continue;
if (rover->flags&FF_SOLID && rover->top.plane->ZatPoint(mo->x,mo->y)==mo->floorz) break;
}
if (i==mo->Sector->e->XFloor.ffloors.Size())
#endif
return; return;
} }
} }
@ -1894,6 +1929,7 @@ void P_ZMovement (AActor *mo)
{ // [RH] Let the sector do something to the actor { // [RH] Let the sector do something to the actor
mo->Sector->SecActTarget->TriggerAction (mo, SECSPAC_HitFloor); mo->Sector->SecActTarget->TriggerAction (mo, SECSPAC_HitFloor);
} }
P_CheckFor3DFloorHit(mo);
// [RH] Need to recheck this because the sector action might have // [RH] Need to recheck this because the sector action might have
// teleported the actor so it is no longer below the floor. // teleported the actor so it is no longer below the floor.
if (mo->z <= mo->floorz) if (mo->z <= mo->floorz)
@ -1992,6 +2028,7 @@ void P_ZMovement (AActor *mo)
{ // [RH] Let the sector do something to the actor { // [RH] Let the sector do something to the actor
mo->Sector->SecActTarget->TriggerAction (mo, SECSPAC_HitCeiling); mo->Sector->SecActTarget->TriggerAction (mo, SECSPAC_HitCeiling);
} }
P_CheckFor3DCeilingHit(mo);
// [RH] Need to recheck this because the sector action might have // [RH] Need to recheck this because the sector action might have
// teleported the actor so it is no longer above the ceiling. // teleported the actor so it is no longer above the ceiling.
if (mo->z + mo->height > mo->ceilingz) if (mo->z + mo->height > mo->ceilingz)
@ -2829,6 +2866,26 @@ void AActor::Tick ()
floorz == z) floorz == z)
{ {
const secplane_t * floorplane = &floorsector->floorplane; const secplane_t * floorplane = &floorsector->floorplane;
static secplane_t copyplane;
#ifdef _3DFLOORS
// Check 3D floors as well
if (floorsector->e) // apparently this can be called when the data is already gone-
for(unsigned int i=0;i<floorsector->e->XFloor.ffloors.Size();i++)
{
F3DFloor * rover= floorsector->e->XFloor.ffloors[i];
if(!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue;
if (rover->top.plane->ZatPoint(x, y) == floorz)
{
copyplane = *rover->top.plane;
if (copyplane.c<0) copyplane.FlipVert();
floorplane = &copyplane;
break;
}
}
#endif
if (floorplane->c < STEEPSLOPE && if (floorplane->c < STEEPSLOPE &&
floorplane->ZatPoint (x, y) <= floorz) floorplane->ZatPoint (x, y) <= floorz)
{ {
@ -3053,8 +3110,42 @@ bool AActor::UpdateWaterLevel (fixed_t oldz, bool dosplash)
// But the water level must be reset when this function returns // But the water level must be reset when this function returns
if (!(hsec->MoreFlags&SECF_UNDERWATERMASK)) reset=true; if (!(hsec->MoreFlags&SECF_UNDERWATERMASK)) reset=true;
} }
#ifdef _3DFLOORS
else
{
// Check 3D floors as well!
for(unsigned int i=0;i<Sector->e->XFloor.ffloors.Size();i++)
{
F3DFloor* rover=Sector->e->XFloor.ffloors[i];
if (!(rover->flags & FF_EXISTS)) continue;
if(!(rover->flags & FF_SWIMMABLE) || rover->flags & FF_SOLID) continue;
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(x, y);
fixed_t ff_top=rover->top.plane->ZatPoint(x, y);
if(ff_top <= z || ff_bottom > (z + (height >> 1))) continue;
fh=ff_top;
if (z < fh)
{
waterlevel = 1;
if (z + height/2 < fh)
{
waterlevel = 2;
if ((player && z + player->viewheight <= fh) ||
(z + height <= fh))
{
waterlevel = 3;
}
}
} }
break;
}
}
#endif
}
// some additional checks to make deep sectors like Boom's splash without setting // some additional checks to make deep sectors like Boom's splash without setting
// the water flags. // the water flags.
@ -3064,7 +3155,7 @@ bool AActor::UpdateWaterLevel (fixed_t oldz, bool dosplash)
} }
boomwaterlevel=waterlevel; boomwaterlevel=waterlevel;
if (reset) waterlevel=lastwaterlevel; if (reset) waterlevel=lastwaterlevel;
return false; // we did the splash ourselves! ;) return false; // we did the splash ourselves
} }
//========================================================================== //==========================================================================
@ -3377,6 +3468,9 @@ void AActor::AdjustFloorClip ()
fixed_t shallowestclip = FIXED_MAX; fixed_t shallowestclip = FIXED_MAX;
const msecnode_t *m; const msecnode_t *m;
// possibly standing on a 3D-floor!
if (Sector->e->XFloor.ffloors.Size() && z>Sector->floorplane.ZatPoint(x,y)) floorclip=0;
// [RH] clip based on shallowest floor player is standing on // [RH] clip based on shallowest floor player is standing on
// If the sector has a deep water effect, then let that effect // If the sector has a deep water effect, then let that effect
// do the floorclipping instead of the terrain type. // do the floorclipping instead of the terrain type.
@ -4234,6 +4328,25 @@ bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z
if (z == FIXED_MIN) z = thing->z; if (z == FIXED_MIN) z = thing->z;
// don't splash above the object // don't splash above the object
if (checkabove && z > thing->z + (thing->height >> 1)) return false; if (checkabove && z > thing->z + (thing->height >> 1)) return false;
#ifdef _3DFLOORS
for(unsigned int i=0;i<sec->e->XFloor.ffloors.Size();i++)
{
F3DFloor * rover = sec->e->XFloor.ffloors[i];
if (!(rover->flags & FF_EXISTS)) continue;
fixed_t planez = rover->top.plane->ZatPoint(x, y);
if (z > planez - FRACUNIT/2 && z < planez + FRACUNIT/2) // allow minor imprecisions
{
if (rover->flags & (FF_SOLID|FF_SWIMMABLE) )
{
terrainnum = TerrainTypes[*rover->top.texture];
goto foundone;
}
}
planez = rover->bottom.plane->ZatPoint(x, y);
if (planez < z) return false;
}
#endif
if (sec->heightsec == NULL || if (sec->heightsec == NULL ||
//!sec->heightsec->waterzone || //!sec->heightsec->waterzone ||
(sec->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC) || (sec->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC) ||
@ -4245,6 +4358,9 @@ bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z
{ {
terrainnum = TerrainTypes[sec->heightsec->GetTexture(sector_t::floor)]; terrainnum = TerrainTypes[sec->heightsec->GetTexture(sector_t::floor)];
} }
#ifdef _3DFLOORS
foundone:
#endif
int splashnum = Terrains[terrainnum].Splash; int splashnum = Terrains[terrainnum].Splash;
bool smallsplash = false; bool smallsplash = false;
@ -4339,6 +4455,22 @@ bool P_HitFloor (AActor *thing)
{ {
break; break;
} }
#ifdef _3DFLOORS
// Check 3D floors
for(unsigned int i=0;i<m->m_sector->e->XFloor.ffloors.Size();i++)
{
F3DFloor * rover = m->m_sector->e->XFloor.ffloors[i];
if (!(rover->flags & FF_EXISTS)) continue;
if (rover->flags & (FF_SOLID|FF_SWIMMABLE))
{
if (rover->top.plane->ZatPoint(thing->x, thing->y) == thing->z)
{
return P_HitWater (thing, m->m_sector);
}
}
}
#endif
} }
if (m == NULL || if (m == NULL ||
(m->m_sector->heightsec != NULL && (m->m_sector->heightsec != NULL &&

View file

@ -1242,6 +1242,7 @@ void P_LoadSectors (MapData * map)
// killough 8/28/98: initialize all sectors to normal friction // killough 8/28/98: initialize all sectors to normal friction
ss->friction = ORIG_FRICTION; ss->friction = ORIG_FRICTION;
ss->movefactor = ORIG_FRICTION_FACTOR; ss->movefactor = ORIG_FRICTION_FACTOR;
ss->sectornum = i;
} }
delete[] msp; delete[] msp;
} }
@ -2131,6 +2132,28 @@ void P_ProcessSideTextures(bool checktranmap, side_t *sd, sector_t *sec, mapside
} }
break; break;
#ifdef _3DFLOORS
case Sector_Set3DFloor:
if (msd->toptexture[0]=='#')
{
strncpy (name, msd->toptexture, 8);
sd->SetTexture(side_t::top, FNullTextureID() +(-strtol(name+1, NULL, 10))); // store the alpha as a negative texture index
// This will be sorted out by the 3D-floor code later.
}
else
{
strncpy (name, msd->toptexture, 8);
sd->SetTexture(side_t::top, TexMan.GetTexture (name, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable));
}
strncpy (name, msd->midtexture, 8);
sd->SetTexture(side_t::mid, TexMan.GetTexture (name, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable));
strncpy (name, msd->bottomtexture, 8);
sd->SetTexture(side_t::bottom, TexMan.GetTexture (name, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable));
break;
#endif
case TranslucentLine: // killough 4/11/98: apply translucency to 2s normal texture case TranslucentLine: // killough 4/11/98: apply translucency to 2s normal texture
if (checktranmap) if (checktranmap)
{ {
@ -3483,6 +3506,9 @@ void P_SetupLevel (char *lumpname, int position)
deathmatchstarts.Clear (); deathmatchstarts.Clear ();
// Spawn 3d floors - must be done before spawning things so it can't be done in P_SpawnSpecials
P_Spawn3DFloors();
if (!buildmap) if (!buildmap)
{ {
times[14].Clock(); times[14].Clock();

View file

@ -37,19 +37,47 @@ This uses specialized forms of the maputils routines for optimized performance
============================================================================== ==============================================================================
*/ */
static TArray<intercept_t> intercepts (128);
static divline_t trace;
static fixed_t sightzstart; // eye z of looker
static fixed_t topslope, bottomslope; // slopes to top and bottom of target
static int SeePastBlockEverything, SeePastShootableLines;
// Performance meters // Performance meters
static int sightcounts[6]; static int sightcounts[6];
static cycle_t SightCycles; static cycle_t SightCycles;
static cycle_t MaxSightCycles; static cycle_t MaxSightCycles;
static bool P_SightTraverseIntercepts (); static TArray<intercept_t> intercepts (128);
class SightCheck
{
fixed_t sightzstart; // eye z of looker
const AActor * sightthing;
const AActor * seeingthing;
fixed_t lastztop; // z at last line
fixed_t lastzbottom; // z at last line
sector_t * lastsector; // last sector being entered by trace
fixed_t topslope, bottomslope; // slopes to top and bottom of target
int SeePastBlockEverything, SeePastShootableLines;
divline_t trace;
int myseethrough;
bool PTR_SightTraverse (intercept_t *in);
bool P_SightCheckLine (line_t *ld);
bool P_SightBlockLinesIterator (int x, int y);
bool P_SightTraverseIntercepts ();
public:
bool P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2);
SightCheck(const AActor * t1, const AActor * t2, int flags)
{
lastztop = lastzbottom = sightzstart = t1->z + t1->height - (t1->height>>2);
lastsector = t1->Sector;
sightthing=t1;
seeingthing=t2;
bottomslope = t2->z - sightzstart;
topslope = bottomslope + t2->height;
SeePastBlockEverything = flags & 6;
SeePastShootableLines = flags & 4;
}
};
/* /*
============== ==============
@ -59,7 +87,10 @@ static bool P_SightTraverseIntercepts ();
============== ==============
*/ */
/*
static bool PTR_SightTraverse (intercept_t *in) static bool PTR_SightTraverse (intercept_t *in)
*/
bool SightCheck::PTR_SightTraverse (intercept_t *in)
{ {
line_t *li; line_t *li;
fixed_t slope; fixed_t slope;
@ -70,8 +101,9 @@ static bool PTR_SightTraverse (intercept_t *in)
// //
// crosses a two sided line // crosses a two sided line
// //
P_LineOpening (open, NULL, li, trace.x + FixedMul (trace.dx, in->frac), fixed_t trX=trace.x + FixedMul (trace.dx, in->frac);
trace.y + FixedMul (trace.dy, in->frac)); fixed_t trY=trace.y + FixedMul (trace.dy, in->frac);
P_LineOpening (open, NULL, li, trX, trY);
if (open.range <= 0) // quick test for totally closed doors if (open.range <= 0) // quick test for totally closed doors
return false; // stop return false; // stop
@ -89,6 +121,98 @@ static bool PTR_SightTraverse (intercept_t *in)
if (topslope <= bottomslope) if (topslope <= bottomslope)
return false; // stop return false; // stop
#ifdef _3DFLOORS
// now handle 3D-floors
if(li->frontsector->e->XFloor.ffloors.Size() || li->backsector->e->XFloor.ffloors.Size())
{
int frontflag;
frontflag = P_PointOnLineSide(sightthing->x, sightthing->y, li);
//Check 3D FLOORS!
for(int i=1;i<=2;i++)
{
sector_t * s=i==1? li->frontsector:li->backsector;
fixed_t highslope, lowslope;
fixed_t topz= FixedMul (topslope, in->frac) + sightzstart;
fixed_t bottomz= FixedMul (bottomslope, in->frac) + sightzstart;
for(unsigned int j=0;j<s->e->XFloor.ffloors.Size();j++)
{
F3DFloor* rover=s->e->XFloor.ffloors[j];
if((rover->flags & FF_SEETHROUGH) == myseethrough || !(rover->flags & FF_EXISTS)) continue;
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(trX, trY);
fixed_t ff_top=rover->top.plane->ZatPoint(trX, trY);
highslope = FixedDiv (ff_top - sightzstart, in->frac);
lowslope = FixedDiv (ff_bottom - sightzstart, in->frac);
if (highslope>=topslope)
{
// blocks completely
if (lowslope<=bottomslope) return false;
// blocks upper edge of view
if (lowslope<topslope) topslope=lowslope;
}
else if (lowslope<=bottomslope)
{
// blocks lower edge of view
if (highslope>bottomslope) bottomslope=highslope;
}
else
{
// the 3D-floor is inside the viewing cone but neither clips the top nor the bottom so by
// itself it can't be view blocking.
// However, if there's a 3D-floor on the other side that obstructs the same vertical range
// the 2 together will block sight.
sector_t * sb=i==2? li->frontsector:li->backsector;
for(unsigned int k=0;k<sb->e->XFloor.ffloors.Size();k++)
{
F3DFloor* rover2=sb->e->XFloor.ffloors[k];
if((rover2->flags & FF_SEETHROUGH) == myseethrough || !(rover2->flags & FF_EXISTS)) continue;
fixed_t ffb_bottom=rover2->bottom.plane->ZatPoint(trX, trY);
fixed_t ffb_top=rover2->top.plane->ZatPoint(trX, trY);
if (ffb_bottom >= ff_bottom && ffb_bottom<=ff_top ||
ffb_top <= ff_top && ffb_top >= ff_bottom ||
ffb_top >= ff_top && ffb_bottom <= ff_bottom ||
ffb_top <= ff_top && ffb_bottom >= ff_bottom)
{
return false;
}
}
}
// trace is leaving a sector with a 3d-floor
if (s==lastsector && frontflag==i-1)
{
// upper slope intersects with this 3d-floor
if (lastztop<=ff_bottom && topz>ff_top)
{
topslope=lowslope;
}
// lower slope intersects with this 3d-floor
if (lastzbottom>=ff_top && bottomz<ff_top)
{
bottomslope=highslope;
}
}
if (topslope <= bottomslope) return false; // stop
}
}
lastsector = frontflag==0 ? li->backsector : li->frontsector;
}
else lastsector=NULL; // don't need it if there are no 3D-floors
lastztop= FixedMul (topslope, in->frac) + sightzstart;
lastzbottom= FixedMul (bottomslope, in->frac) + sightzstart;
#endif
return true; // keep going return true; // keep going
} }
@ -102,7 +226,7 @@ static bool PTR_SightTraverse (intercept_t *in)
=================== ===================
*/ */
static bool P_SightCheckLine (line_t *ld) bool SightCheck::P_SightCheckLine (line_t *ld)
{ {
divline_t dl; divline_t dl;
@ -123,7 +247,7 @@ static bool P_SightCheckLine (line_t *ld)
return true; // line isn't crossed return true; // line isn't crossed
} }
// try to early out the check // try to early out the check
if (!ld->backsector || !(ld->flags & ML_TWOSIDED)) if (!ld->backsector || !(ld->flags & ML_TWOSIDED))
return false; // stop checking return false; // stop checking
@ -156,7 +280,7 @@ static bool P_SightCheckLine (line_t *ld)
} }
sightcounts[3]++; sightcounts[3]++;
// store the line for later intersection testing // store the line for later intersection testing
intercept_t newintercept; intercept_t newintercept;
newintercept.isaline = true; newintercept.isaline = true;
newintercept.d.line = ld; newintercept.d.line = ld;
@ -173,7 +297,7 @@ static bool P_SightCheckLine (line_t *ld)
=================== ===================
*/ */
static bool P_SightBlockLinesIterator (int x, int y) bool SightCheck::P_SightBlockLinesIterator (int x, int y)
{ {
int offset; int offset;
int *list; int *list;
@ -222,12 +346,12 @@ static bool P_SightBlockLinesIterator (int x, int y)
==================== ====================
*/ */
static bool P_SightTraverseIntercepts () bool SightCheck::P_SightTraverseIntercepts ()
{ {
size_t count; unsigned count;
fixed_t dist; fixed_t dist;
intercept_t *scan, *in; intercept_t *scan, *in;
unsigned int scanpos; unsigned scanpos;
divline_t dl; divline_t dl;
count = intercepts.Size (); count = intercepts.Size ();
@ -269,6 +393,29 @@ static bool P_SightTraverseIntercepts ()
} }
} }
#ifdef _3DFLOORS
if (lastsector==seeingthing->Sector && lastsector->e->XFloor.ffloors.Size())
{
// we must do one last check whether the trace has crossed a 3D floor in the last sector
fixed_t topz= topslope + sightzstart;
fixed_t bottomz= bottomslope + sightzstart;
for(unsigned int i=0;i<lastsector->e->XFloor.ffloors.Size();i++)
{
F3DFloor* rover = lastsector->e->XFloor.ffloors[i];
if((rover->flags & FF_SOLID) == myseethrough || !(rover->flags & FF_EXISTS)) continue;
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(seeingthing->x, seeingthing->y);
fixed_t ff_top=rover->top.plane->ZatPoint(seeingthing->x, seeingthing->y);
if (lastztop<=ff_bottom && topz>ff_bottom && lastzbottom<=ff_bottom && bottomz>ff_bottom) return false;
if (lastzbottom>=ff_top && bottomz<ff_top && lastztop>=ff_top && topz<ff_top) return false;
}
}
#endif
return true; // everything was traversed return true; // everything was traversed
} }
@ -284,7 +431,7 @@ static bool P_SightTraverseIntercepts ()
================== ==================
*/ */
static bool P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2) bool SightCheck::P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
{ {
fixed_t xt1,yt1,xt2,yt2; fixed_t xt1,yt1,xt2,yt2;
fixed_t xstep,ystep; fixed_t xstep,ystep;
@ -296,6 +443,27 @@ static bool P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
validcount++; validcount++;
intercepts.Clear (); intercepts.Clear ();
#ifdef _3DFLOORS
// for FF_SEETHROUGH the following rule applies:
// If the viewer is in an area without FF_SEETHROUGH he can only see into areas without this flag
// If the viewer is in an area with FF_SEETHROUGH he can only see into areas with this flag
for(unsigned int i=0;i<lastsector->e->XFloor.ffloors.Size();i++)
{
F3DFloor* rover = lastsector->e->XFloor.ffloors[i];
if(!(rover->flags & FF_EXISTS)) continue;
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(sightthing->x, sightthing->y);
fixed_t ff_top=rover->top.plane->ZatPoint(sightthing->x, sightthing->y);
if (sightzstart < ff_top && sightzstart >= ff_bottom)
{
myseethrough = rover->flags & FF_SEETHROUGH;
break;
}
}
#endif
if ( ((x1-bmaporgx)&(MAPBLOCKSIZE-1)) == 0) if ( ((x1-bmaporgx)&(MAPBLOCKSIZE-1)) == 0)
x1 += FRACUNIT; // don't side exactly on a line x1 += FRACUNIT; // don't side exactly on a line
if ( ((y1-bmaporgy)&(MAPBLOCKSIZE-1)) == 0) if ( ((y1-bmaporgy)&(MAPBLOCKSIZE-1)) == 0)
@ -535,16 +703,10 @@ sightcounts[0]++;
// Now look from eyes of t1 to any part of t2. // Now look from eyes of t1 to any part of t2.
validcount++; validcount++;
{
sightzstart = t1->z + t1->height - (t1->height>>2); SightCheck s(t1, t2, flags);
bottomslope = t2->z - sightzstart; res = s.P_SightPathTraverse (t1->x, t1->y, t2->x, t2->y);
topslope = bottomslope + t2->height; }
SeePastBlockEverything = flags & 6;
SeePastShootableLines = flags & 4;
res = P_SightPathTraverse (t1->x, t1->y, t2->x, t2->y);
SeePastBlockEverything = 0;
SeePastShootableLines = 0;
done: done:
SightCycles.Unclock(); SightCycles.Unclock();
@ -573,3 +735,5 @@ void P_ResetSightCounters (bool full)
SightCycles.Reset(); SightCycles.Reset();
memset (sightcounts, 0, sizeof(sightcounts)); memset (sightcounts, 0, sizeof(sightcounts));
} }

View file

@ -387,17 +387,21 @@ bool P_TestActivateLine (line_t *line, AActor *mo, int side, int activationType)
// Called every tic frame // Called every tic frame
// that the player origin is in a special sector // that the player origin is in a special sector
// //
void P_PlayerInSpecialSector (player_t *player) void P_PlayerInSpecialSector (player_t *player, sector_t * sector)
{ {
sector_t *sector = player->mo->Sector;
int special = sector->special & ~SECRET_MASK;
if (sector == NULL)
{
// Falling, not all the way down yet? // Falling, not all the way down yet?
sector = player->mo->Sector;
if (player->mo->z != sector->floorplane.ZatPoint (player->mo->x, player->mo->y) if (player->mo->z != sector->floorplane.ZatPoint (player->mo->x, player->mo->y)
&& !player->mo->waterlevel) && !player->mo->waterlevel)
{ {
return; return;
} }
}
int special = sector->special & ~SECRET_MASK;
// Has hit ground. // Has hit ground.
AInventory *ironfeet; AInventory *ironfeet;

View file

@ -182,7 +182,7 @@ void P_UpdateSpecials (void);
bool P_ActivateLine (line_t *ld, AActor *mo, int side, int activationType); bool P_ActivateLine (line_t *ld, AActor *mo, int side, int activationType);
bool P_TestActivateLine (line_t *ld, AActor *mo, int side, int activationType); bool P_TestActivateLine (line_t *ld, AActor *mo, int side, int activationType);
void P_PlayerInSpecialSector (player_t *player); void P_PlayerInSpecialSector (player_t *player, sector_t * sector=NULL);
void P_PlayerOnSpecialFlat (player_t *player, int floorType); void P_PlayerOnSpecialFlat (player_t *player, int floorType);
void P_SetSectorFriction (int tag, int amount, bool alterFlag); void P_SetSectorFriction (int tag, int amount, bool alterFlag);

View file

@ -50,6 +50,13 @@ struct FTraceInfo
fixed_t EnterDist; fixed_t EnterDist;
bool (*TraceCallback)(FTraceResults &res); bool (*TraceCallback)(FTraceResults &res);
DWORD TraceFlags; DWORD TraceFlags;
int inshootthrough;
// These are required for 3D-floor checking
// to create a fake sector with a floor
// or ceiling plane coming from a 3D-floor
sector_t DummySector[2];
int sectorsel;
bool TraceTraverse (int ptflags); bool TraceTraverse (int ptflags);
bool CheckSectorPlane (const sector_t *sector, bool checkFloor); bool CheckSectorPlane (const sector_t *sector, bool checkFloor);
@ -85,27 +92,121 @@ bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector,
inf.TraceFlags = flags; inf.TraceFlags = flags;
res.CrossedWater = NULL; res.CrossedWater = NULL;
inf.Results = &res; inf.Results = &res;
inf.inshootthrough = true;
res.HitType = TRACE_HitNone; res.HitType = TRACE_HitNone;
// Do a 3D floor check in the starting sector
memset(&res, 0, sizeof(res));
inf.sectorsel=0;
#ifdef _3DFLOORS
TDeletingArray<F3DFloor*> &ff = sector->e->XFloor.ffloors;
if (ff.Size())
{
memcpy(&inf.DummySector[0],sector,sizeof(sector_t));
inf.CurSector=sector=&inf.DummySector[0];
inf.sectorsel=1;
fixed_t bf = sector->floorplane.ZatPoint (x, y);
fixed_t bc = sector->ceilingplane.ZatPoint (x, y);
for(unsigned int i=0;i<ff.Size();i++)
{
F3DFloor * rover=ff[i];
if (!(rover->flags&FF_SHOOTTHROUGH) && rover->flags&FF_EXISTS)
{
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(x, y);
fixed_t ff_top=rover->top.plane->ZatPoint(x, y);
// clip to the part of the sector we are in
if (z>ff_top)
{
// above
if (bf<ff_top)
{
sector->floorplane=*rover->top.plane;
sector->SetTexture(sector_t::floor, *rover->top.texture, false);
bf=ff_top;
}
}
else if (z<ff_bottom)
{
//below
if (bc>ff_bottom)
{
sector->ceilingplane=*rover->bottom.plane;
sector->SetTexture(sector_t::ceiling, *rover->bottom.texture, false);
bc=ff_bottom;
}
}
else
{
// inside
if (bf<ff_bottom)
{
sector->floorplane=*rover->bottom.plane;
sector->SetTexture(sector_t::floor, *rover->bottom.texture, false);
bf=ff_bottom;
}
if (bc>ff_top)
{
sector->ceilingplane=*rover->top.plane;
sector->SetTexture(sector_t::ceiling, *rover->top.texture, false);
bc=ff_top;
}
inf.inshootthrough = false;
}
}
}
}
#endif
// check for overflows and clip if necessary
SQWORD xd= (SQWORD)x + ( ( SQWORD(vx) * SQWORD(maxDist) )>>16);
if (xd>SQWORD(32767)*FRACUNIT)
{
maxDist = inf.MaxDist=FixedDiv(FIXED_MAX-x,vx);
}
else if (xd<-SQWORD(32767)*FRACUNIT)
{
maxDist = inf.MaxDist=FixedDiv(FIXED_MIN-x,vx);
}
SQWORD yd= (SQWORD)y + ( ( SQWORD(vy) * SQWORD(maxDist) )>>16);
if (yd>SQWORD(32767)*FRACUNIT)
{
maxDist = inf.MaxDist=FixedDiv(FIXED_MAX-y,vy);
}
else if (yd<-SQWORD(32767)*FRACUNIT)
{
maxDist = inf.MaxDist=FixedDiv(FIXED_MIN-y,vy);
}
// recalculate the trace's end points for robustness
if (inf.TraceTraverse (ptflags)) if (inf.TraceTraverse (ptflags))
{ // check for intersection with floor/ceiling { // check for intersection with floor/ceiling
res.Sector = inf.CurSector; res.Sector = &sectors[inf.CurSector->sectornum];
if (inf.CheckSectorPlane (inf.CurSector, true)) if (inf.CheckSectorPlane (inf.CurSector, true))
{ {
res.HitType = TRACE_HitFloor; res.HitType = TRACE_HitFloor;
res.HitTexture = inf.CurSector->GetTexture(sector_t::floor);
if (res.CrossedWater == NULL && if (res.CrossedWater == NULL &&
inf.CurSector->heightsec != NULL && inf.CurSector->heightsec != NULL &&
inf.CurSector->heightsec->floorplane.ZatPoint (res.X, res.Y) >= res.Z) inf.CurSector->heightsec->floorplane.ZatPoint (res.X, res.Y) >= res.Z)
{ {
res.CrossedWater = inf.CurSector; res.CrossedWater = &sectors[inf.CurSector->sectornum];
} }
} }
else if (inf.CheckSectorPlane (inf.CurSector, false)) else if (inf.CheckSectorPlane (inf.CurSector, false))
{ {
res.HitType = TRACE_HitCeiling; res.HitType = TRACE_HitCeiling;
res.HitTexture = inf.CurSector->GetTexture(sector_t::ceiling);
} }
} }
@ -154,11 +255,12 @@ bool FTraceInfo::TraceTraverse (int ptflags)
fixed_t ff, fc, bf = 0, bc = 0; fixed_t ff, fc, bf = 0, bc = 0;
if (in->d.line->frontsector == CurSector) // CurSector may be a copy so we must compare the sector number, not the index!
if (in->d.line->frontsector->sectornum == CurSector->sectornum)
{ {
lineside = 0; lineside = 0;
} }
else if (in->d.line->backsector == CurSector) else if (in->d.line->backsector && in->d.line->backsector->sectornum == CurSector->sectornum)
{ {
lineside = 1; lineside = 1;
} }
@ -208,16 +310,18 @@ bool FTraceInfo::TraceTraverse (int ptflags)
hitz <= CurSector->heightsec->floorplane.ZatPoint (hitx, hity)) hitz <= CurSector->heightsec->floorplane.ZatPoint (hitx, hity))
{ {
// hit crossed a water plane // hit crossed a water plane
Results->CrossedWater = CurSector; Results->CrossedWater = &sectors[CurSector->sectornum];
} }
if (hitz <= ff) if (hitz <= ff)
{ // hit floor in front of wall { // hit floor in front of wall
Results->HitType = TRACE_HitFloor; Results->HitType = TRACE_HitFloor;
Results->HitTexture = CurSector->GetTexture(sector_t::floor);
} }
else if (hitz >= fc) else if (hitz >= fc)
{ // hit ceiling in front of wall { // hit ceiling in front of wall
Results->HitType = TRACE_HitCeiling; Results->HitType = TRACE_HitCeiling;
Results->HitTexture = CurSector->GetTexture(sector_t::ceiling);
} }
else if (entersector == NULL || else if (entersector == NULL ||
hitz <= bf || hitz >= bc || hitz <= bf || hitz >= bc ||
@ -235,6 +339,64 @@ bool FTraceInfo::TraceTraverse (int ptflags)
} }
else else
{ // made it past the wall { // made it past the wall
#ifdef _3DFLOORS
// check for 3D floors first
if (entersector->e->XFloor.ffloors.Size())
{
memcpy(&DummySector[sectorsel],entersector,sizeof(sector_t));
entersector=&DummySector[sectorsel];
sectorsel^=1;
for(unsigned int i=0;i<entersector->e->XFloor.ffloors.Size();i++)
{
F3DFloor * rover=entersector->e->XFloor.ffloors[i];
int entershootthrough = !!(rover->flags&FF_SHOOTTHROUGH);
if (entershootthrough != inshootthrough && rover->flags&FF_EXISTS)
{
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(hitx, hity);
fixed_t ff_top=rover->top.plane->ZatPoint(hitx, hity);
// clip to the part of the sector we are in
if (hitz>ff_top)
{
// above
if (bf<ff_top)
{
entersector->floorplane=*rover->top.plane;
entersector->SetTexture(sector_t::floor, *rover->top.texture, false);
bf=ff_top;
}
}
else if (hitz<ff_bottom)
{
//below
if (bc>ff_bottom)
{
entersector->ceilingplane=*rover->bottom.plane;
entersector->SetTexture(sector_t::ceiling, *rover->bottom.texture, false);
bc=ff_bottom;
}
}
else
{
//hit the edge - equivalent to hitting the wall
Results->HitType = TRACE_HitWall;
Results->Tier = TIER_FFloor;
Results->ffloor = rover;
if ((TraceFlags & TRACE_Impact) && in->d.line->special)
{
P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_Impact);
}
goto cont;
}
}
}
}
#endif
Results->HitType = TRACE_HitNone; Results->HitType = TRACE_HitNone;
if (TraceFlags & TRACE_PCross) if (TraceFlags & TRACE_PCross)
{ {
@ -246,11 +408,14 @@ bool FTraceInfo::TraceTraverse (int ptflags)
P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_Impact); P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_Impact);
} }
} }
#ifdef _3DFLOORS
cont:
#endif
if (Results->HitType != TRACE_HitNone) if (Results->HitType != TRACE_HitNone)
{ {
// We hit something, so figure out where exactly // We hit something, so figure out where exactly
Results->Sector = CurSector; Results->Sector = &sectors[CurSector->sectornum];
if (Results->HitType != TRACE_HitWall && if (Results->HitType != TRACE_HitWall &&
!CheckSectorPlane (CurSector, Results->HitType == TRACE_HitFloor)) !CheckSectorPlane (CurSector, Results->HitType == TRACE_HitFloor))
@ -357,6 +522,41 @@ bool FTraceInfo::TraceTraverse (int ptflags)
abs(hity - in->d.thing->y) > in->d.thing->radius) continue; abs(hity - in->d.thing->y) > in->d.thing->radius) continue;
} }
// check for extrafloors first
if (CurSector->e->XFloor.ffloors.Size())
{
fixed_t ff_floor=CurSector->floorplane.ZatPoint(hitx, hity);
fixed_t ff_ceiling=CurSector->ceilingplane.ZatPoint(hitx, hity);
if (hitz>ff_ceiling) // actor is hit above the current ceiling
{
Results->HitType=TRACE_HitCeiling;
Results->HitTexture = CurSector->GetTexture(sector_t::ceiling);
}
else if (hitz<ff_floor) // actor is hit below the current floor
{
Results->HitType=TRACE_HitFloor;
Results->HitTexture = CurSector->GetTexture(sector_t::floor);
}
else goto cont1;
// the trace hit a 3D-floor before the thing.
// Calculate an intersection and abort.
Results->Sector = &sectors[CurSector->sectornum];
if (!CheckSectorPlane(CurSector, Results->HitType==TRACE_HitFloor))
{
Results->HitType=TRACE_HitNone;
}
if (TraceCallback != NULL)
{
return TraceCallback (*Results);
}
else
{
return false;
}
}
cont1:
Results->HitType = TRACE_HitActor; Results->HitType = TRACE_HitActor;
Results->X = hitx; Results->X = hitx;
@ -418,17 +618,9 @@ static bool EditTraceResult (DWORD flags, FTraceResults &res)
{ {
if (flags & TRACE_NoSky) if (flags & TRACE_NoSky)
{ // Throw away sky hits { // Throw away sky hits
if (res.HitType == TRACE_HitFloor) if (res.HitType == TRACE_HitFloor || res.HitType == TRACE_HitCeiling)
{ {
if (res.Sector->GetTexture(sector_t::floor) == skyflatnum) if (res.HitTexture == skyflatnum)
{
res.HitType = TRACE_HitNone;
return false;
}
}
else if (res.HitType == TRACE_HitCeiling)
{
if (res.Sector->GetTexture(sector_t::ceiling) == skyflatnum)
{ {
res.HitType = TRACE_HitNone; res.HitType = TRACE_HitNone;
return false; return false;

View file

@ -35,11 +35,12 @@
#define __P_TRACE_H__ #define __P_TRACE_H__
#include <stddef.h> #include <stddef.h>
#include "basictypes.h" #include "textures/textures.h"
struct sector_t; struct sector_t;
struct line_t; struct line_t;
class AActor; class AActor;
struct F3DFloor;
enum ETraceResult enum ETraceResult
{ {
@ -54,12 +55,14 @@ enum
{ {
TIER_Middle, TIER_Middle,
TIER_Upper, TIER_Upper,
TIER_Lower TIER_Lower,
TIER_FFloor,
}; };
struct FTraceResults struct FTraceResults
{ {
sector_t *Sector; sector_t *Sector;
FTextureID HitTexture;
fixed_t X, Y, Z; fixed_t X, Y, Z;
fixed_t Distance; fixed_t Distance;
fixed_t Fraction; fixed_t Fraction;
@ -71,6 +74,7 @@ struct FTraceResults
BYTE Tier; BYTE Tier;
ETraceResult HitType; ETraceResult HitType;
sector_t *CrossedWater; sector_t *CrossedWater;
F3DFloor * ffloor;
}; };
enum enum

View file

@ -2199,6 +2199,7 @@ void P_PlayerThink (player_t *player)
if (!(player->cheats & CF_PREDICTING)) if (!(player->cheats & CF_PREDICTING))
{ {
P_PlayerOnSpecial3DFloor (player);
if (player->mo->Sector->special || player->mo->Sector->damage) if (player->mo->Sector->special || player->mo->Sector->damage)
{ {
P_PlayerInSpecialSector (player); P_PlayerInSpecialSector (player);

View file

@ -229,6 +229,7 @@ inline FArchive &operator<< (FArchive &arc, secplane_t &plane)
return arc; return arc;
} }
#include "p_3dfloors.h"
// Ceiling/floor flags // Ceiling/floor flags
enum enum
{ {
@ -320,6 +321,14 @@ struct extsector_t
} Floor, Ceiling; } Floor, Ceiling;
} Linked; } Linked;
// 3D floors
struct xfloor
{
TDeletingArray<F3DFloor *> ffloors; // 3D floors in this sector
TArray<lightlist_t> lightlist; // 3D light list
TArray<sector_t*> attached; // 3D floors attached to this sector
} XFloor;
void Serialize(FArchive &arc); void Serialize(FArchive &arc);
}; };
@ -600,6 +609,7 @@ struct sector_t
vertex_t *Triangle[3]; // Three points that can define a plane vertex_t *Triangle[3]; // Three points that can define a plane
short oldspecial; //jff 2/16/98 remembers if sector WAS secret (automap) short oldspecial; //jff 2/16/98 remembers if sector WAS secret (automap)
int sectornum; // for comparing sector copies
extsector_t * e; // This stores data that requires construction/destruction. Such data must not be copied by R_FakeFlat. extsector_t * e; // This stores data that requires construction/destruction. Such data must not be copied by R_FakeFlat.
}; };
@ -742,7 +752,6 @@ struct line_t
slopetype_t slopetype; // To aid move clipping. slopetype_t slopetype; // To aid move clipping.
sector_t *frontsector, *backsector; sector_t *frontsector, *backsector;
int validcount; // if == validcount, already checked int validcount; // if == validcount, already checked
}; };
// phares 3/14/98 // phares 3/14/98

View file

@ -29,6 +29,7 @@ static const struct {
int code; int code;
const char *name; const char *name;
} sigill_codes[] = { } sigill_codes[] = {
#ifndef __FreeBSD__
{ ILL_ILLOPC, "Illegal opcode" }, { ILL_ILLOPC, "Illegal opcode" },
{ ILL_ILLOPN, "Illegal operand" }, { ILL_ILLOPN, "Illegal operand" },
{ ILL_ILLADR, "Illegal addressing mode" }, { ILL_ILLADR, "Illegal addressing mode" },
@ -37,6 +38,7 @@ static const struct {
{ ILL_PRVREG, "Privileged register" }, { ILL_PRVREG, "Privileged register" },
{ ILL_COPROC, "Coprocessor error" }, { ILL_COPROC, "Coprocessor error" },
{ ILL_BADSTK, "Internal stack error" }, { ILL_BADSTK, "Internal stack error" },
#endif
{ 0, NULL } { 0, NULL }
}; };
@ -59,8 +61,10 @@ static const struct {
int code; int code;
const char *name; const char *name;
} sigsegv_codes[] = { } sigsegv_codes[] = {
#ifndef __FreeBSD__
{ SEGV_MAPERR, "Address not mapped to object" }, { SEGV_MAPERR, "Address not mapped to object" },
{ SEGV_ACCERR, "Invalid permissions for mapped object" }, { SEGV_ACCERR, "Invalid permissions for mapped object" },
#endif
{ 0, NULL } { 0, NULL }
}; };
@ -68,9 +72,11 @@ static const struct {
int code; int code;
const char *name; const char *name;
} sigbus_codes[] = { } sigbus_codes[] = {
#ifndef __FreeBSD__
{ BUS_ADRALN, "Invalid address alignment" }, { BUS_ADRALN, "Invalid address alignment" },
{ BUS_ADRERR, "Non-existent physical address" }, { BUS_ADRERR, "Non-existent physical address" },
{ BUS_OBJERR, "Object specific hardware error" }, { BUS_OBJERR, "Object specific hardware error" },
#endif
{ 0, NULL } { 0, NULL }
}; };
@ -176,7 +182,9 @@ static void crash_catcher(int signum, siginfo_t *siginfo, void *context)
const char *sigdesc = NULL; const char *sigdesc = NULL;
pid_t pid, dbg_pid; pid_t pid, dbg_pid;
struct stat sbuf; struct stat sbuf;
#ifndef __FreeBSD__
struct rlimit rl; struct rlimit rl;
#endif
int status, i; int status, i;
FILE *f; FILE *f;
@ -374,7 +382,12 @@ int cc_install_handlers(int num_signals, int *signals, const char *logfile, int
memset(&sa, 0, sizeof(sa)); memset(&sa, 0, sizeof(sa));
sa.sa_sigaction = crash_catcher; sa.sa_sigaction = crash_catcher;
#ifndef __FreeBSD__
sa.sa_flags = SA_ONESHOT | SA_NODEFER | SA_SIGINFO; sa.sa_flags = SA_ONESHOT | SA_NODEFER | SA_SIGINFO;
#else
sa.sa_flags = SA_NODEFER | SA_SIGINFO;
#endif
cc_logfile = logfile; cc_logfile = logfile;
cc_user_info = user_info; cc_user_info = user_info;

View file

@ -736,6 +736,10 @@
RelativePath=".\src\nodebuild_utility.cpp" RelativePath=".\src\nodebuild_utility.cpp"
> >
</File> </File>
<File
RelativePath=".\src\p_3dfloors.cpp"
>
</File>
<File <File
RelativePath=".\src\p_3dmidtex.cpp" RelativePath=".\src\p_3dmidtex.cpp"
> >
@ -1377,6 +1381,10 @@
RelativePath=".\src\nodebuild.h" RelativePath=".\src\nodebuild.h"
> >
</File> </File>
<File
RelativePath=".\src\p_3dfloors.h"
>
</File>
<File <File
RelativePath=".\src\p_3dmidtex.h" RelativePath=".\src\p_3dmidtex.h"
> >