qzdoom/src/p_sectors.cpp
Christoph Oelckers 9bdb0f2e49 - renamed the flag bits for sector_t::MoreFlags, so that they are easier to distinguish from sector_t::Flags.
- precalculate if a sector's floor and ceiling plane overlap. This avoids rechecking this for each single call of hw_FakeFlat.
- vertices must be marked dirty every time they change after map setup. That means that ChangePlaneTexZ must do this as well, because it cannot rely on interpolation taking care of it.
- Having a 'dirty' argument for SetPlaneTexZ's ZScript version makes no sense. If the value changes from the script side the vertices must always be marked to be recalculated.
2018-05-01 11:29:29 +02:00

2688 lines
65 KiB
C++

//-----------------------------------------------------------------------------
//
// Copyright 1993-1996 id Software
// Copyright 1998-1998 Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
// Copyright 1999-2016 Randy Heit
// Copyright 2002-2018 Christoph Oelckers
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//-----------------------------------------------------------------------------
//
// DESCRIPTION:
// Sector utility functions.
//
//-----------------------------------------------------------------------------
/* For code that originates from ZDoom the following applies:
**
**---------------------------------------------------------------------------
**
** 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.
**
** 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.
**---------------------------------------------------------------------------
**
*/
#include "p_spec.h"
#include "p_lnspec.h"
#include "c_cvars.h"
#include "doomstat.h"
#include "g_level.h"
#include "nodebuild.h"
#include "p_terrain.h"
#include "po_man.h"
#include "serializer.h"
#include "r_utility.h"
#include "a_sharedglobal.h"
#include "p_local.h"
#include "r_sky.h"
#include "g_levellocals.h"
#include "vm.h"
// [RH]
// P_NextSpecialSector()
//
// Returns the next special sector attached to this sector
// with a certain special.
sector_t *sector_t::NextSpecialSector (int type, sector_t *nogood) const
{
sector_t *tsec;
for (auto ln : Lines)
{
if (NULL != (tsec = getNextSector (ln, this)) &&
tsec != nogood &&
tsec->special == type)
{
return tsec;
}
}
return NULL;
}
DEFINE_ACTION_FUNCTION(_Sector, NextSpecialSector)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(type);
PARAM_POINTER(nogood, sector_t);
ACTION_RETURN_POINTER(self->NextSpecialSector(type, nogood));
}
//
// P_FindLowestFloorSurrounding()
// FIND LOWEST FLOOR HEIGHT IN SURROUNDING SECTORS
//
double sector_t::FindLowestFloorSurrounding (vertex_t **v) const
{
sector_t *other;
double floor;
double ofloor;
vertex_t *spot;
if (Lines.Size() == 0) return GetPlaneTexZ(sector_t::floor);
spot = Lines[0]->v1;
floor = floorplane.ZatPoint(spot);
for (auto check : Lines)
{
if (NULL != (other = getNextSector (check, this)))
{
ofloor = other->floorplane.ZatPoint (check->v1);
if (ofloor < floor && ofloor < floorplane.ZatPoint (check->v1))
{
floor = ofloor;
spot = check->v1;
}
ofloor = other->floorplane.ZatPoint (check->v2);
if (ofloor < floor && ofloor < floorplane.ZatPoint (check->v2))
{
floor = ofloor;
spot = check->v2;
}
}
}
if (v != NULL)
*v = spot;
return floor;
}
DEFINE_ACTION_FUNCTION(_Sector, FindLowestFloorSurrounding)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
vertex_t *v;
double h = self->FindLowestFloorSurrounding(&v);
if (numret > 0) ret[0].SetFloat(h);
if (numret > 1) ret[1].SetPointer(v);
return numret;
}
//
// P_FindHighestFloorSurrounding()
// FIND HIGHEST FLOOR HEIGHT IN SURROUNDING SECTORS
//
double sector_t::FindHighestFloorSurrounding (vertex_t **v) const
{
sector_t *other;
double floor;
double ofloor;
vertex_t *spot;
if (Lines.Size() == 0) return GetPlaneTexZ(sector_t::floor);
spot = Lines[0]->v1;
floor = -FLT_MAX;
for (auto check : Lines)
{
if (NULL != (other = getNextSector (check, this)))
{
ofloor = other->floorplane.ZatPoint (check->v1);
if (ofloor > floor)
{
floor = ofloor;
spot = check->v1;
}
ofloor = other->floorplane.ZatPoint (check->v2);
if (ofloor > floor)
{
floor = ofloor;
spot = check->v2;
}
}
}
if (v != NULL)
*v = spot;
return floor;
}
DEFINE_ACTION_FUNCTION(_Sector, FindHighestFloorSurrounding)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
vertex_t *v;
double h = self->FindHighestFloorSurrounding(&v);
if (numret > 0) ret[0].SetFloat(h);
if (numret > 1) ret[1].SetPointer(v);
return numret;
}
//
// P_FindNextHighestFloor()
//
// Passed a sector and a floor height, returns the fixed point value
// of the smallest floor height in a surrounding sector larger than
// the floor height passed. If no such height exists the floorheight
// passed is returned.
//
// Rewritten by Lee Killough to avoid fixed array and to be faster
//
double sector_t::FindNextHighestFloor (vertex_t **v) const
{
double height;
double heightdiff;
double ofloor, floor;
sector_t *other;
vertex_t *spot;
if (Lines.Size() == 0) return GetPlaneTexZ(sector_t::floor);
spot = Lines[0]->v1;
height = floorplane.ZatPoint(spot);
heightdiff = FLT_MAX;
for (auto check : Lines)
{
if (NULL != (other = getNextSector (check, this)))
{
ofloor = other->floorplane.ZatPoint (check->v1);
floor = floorplane.ZatPoint (check->v1);
if (ofloor > floor && ofloor - floor < heightdiff && !IsLinked(other, false))
{
heightdiff = ofloor - floor;
height = ofloor;
spot = check->v1;
}
ofloor = other->floorplane.ZatPoint (check->v2);
floor = floorplane.ZatPoint (check->v2);
if (ofloor > floor && ofloor - floor < heightdiff && !IsLinked(other, false))
{
heightdiff = ofloor - floor;
height = ofloor;
spot = check->v2;
}
}
}
if (v != NULL)
*v = spot;
return height;
}
DEFINE_ACTION_FUNCTION(_Sector, FindNextHighestFloor)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
vertex_t *v;
double h = self->FindNextHighestFloor(&v);
if (numret > 0) ret[0].SetFloat(h);
if (numret > 1) ret[1].SetPointer(v);
return numret;
}
//
// P_FindNextLowestFloor()
//
// Passed a sector and a floor height, returns the fixed point value
// of the largest floor height in a surrounding sector smaller than
// the floor height passed. If no such height exists the floorheight
// passed is returned.
//
// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this
//
double sector_t::FindNextLowestFloor (vertex_t **v) const
{
double height;
double heightdiff;
double ofloor, floor;
sector_t *other;
vertex_t *spot;
if (Lines.Size() == 0) return GetPlaneTexZ(sector_t::floor);
spot = Lines[0]->v1;
height = floorplane.ZatPoint (spot);
heightdiff = FLT_MAX;
for (auto check : Lines)
{
if (NULL != (other = getNextSector (check, this)))
{
ofloor = other->floorplane.ZatPoint (check->v1);
floor = floorplane.ZatPoint (check->v1);
if (ofloor < floor && floor - ofloor < heightdiff && !IsLinked(other, false))
{
heightdiff = floor - ofloor;
height = ofloor;
spot = check->v1;
}
ofloor = other->floorplane.ZatPoint (check->v2);
floor = floorplane.ZatPoint(check->v2);
if (ofloor < floor && floor - ofloor < heightdiff && !IsLinked(other, false))
{
heightdiff = floor - ofloor;
height = ofloor;
spot = check->v2;
}
}
}
if (v != NULL)
*v = spot;
return height;
}
DEFINE_ACTION_FUNCTION(_Sector, FindNextLowestFloor)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
vertex_t *v;
double h = self->FindNextLowestFloor(&v);
if (numret > 0) ret[0].SetFloat(h);
if (numret > 1) ret[1].SetPointer(v);
return numret;
}
//
// P_FindNextLowestCeiling()
//
// Passed a sector and a ceiling height, returns the fixed point value
// of the largest ceiling height in a surrounding sector smaller than
// the ceiling height passed. If no such height exists the ceiling height
// passed is returned.
//
// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this
//
double sector_t::FindNextLowestCeiling (vertex_t **v) const
{
double height;
double heightdiff;
double oceil, ceil;
sector_t *other;
vertex_t *spot;
if (Lines.Size() == 0) return GetPlaneTexZ(sector_t::floor);
spot = Lines[0]->v1;
height = ceilingplane.ZatPoint(spot);
heightdiff = FLT_MAX;
for (auto check : Lines)
{
if (NULL != (other = getNextSector (check, this)))
{
oceil = other->ceilingplane.ZatPoint(check->v1);
ceil = ceilingplane.ZatPoint(check->v1);
if (oceil < ceil && ceil - oceil < heightdiff && !IsLinked(other, true))
{
heightdiff = ceil - oceil;
height = oceil;
spot = check->v1;
}
oceil = other->ceilingplane.ZatPoint(check->v2);
ceil = ceilingplane.ZatPoint(check->v2);
if (oceil < ceil && ceil - oceil < heightdiff && !IsLinked(other, true))
{
heightdiff = ceil - oceil;
height = oceil;
spot = check->v2;
}
}
}
if (v != NULL)
*v = spot;
return height;
}
DEFINE_ACTION_FUNCTION(_Sector, FindNextLowestCeiling)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
vertex_t *v;
double h = self->FindNextLowestCeiling(&v);
if (numret > 0) ret[0].SetFloat(h);
if (numret > 1) ret[1].SetPointer(v);
return numret;
}
//
// P_FindNextHighestCeiling()
//
// Passed a sector and a ceiling height, returns the fixed point value
// of the smallest ceiling height in a surrounding sector larger than
// the ceiling height passed. If no such height exists the ceiling height
// passed is returned.
//
// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this
//
double sector_t::FindNextHighestCeiling (vertex_t **v) const
{
double height;
double heightdiff;
double oceil, ceil;
sector_t *other;
vertex_t *spot;
if (Lines.Size() == 0) return GetPlaneTexZ(sector_t::ceiling);
spot = Lines[0]->v1;
height = ceilingplane.ZatPoint(spot);
heightdiff = FLT_MAX;
for (auto check : Lines)
{
if (NULL != (other = getNextSector (check, this)))
{
oceil = other->ceilingplane.ZatPoint(check->v1);
ceil = ceilingplane.ZatPoint(check->v1);
if (oceil > ceil && oceil - ceil < heightdiff && !IsLinked(other, true))
{
heightdiff = oceil - ceil;
height = oceil;
spot = check->v1;
}
oceil = other->ceilingplane.ZatPoint(check->v2);
ceil = ceilingplane.ZatPoint(check->v2);
if (oceil > ceil && oceil - ceil < heightdiff && !IsLinked(other, true))
{
heightdiff = oceil - ceil;
height = oceil;
spot = check->v2;
}
}
}
if (v != NULL)
*v = spot;
return height;
}
DEFINE_ACTION_FUNCTION(_Sector, FindNextHighestCeiling)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
vertex_t *v;
double h = self->FindNextHighestCeiling(&v);
if (numret > 0) ret[0].SetFloat(h);
if (numret > 1) ret[1].SetPointer(v);
return numret;
}
//
// FIND LOWEST CEILING IN THE SURROUNDING SECTORS
//
double sector_t::FindLowestCeilingSurrounding (vertex_t **v) const
{
double height;
double oceil;
sector_t *other;
vertex_t *spot;
if (Lines.Size() == 0) return GetPlaneTexZ(sector_t::ceiling);
spot = Lines[0]->v1;
height = FLT_MAX;
for (auto check : Lines)
{
if (NULL != (other = getNextSector (check, this)))
{
oceil = other->ceilingplane.ZatPoint(check->v1);
if (oceil < height)
{
height = oceil;
spot = check->v1;
}
oceil = other->ceilingplane.ZatPoint(check->v2);
if (oceil < height)
{
height = oceil;
spot = check->v2;
}
}
}
if (v != NULL)
*v = spot;
return height;
}
DEFINE_ACTION_FUNCTION(_Sector, FindLowestCeilingSurrounding)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
vertex_t *v;
double h = self->FindLowestCeilingSurrounding(&v);
if (numret > 0) ret[0].SetFloat(h);
if (numret > 1) ret[1].SetPointer(v);
return numret;
}
//
// FIND HIGHEST CEILING IN THE SURROUNDING SECTORS
//
double sector_t::FindHighestCeilingSurrounding (vertex_t **v) const
{
double height;
double oceil;
sector_t *other;
vertex_t *spot;
if (Lines.Size() == 0) return GetPlaneTexZ(sector_t::ceiling);
spot = Lines[0]->v1;
height = -FLT_MAX;
for (auto check : Lines)
{
if (NULL != (other = getNextSector (check, this)))
{
oceil = other->ceilingplane.ZatPoint(check->v1);
if (oceil > height)
{
height = oceil;
spot = check->v1;
}
oceil = other->ceilingplane.ZatPoint(check->v2);
if (oceil > height)
{
height = oceil;
spot = check->v2;
}
}
}
if (v != NULL)
*v = spot;
return height;
}
DEFINE_ACTION_FUNCTION(_Sector, FindHighestCeilingSurrounding)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
vertex_t *v;
double h = self->FindHighestCeilingSurrounding(&v);
if (numret > 0) ret[0].SetFloat(h);
if (numret > 1) ret[1].SetPointer(v);
return numret;
}
//
// P_FindShortestTextureAround()
//
// Passed a sector number, returns the shortest lower texture on a
// linedef bounding the sector.
//
// jff 02/03/98 Add routine to find shortest lower texture
//
static inline void CheckShortestTex (FTextureID texnum, double &minsize)
{
if (texnum.isValid() || (texnum.isNull() && (i_compatflags & COMPATF_SHORTTEX)))
{
FTexture *tex = TexMan[texnum];
if (tex != NULL)
{
double h = tex->GetScaledHeight();
if (h < minsize)
{
minsize = h;
}
}
}
}
double sector_t::FindShortestTextureAround () const
{
double minsize = FLT_MAX;
for (auto check : Lines)
{
if (check->flags & ML_TWOSIDED)
{
CheckShortestTex (check->sidedef[0]->GetTexture(side_t::bottom), minsize);
CheckShortestTex (check->sidedef[1]->GetTexture(side_t::bottom), minsize);
}
}
return minsize < FLT_MAX ? minsize : TexMan[0]->GetHeight();
}
DEFINE_ACTION_FUNCTION(_Sector, FindShortestTextureAround)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
double h = self->FindShortestTextureAround();
ACTION_RETURN_FLOAT(h);
}
//
// P_FindShortestUpperAround()
//
// Passed a sector number, returns the shortest upper texture on a
// linedef bounding the sector.
//
// Note: If no upper texture exists MAXINT is returned.
//
// jff 03/20/98 Add routine to find shortest upper texture
//
double sector_t::FindShortestUpperAround () const
{
double minsize = FLT_MAX;
for (auto check : Lines)
{
if (check->flags & ML_TWOSIDED)
{
CheckShortestTex (check->sidedef[0]->GetTexture(side_t::top), minsize);
CheckShortestTex (check->sidedef[1]->GetTexture(side_t::top), minsize);
}
}
return minsize < FLT_MAX ? minsize : TexMan[0]->GetHeight();
}
DEFINE_ACTION_FUNCTION(_Sector, FindShortestUpperAround)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
double h = self->FindShortestUpperAround();
ACTION_RETURN_FLOAT(h);
}
//
// P_FindModelFloorSector()
//
// Passed a floor height and a sector number, return a pointer to a
// a sector with that floor height across the lowest numbered two sided
// line surrounding the sector.
//
// Note: If no sector at that height bounds the sector passed, return NULL
//
// jff 02/03/98 Add routine to find numeric model floor
// around a sector specified by sector number
// jff 3/14/98 change first parameter to plain height to allow call
// from routine not using floormove_t
//
sector_t *sector_t::FindModelFloorSector (double floordestheight) const
{
sector_t *sec;
for (auto check : Lines)
{
sec = getNextSector (check, this);
if (sec != NULL &&
(sec->floorplane.ZatPoint(check->v1) == floordestheight ||
sec->floorplane.ZatPoint(check->v2) == floordestheight))
{
return sec;
}
}
return NULL;
}
DEFINE_ACTION_FUNCTION(_Sector, FindModelFloorSector)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_FLOAT(fdh);
auto h = self->FindModelFloorSector(fdh);
ACTION_RETURN_POINTER(h);
}
//
// P_FindModelCeilingSector()
//
// Passed a ceiling height and a sector number, return a pointer to a
// a sector with that ceiling height across the lowest numbered two sided
// line surrounding the sector.
//
// Note: If no sector at that height bounds the sector passed, return NULL
//
// jff 02/03/98 Add routine to find numeric model ceiling
// around a sector specified by sector number
// used only from generalized ceiling types
// jff 3/14/98 change first parameter to plain height to allow call
// from routine not using ceiling_t
//
sector_t *sector_t::FindModelCeilingSector (double floordestheight) const
{
sector_t *sec;
for (auto check : Lines)
{
sec = getNextSector (check, this);
if (sec != NULL &&
(sec->ceilingplane.ZatPoint(check->v1) == floordestheight ||
sec->ceilingplane.ZatPoint(check->v2) == floordestheight))
{
return sec;
}
}
return NULL;
}
DEFINE_ACTION_FUNCTION(_Sector, FindModelCeilingSector)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_FLOAT(fdh);
auto h = self->FindModelCeilingSector(fdh);
ACTION_RETURN_POINTER(h);
}
//
// Find minimum light from an adjacent sector
//
int sector_t::FindMinSurroundingLight (int min) const
{
sector_t* check;
for (auto line : Lines)
{
if (NULL != (check = getNextSector (line, this)) &&
check->lightlevel < min)
{
min = check->lightlevel;
}
}
return min;
}
DEFINE_ACTION_FUNCTION(_Sector, FindMinSurroundingLight)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(min);
auto h = self->FindMinSurroundingLight(min);
ACTION_RETURN_INT(h);
}
//
// Find the highest point on the floor of the sector
//
double sector_t::FindHighestFloorPoint (vertex_t **v) const
{
double height = -FLT_MAX;
double probeheight;
vertex_t *spot = NULL;
if (!floorplane.isSlope())
{
if (v != NULL)
{
if (Lines.Size() == 0) *v = &level.vertexes[0];
else *v = Lines[0]->v1;
}
return -floorplane.fD();
}
for (auto line : Lines)
{
probeheight = floorplane.ZatPoint(line->v1);
if (probeheight > height)
{
height = probeheight;
spot = line->v1;
}
probeheight = floorplane.ZatPoint(line->v2);
if (probeheight > height)
{
height = probeheight;
spot = line->v2;
}
}
if (v != NULL)
*v = spot;
return height;
}
DEFINE_ACTION_FUNCTION(_Sector, FindHighestFloorPoint)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
vertex_t *v;
double h = self->FindHighestFloorPoint(&v);
if (numret > 0) ret[0].SetFloat(h);
if (numret > 1) ret[1].SetPointer(v);
return numret;
}
//
// Find the lowest point on the ceiling of the sector
//
double sector_t::FindLowestCeilingPoint (vertex_t **v) const
{
double height = FLT_MAX;
double probeheight;
vertex_t *spot = NULL;
if (!ceilingplane.isSlope())
{
if (v != NULL)
{
if (Lines.Size() == 0) *v = &level.vertexes[0];
else *v = Lines[0]->v1;
}
return ceilingplane.fD();
}
for (auto line : Lines)
{
probeheight = ceilingplane.ZatPoint(line->v1);
if (probeheight < height)
{
height = probeheight;
spot = line->v1;
}
probeheight = ceilingplane.ZatPoint(line->v2);
if (probeheight < height)
{
height = probeheight;
spot = line->v2;
}
}
if (v != NULL)
*v = spot;
return height;
}
DEFINE_ACTION_FUNCTION(_Sector, FindLowestCeilingPoint)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
vertex_t *v;
double h = self->FindLowestCeilingPoint(&v);
if (numret > 0) ret[0].SetFloat(h);
if (numret > 1) ret[1].SetPointer(v);
return numret;
}
//=====================================================================================
//
//
//=====================================================================================
void sector_t::SetColor(int r, int g, int b, int desat)
{
Colormap.LightColor = PalEntry(r, g, b);
Colormap.Desaturation = desat;
P_RecalculateAttachedLights(this);
}
DEFINE_ACTION_FUNCTION(_Sector, SetColor)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_COLOR(color);
PARAM_INT(desat);
self->Colormap.LightColor.SetRGB(color);
self->Colormap.Desaturation = desat;
P_RecalculateAttachedLights(self);
return 0;
}
//=====================================================================================
//
//
//=====================================================================================
void sector_t::SetFade(int r, int g, int b)
{
Colormap.FadeColor = PalEntry (r,g,b);
P_RecalculateAttachedLights(this);
}
DEFINE_ACTION_FUNCTION(_Sector, SetFade)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_COLOR(fade);
self->Colormap.FadeColor.SetRGB(fade);
P_RecalculateAttachedLights(self);
return 0;
}
//=====================================================================================
//
//
//=====================================================================================
void sector_t::SetSpecialColor(int slot, int r, int g, int b)
{
SpecialColors[slot] = PalEntry(255, r, g, b);
}
void sector_t::SetSpecialColor(int slot, PalEntry rgb)
{
rgb.a = 255;
SpecialColors[slot] = rgb;
}
DEFINE_ACTION_FUNCTION(_Sector, SetSpecialColor)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(num);
PARAM_COLOR(color);
if (num >= 0 && num < 5)
{
color.a = 255;
self->SetSpecialColor(num, color);
}
return 0;
}
//=====================================================================================
//
//
//=====================================================================================
void sector_t::SetFogDensity(int dens)
{
Colormap.FogDensity = dens;
}
DEFINE_ACTION_FUNCTION(_Sector, SetFogDensity)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(dens);
self->Colormap.FogDensity = dens;
return 0;
}
//===========================================================================
//
// sector_t :: ClosestPoint
//
// Given a point (x,y), returns the point (ox,oy) on the sector's defining
// lines that is nearest to (x,y).
//
//===========================================================================
void sector_t::ClosestPoint(const DVector2 &in, DVector2 &out) const
{
double x = in.X, y = in.Y;
double bestdist = HUGE_VAL;
double bestx = 0, besty = 0;
for (auto check : Lines)
{
vertex_t *v1 = check->v1;
vertex_t *v2 = check->v2;
double a = v2->fX() - v1->fX();
double b = v2->fY() - v1->fY();
double den = a*a + b*b;
double ix, iy, dist;
if (den == 0)
{ // Line is actually a point!
ix = v1->fX();
iy = v1->fY();
}
else
{
double num = (x - v1->fX()) * a + (y - v1->fY()) * b;
double u = num / den;
if (u <= 0)
{
ix = v1->fX();
iy = v1->fY();
}
else if (u >= 1)
{
ix = v2->fX();
iy = v2->fY();
}
else
{
ix = v1->fX() + u * a;
iy = v1->fY() + u * b;
}
}
a = (ix - x);
b = (iy - y);
dist = a*a + b*b;
if (dist < bestdist)
{
bestdist = dist;
bestx = ix;
besty = iy;
}
}
out = { bestx, besty };
}
//=====================================================================================
//
//
//=====================================================================================
bool sector_t::PlaneMoving(int pos)
{
if (pos == floor)
return (floordata != NULL || (planes[floor].Flags & PLANEF_BLOCKED));
else
return (ceilingdata != NULL || (planes[ceiling].Flags & PLANEF_BLOCKED));
}
DEFINE_ACTION_FUNCTION(_Sector, PlaneMoving)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
ACTION_RETURN_BOOL(self->PlaneMoving(pos));
}
//=====================================================================================
//
//
//=====================================================================================
int sector_t::GetFloorLight () const
{
if (GetFlags(sector_t::floor) & PLANEF_ABSLIGHTING)
{
return GetPlaneLight(floor);
}
else
{
return ClampLight(lightlevel + GetPlaneLight(floor));
}
}
DEFINE_ACTION_FUNCTION(_Sector, GetFloorLight)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
ACTION_RETURN_INT(self->GetFloorLight());
}
//=====================================================================================
//
//
//=====================================================================================
int sector_t::GetCeilingLight () const
{
if (GetFlags(ceiling) & PLANEF_ABSLIGHTING)
{
return GetPlaneLight(ceiling);
}
else
{
return ClampLight(lightlevel + GetPlaneLight(ceiling));
}
}
DEFINE_ACTION_FUNCTION(_Sector, GetCeilingLight)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
ACTION_RETURN_INT(self->GetCeilingLight());
}
//=====================================================================================
//
//
//=====================================================================================
FSectorPortal *sector_t::ValidatePortal(int which)
{
FSectorPortal *port = GetPortal(which);
if (port->mType == PORTS_SKYVIEWPOINT && port->mSkybox == nullptr) return nullptr; // A skybox without a viewpoint is just a regular sky.
if (PortalBlocksView(which)) return nullptr; // disabled or obstructed linked portal.
if ((port->mFlags & PORTSF_SKYFLATONLY) && GetTexture(which) != skyflatnum) return nullptr; // Skybox without skyflat texture
return port;
}
//=====================================================================================
//
//
//=====================================================================================
DEFINE_ACTION_FUNCTION(_Sector, GetHeightSec)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
ACTION_RETURN_POINTER(self->GetHeightSec());
}
//=====================================================================================
//
//
//=====================================================================================
void sector_t::GetSpecial(secspecial_t *spec)
{
spec->special = special;
spec->damageamount = damageamount;
spec->damagetype = damagetype;
spec->damageinterval = damageinterval;
spec->leakydamage = leakydamage;
spec->Flags = Flags & SECF_SPECIALFLAGS;
}
DEFINE_ACTION_FUNCTION(_Sector, GetSpecial)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_POINTER(spec, secspecial_t);
self->GetSpecial(spec);
return 0;
}
//=====================================================================================
//
//
//=====================================================================================
void sector_t::SetSpecial(const secspecial_t *spec)
{
special = spec->special;
damageamount = spec->damageamount;
damagetype = spec->damagetype;
damageinterval = spec->damageinterval;
leakydamage = spec->leakydamage;
Flags = (Flags & ~SECF_SPECIALFLAGS) | (spec->Flags & SECF_SPECIALFLAGS);
}
DEFINE_ACTION_FUNCTION(_Sector, SetSpecial)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_POINTER(spec, secspecial_t);
self->SetSpecial(spec);
return 0;
}
//=====================================================================================
//
//
//=====================================================================================
void sector_t::TransferSpecial(sector_t *model)
{
special = model->special;
damageamount = model->damageamount;
damagetype = model->damagetype;
damageinterval = model->damageinterval;
leakydamage = model->leakydamage;
Flags = (Flags&~SECF_SPECIALFLAGS) | (model->Flags & SECF_SPECIALFLAGS);
}
DEFINE_ACTION_FUNCTION(_Sector, TransferSpecial)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_POINTER(spec, sector_t);
self->TransferSpecial(spec);
return 0;
}
//=====================================================================================
//
//
//=====================================================================================
int sector_t::GetTerrain(int pos) const
{
return terrainnum[pos] >= 0 ? terrainnum[pos] : TerrainTypes[GetTexture(pos)];
}
DEFINE_ACTION_FUNCTION(_Sector, GetTerrain)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
ACTION_RETURN_INT(self->GetTerrain(pos));
}
//=====================================================================================
//
//
//=====================================================================================
void sector_t::CheckPortalPlane(int plane)
{
if (GetPortalType(plane) == PORTS_LINKEDPORTAL)
{
double portalh = GetPortalPlaneZ(plane);
double planeh = GetPlaneTexZ(plane);
int obstructed = PLANEF_OBSTRUCTED * (plane == sector_t::floor ? planeh > portalh : planeh < portalh);
planes[plane].Flags = (planes[plane].Flags & ~PLANEF_OBSTRUCTED) | obstructed;
}
}
DEFINE_ACTION_FUNCTION(_Sector, CheckPortalPlane)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(plane);
self->CheckPortalPlane(plane);
return 0;
}
//===========================================================================
//
// Finds the highest ceiling at the given position, all portals considered
//
//===========================================================================
double sector_t::HighestCeilingAt(const DVector2 &p, sector_t **resultsec)
{
sector_t *check = this;
double planeheight = -FLT_MAX;
DVector2 pos = p;
// Continue until we find a blocking portal or a portal below where we actually are.
while (!check->PortalBlocksMovement(ceiling) && planeheight < check->GetPortalPlaneZ(ceiling))
{
pos += check->GetPortalDisplacement(ceiling);
planeheight = check->GetPortalPlaneZ(ceiling);
check = P_PointInSector(pos);
}
if (resultsec) *resultsec = check;
return check->ceilingplane.ZatPoint(pos);
}
DEFINE_ACTION_FUNCTION(_Sector, HighestCeilingAt)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
sector_t *s;
double h = self->HighestCeilingAt(DVector2(x, y), &s);
if (numret > 0) ret[0].SetFloat(h);
if (numret > 1) ret[1].SetPointer(s);
return numret;
}
//===========================================================================
//
// Finds the lowest floor at the given position, all portals considered
//
//===========================================================================
double sector_t::LowestFloorAt(const DVector2 &p, sector_t **resultsec)
{
sector_t *check = this;
double planeheight = FLT_MAX;
DVector2 pos = p;
// Continue until we find a blocking portal or a portal above where we actually are.
while (!check->PortalBlocksMovement(floor) && planeheight > check->GetPortalPlaneZ(floor))
{
pos += check->GetPortalDisplacement(floor);
planeheight = check->GetPortalPlaneZ(ceiling);
check = P_PointInSector(pos);
}
if (resultsec) *resultsec = check;
return check->floorplane.ZatPoint(pos);
}
DEFINE_ACTION_FUNCTION(_Sector, LowestFloorAt)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
sector_t *s;
double h = self->LowestFloorAt(DVector2(x, y), &s);
if (numret > 0) ret[0].SetFloat(h);
if (numret > 1) ret[1].SetPointer(s);
return numret;
}
//=====================================================================================
//
//
//=====================================================================================
double sector_t::NextHighestCeilingAt(double x, double y, double bottomz, double topz, int flags, sector_t **resultsec, F3DFloor **resultffloor)
{
sector_t *sec = this;
double planeheight = -FLT_MAX;
while (true)
{
// Looking through planes from bottom to top
double realceil = sec->ceilingplane.ZatPoint(x, y);
for (int i = sec->e->XFloor.ffloors.Size() - 1; i >= 0; --i)
{
F3DFloor *rover = sec->e->XFloor.ffloors[i];
if (!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue;
double ff_bottom = rover->bottom.plane->ZatPoint(x, y);
double ff_top = rover->top.plane->ZatPoint(x, y);
double delta1 = bottomz - (ff_bottom + ((ff_top - ff_bottom) / 2));
double delta2 = topz - (ff_bottom + ((ff_top - ff_bottom) / 2));
if (ff_bottom < realceil && fabs(delta1) > fabs(delta2))
{
if (resultsec) *resultsec = sec;
if (resultffloor) *resultffloor = rover;
return ff_bottom;
}
}
if ((flags & FFCF_NOPORTALS) || sec->PortalBlocksMovement(ceiling) || planeheight >= sec->GetPortalPlaneZ(ceiling))
{ // Use sector's ceiling
if (resultffloor) *resultffloor = NULL;
if (resultsec) *resultsec = sec;
return realceil;
}
else
{
DVector2 pos = sec->GetPortalDisplacement(ceiling);
x += pos.X;
y += pos.Y;
planeheight = sec->GetPortalPlaneZ(ceiling);
sec = P_PointInSector(x, y);
}
}
}
DEFINE_ACTION_FUNCTION(_Sector, NextHighestCeilingAt)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
PARAM_FLOAT(bottomz);
PARAM_FLOAT(topz);
PARAM_INT_DEF(flags);
sector_t *resultsec;
F3DFloor *resultff;
double resultheight = self->NextHighestCeilingAt(x, y, bottomz, topz, flags, &resultsec, &resultff);
if (numret > 2)
{
ret[2].SetPointer(resultff);
numret = 3;
}
if (numret > 1)
{
ret[1].SetPointer(resultsec);
}
if (numret > 0)
{
ret[0].SetFloat(resultheight);
}
return numret;
}
//=====================================================================================
//
//
//=====================================================================================
double sector_t::NextLowestFloorAt(double x, double y, double z, int flags, double steph, sector_t **resultsec, F3DFloor **resultffloor)
{
sector_t *sec = this;
double planeheight = FLT_MAX;
while (true)
{
// Looking through planes from top to bottom
unsigned numff = sec->e->XFloor.ffloors.Size();
double realfloor = sec->floorplane.ZatPoint(x, y);
for (unsigned i = 0; i < numff; ++i)
{
F3DFloor *ff = sec->e->XFloor.ffloors[i];
// either with feet above the 3D floor or feet with less than 'stepheight' map units inside
if ((ff->flags & (FF_EXISTS | FF_SOLID)) == (FF_EXISTS | FF_SOLID))
{
double ffz = ff->top.plane->ZatPoint(x, y);
double ffb = ff->bottom.plane->ZatPoint(x, y);
if (ffz > realfloor && (z >= ffz || (!(flags & FFCF_3DRESTRICT) && (ffb < z && ffz < z + steph))))
{ // This floor is beneath our feet.
if (resultsec) *resultsec = sec;
if (resultffloor) *resultffloor = ff;
return ffz;
}
}
}
if ((flags & FFCF_NOPORTALS) || sec->PortalBlocksMovement(sector_t::floor) || planeheight <= sec->GetPortalPlaneZ(floor))
{ // Use sector's floor
if (resultffloor) *resultffloor = NULL;
if (resultsec) *resultsec = sec;
return realfloor;
}
else
{
DVector2 pos = sec->GetPortalDisplacement(floor);
x += pos.X;
y += pos.Y;
planeheight = sec->GetPortalPlaneZ(floor);
sec = P_PointInSector(x, y);
}
}
}
DEFINE_ACTION_FUNCTION(_Sector, NextLowestFloorAt)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
PARAM_FLOAT(z);
PARAM_INT_DEF(flags);
PARAM_FLOAT_DEF(steph);
sector_t *resultsec;
F3DFloor *resultff;
double resultheight = self->NextLowestFloorAt(x, y, z, flags, steph, &resultsec, &resultff);
if (numret > 2)
{
ret[2].SetPointer(resultff);
numret = 3;
}
if (numret > 1)
{
ret[1].SetPointer(resultsec);
}
if (numret > 0)
{
ret[0].SetFloat(resultheight);
}
return numret;
}
//===========================================================================
//
//
//
//===========================================================================
double sector_t::GetFriction(int plane, double *pMoveFac) const
{
if (Flags & SECF_FRICTION)
{
if (pMoveFac) *pMoveFac = movefactor;
return friction;
}
FTerrainDef *terrain = &Terrains[GetTerrain(plane)];
if (terrain->Friction != 0)
{
if (pMoveFac) *pMoveFac = terrain->MoveFactor;
return terrain->Friction;
}
else
{
if (pMoveFac) *pMoveFac = ORIG_FRICTION_FACTOR;
return ORIG_FRICTION;
}
}
DEFINE_ACTION_FUNCTION(_Sector, GetFriction)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(plane);
double mf;
double h = self->GetFriction(plane, &mf);
if (numret > 0) ret[0].SetFloat(h);
if (numret > 1) ret[1].SetFloat(mf);
return numret;
}
//===========================================================================
//
//
//
//===========================================================================
void sector_t::RemoveForceField()
{
for (auto line : Lines)
{
if (line->backsector != NULL && line->special == ForceField)
{
line->flags &= ~(ML_BLOCKING | ML_BLOCKEVERYTHING);
line->special = 0;
line->sidedef[0]->SetTexture(side_t::mid, FNullTextureID());
line->sidedef[1]->SetTexture(side_t::mid, FNullTextureID());
}
}
}
DEFINE_ACTION_FUNCTION(_Sector, RemoveForceField)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
self->RemoveForceField();
return 0;
}
//===========================================================================
//
// phares 3/12/98: End of friction effects
//
//===========================================================================
void sector_t::AdjustFloorClip() const
{
msecnode_t *node;
for (node = touching_thinglist; node; node = node->m_snext)
{
if (node->m_thing->flags2 & MF2_FLOORCLIP)
{
node->m_thing->AdjustFloorClip();
}
}
}
DEFINE_ACTION_FUNCTION(_Sector, AdjustFloorClip)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
self->AdjustFloorClip();
return 0;
}
//==========================================================================
//
// Checks whether a sprite should be affected by a glow
//
//==========================================================================
int sector_t::CheckSpriteGlow(int lightlevel, const DVector3 &pos)
{
float bottomglowcolor[4];
bottomglowcolor[3] = 0;
auto c = planes[sector_t::floor].GlowColor;
if (c == 0)
{
FTexture *tex = TexMan[GetTexture(sector_t::floor)];
if (tex != NULL && tex->isGlowing())
{
if (!tex->bAutoGlowing) tex = TexMan(GetTexture(sector_t::floor));
if (tex->isGlowing()) // recheck the current animation frame.
{
tex->GetGlowColor(bottomglowcolor);
bottomglowcolor[3] = (float)tex->GlowHeight;
}
}
}
else if (c != ~0u)
{
bottomglowcolor[0] = c.r / 255.f;
bottomglowcolor[1] = c.g / 255.f;
bottomglowcolor[2] = c.b / 255.f;
bottomglowcolor[3] = planes[sector_t::floor].GlowHeight;
}
if (bottomglowcolor[3]> 0)
{
double floordiff = pos.Z - floorplane.ZatPoint(pos);
if (floordiff < bottomglowcolor[3])
{
int maxlight = (255 + lightlevel) >> 1;
double lightfrac = floordiff / bottomglowcolor[3];
if (lightfrac < 0) lightfrac = 0;
lightlevel = int(lightfrac*lightlevel + maxlight * (1 - lightfrac));
}
}
return lightlevel;
}
//==========================================================================
//
// Checks whether a wall should glow
//
//==========================================================================
bool sector_t::GetWallGlow(float *topglowcolor, float *bottomglowcolor)
{
bool ret = false;
bottomglowcolor[3] = topglowcolor[3] = 0;
auto c = planes[sector_t::ceiling].GlowColor;
if (c == 0)
{
FTexture *tex = TexMan[GetTexture(sector_t::ceiling)];
if (tex != NULL && tex->isGlowing())
{
if (!tex->bAutoGlowing) tex = TexMan(GetTexture(sector_t::ceiling));
if (tex->isGlowing()) // recheck the current animation frame.
{
ret = true;
tex->GetGlowColor(topglowcolor);
topglowcolor[3] = (float)tex->GlowHeight;
}
}
}
else if (c != ~0u)
{
topglowcolor[0] = c.r / 255.f;
topglowcolor[1] = c.g / 255.f;
topglowcolor[2] = c.b / 255.f;
topglowcolor[3] = planes[sector_t::ceiling].GlowHeight;
ret = topglowcolor[3] > 0;
}
c = planes[sector_t::floor].GlowColor;
if (c == 0)
{
FTexture *tex = TexMan[GetTexture(sector_t::floor)];
if (tex != NULL && tex->isGlowing())
{
if (!tex->bAutoGlowing) tex = TexMan(GetTexture(sector_t::floor));
if (tex->isGlowing()) // recheck the current animation frame.
{
ret = true;
tex->GetGlowColor(bottomglowcolor);
bottomglowcolor[3] = (float)tex->GlowHeight;
}
}
}
else if (c != ~0u)
{
bottomglowcolor[0] = c.r / 255.f;
bottomglowcolor[1] = c.g / 255.f;
bottomglowcolor[2] = c.b / 255.f;
bottomglowcolor[3] = planes[sector_t::floor].GlowHeight;
ret = bottomglowcolor[3] > 0;
}
return ret;
}
//===========================================================================
//
//
//
//===========================================================================
bool sector_t::TriggerSectorActions(AActor *thing, int activation)
{
AActor *act = SecActTarget;
bool res = false;
while (act != nullptr)
{
AActor *next = act->tracer;
IFVIRTUALPTRNAME(act, "SectorAction", TriggerAction)
{
VMValue params[3] = { (DObject *)act, thing, activation };
VMReturn ret;
int didit;
ret.IntAt(&didit);
VMCall(func, params, 3, &ret, 1);
if (didit)
{
if (act->flags4 & MF4_STANDSTILL)
{
act->Destroy();
}
}
act = next;
res |= !!didit;
}
}
return res;
}
DEFINE_ACTION_FUNCTION(_Sector, TriggerSectorActions)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_OBJECT(thing, AActor);
PARAM_INT(activation);
ACTION_RETURN_BOOL(self->TriggerSectorActions(thing, activation));
}
//===========================================================================
//
// checks if the floor is higher than the ceiling and sets a flag
// This condition needs to be tested by the hardware renderer,
// so always having its state available in a flag allows for easier optimization.
//
//===========================================================================
void sector_t::CheckOverlap()
{
if (planes[sector_t::floor].TexZ > planes[sector_t::ceiling].TexZ && !floorplane.isSlope() && !ceilingplane.isSlope())
{
MoreFlags |= SECMF_OVERLAPPING;
}
else
{
MoreFlags &= ~SECMF_OVERLAPPING;
}
}
//===========================================================================
//
//
//
//===========================================================================
DEFINE_ACTION_FUNCTION(_Sector, PointInSector)
{
PARAM_PROLOGUE;
PARAM_FLOAT(x);
PARAM_FLOAT(y);
ACTION_RETURN_POINTER(P_PointInSector(x, y));
}
DEFINE_ACTION_FUNCTION(_Sector, SetXOffset)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
PARAM_FLOAT(o);
self->SetXOffset(pos, o);
return 0;
}
DEFINE_ACTION_FUNCTION(_Sector, AddXOffset)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
PARAM_FLOAT(o);
self->AddXOffset(pos, o);
return 0;
}
DEFINE_ACTION_FUNCTION(_Sector, GetXOffset)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
ACTION_RETURN_FLOAT(self->GetXOffset(pos));
}
DEFINE_ACTION_FUNCTION(_Sector, SetYOffset)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
PARAM_FLOAT(o);
self->SetXOffset(pos, o);
return 0;
}
DEFINE_ACTION_FUNCTION(_Sector, AddYOffset)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
PARAM_FLOAT(o);
self->AddXOffset(pos, o);
return 0;
}
DEFINE_ACTION_FUNCTION(_Sector, GetYOffset)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
PARAM_BOOL_DEF(addbase);
ACTION_RETURN_FLOAT(self->GetYOffset(pos, addbase));
}
DEFINE_ACTION_FUNCTION(_Sector, SetXScale)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
PARAM_FLOAT(o);
self->SetXScale(pos, o);
return 0;
}
DEFINE_ACTION_FUNCTION(_Sector, GetXScale)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
ACTION_RETURN_FLOAT(self->GetXScale(pos));
}
DEFINE_ACTION_FUNCTION(_Sector, SetYScale)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
PARAM_FLOAT(o);
self->SetYScale(pos, o);
return 0;
}
DEFINE_ACTION_FUNCTION(_Sector, GetYScale)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
ACTION_RETURN_FLOAT(self->GetYScale(pos));
}
DEFINE_ACTION_FUNCTION(_Sector, SetAngle)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
PARAM_ANGLE(o);
self->SetAngle(pos, o);
return 0;
}
DEFINE_ACTION_FUNCTION(_Sector, GetAngle)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
PARAM_BOOL_DEF(addbase);
ACTION_RETURN_FLOAT(self->GetAngle(pos, addbase).Degrees);
}
DEFINE_ACTION_FUNCTION(_Sector, SetBase)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
PARAM_FLOAT(o);
PARAM_ANGLE(a);
self->SetBase(pos, o, a);
return 0;
}
DEFINE_ACTION_FUNCTION(_Sector, SetAlpha)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
PARAM_FLOAT(o);
self->SetAlpha(pos, o);
return 0;
}
DEFINE_ACTION_FUNCTION(_Sector, GetAlpha)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
ACTION_RETURN_FLOAT(self->GetAlpha(pos));
}
DEFINE_ACTION_FUNCTION(_Sector, GetFlags)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
ACTION_RETURN_INT(self->GetFlags(pos));
}
DEFINE_ACTION_FUNCTION(_Sector, GetVisFlags)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
ACTION_RETURN_INT(self->GetVisFlags(pos));
}
DEFINE_ACTION_FUNCTION(_Sector, ChangeFlags)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
PARAM_INT(a);
PARAM_INT(o);
self->ChangeFlags(pos, a, o);
return 0;
}
DEFINE_ACTION_FUNCTION(_Sector, SetPlaneLight)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
PARAM_INT(o);
self->SetPlaneLight(pos, o);
return 0;
}
DEFINE_ACTION_FUNCTION(_Sector, GetPlaneLight)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
ACTION_RETURN_INT(self->GetPlaneLight(pos));
}
DEFINE_ACTION_FUNCTION(_Sector, SetTexture)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
PARAM_INT(o);
PARAM_BOOL_DEF(adj);
self->SetTexture(pos, FSetTextureID(o), adj);
return 0;
}
DEFINE_ACTION_FUNCTION(_Sector, GetTexture)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
ACTION_RETURN_INT(self->GetTexture(pos).GetIndex());
}
DEFINE_ACTION_FUNCTION(_Sector, SetPlaneTexZ)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
PARAM_FLOAT(o);
PARAM_BOOL_DEF(dirty);
self->SetPlaneTexZ(pos, o, true); // not setting 'dirty' here is a guaranteed cause for problems.
return 0;
}
DEFINE_ACTION_FUNCTION(_Sector, GetPlaneTexZ)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
ACTION_RETURN_FLOAT(self->GetPlaneTexZ(pos));
}
DEFINE_ACTION_FUNCTION(_Sector, SetLightLevel)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(o);
self->SetLightLevel(o);
return 0;
}
DEFINE_ACTION_FUNCTION(_Sector, ChangeLightLevel)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(o);
self->ChangeLightLevel(o);
return 0;
}
DEFINE_ACTION_FUNCTION(_Sector, GetLightLevel)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
ACTION_RETURN_INT(self->GetLightLevel());
}
DEFINE_ACTION_FUNCTION(_Sector, ClearSpecial)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
self->ClearSpecial();
return 0;
}
DEFINE_ACTION_FUNCTION(_Sector, PortalBlocksView)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
ACTION_RETURN_BOOL(self->PortalBlocksView(pos));
}
DEFINE_ACTION_FUNCTION(_Sector, PortalBlocksSight)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
ACTION_RETURN_BOOL(self->PortalBlocksSight(pos));
}
DEFINE_ACTION_FUNCTION(_Sector, PortalBlocksMovement)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
ACTION_RETURN_BOOL(self->PortalBlocksMovement(pos));
}
DEFINE_ACTION_FUNCTION(_Sector, PortalBlocksSound)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
ACTION_RETURN_BOOL(self->PortalBlocksSound(pos));
}
DEFINE_ACTION_FUNCTION(_Sector, PortalIsLinked)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
ACTION_RETURN_BOOL(self->PortalIsLinked(pos));
}
DEFINE_ACTION_FUNCTION(_Sector, ClearPortal)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
self->ClearPortal(pos);
return 0;
}
DEFINE_ACTION_FUNCTION(_Sector, GetPortalPlaneZ)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
ACTION_RETURN_FLOAT(self->GetPortalPlaneZ(pos));
}
DEFINE_ACTION_FUNCTION(_Sector, GetPortalDisplacement)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
ACTION_RETURN_VEC2(self->GetPortalDisplacement(pos));
}
DEFINE_ACTION_FUNCTION(_Sector, GetPortalType)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
ACTION_RETURN_INT(self->GetPortalType(pos));
}
DEFINE_ACTION_FUNCTION(_Sector, GetOppositePortalGroup)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
ACTION_RETURN_INT(self->GetOppositePortalGroup(pos));
}
DEFINE_ACTION_FUNCTION(_Sector, CenterFloor)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
ACTION_RETURN_FLOAT(self->CenterFloor());
}
DEFINE_ACTION_FUNCTION(_Sector, CenterCeiling)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
ACTION_RETURN_FLOAT(self->CenterCeiling());
}
DEFINE_ACTION_FUNCTION(_Sector, Index)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
unsigned ndx = self->Index();
if (ndx >= level.sectors.Size())
{
// This qualifies as an array out of bounds exception. Normally it can only happen when a sector copy is concerned which scripts should not be able to create.
ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Accessed invalid sector");
}
ACTION_RETURN_INT(ndx);
}
DEFINE_ACTION_FUNCTION(_Sector, SetEnvironmentID)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(envnum);
level.Zones[self->ZoneNumber].Environment = S_FindEnvironment(envnum);
return 0;
}
DEFINE_ACTION_FUNCTION(_Sector, SetEnvironment)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_STRING(env);
level.Zones[self->ZoneNumber].Environment = S_FindEnvironment(env);
return 0;
}
DEFINE_ACTION_FUNCTION(_Sector, GetGlowHeight)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
ACTION_RETURN_FLOAT(self->GetGlowHeight(pos));
}
DEFINE_ACTION_FUNCTION(_Sector, GetGlowColor)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
ACTION_RETURN_INT(self->GetGlowColor(pos));
}
DEFINE_ACTION_FUNCTION(_Sector, SetGlowHeight)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
PARAM_FLOAT(o);
self->SetGlowHeight(pos, float(o));
return 0;
}
DEFINE_ACTION_FUNCTION(_Sector, SetGlowColor)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_INT(pos);
PARAM_COLOR(o);
self->SetGlowColor(pos, o);
return 0;
}
//===========================================================================
//
// line_t exports
//
//===========================================================================
DEFINE_ACTION_FUNCTION(_Line, isLinePortal)
{
PARAM_SELF_STRUCT_PROLOGUE(line_t);
ACTION_RETURN_BOOL(self->isLinePortal());
}
DEFINE_ACTION_FUNCTION(_Line, isVisualPortal)
{
PARAM_SELF_STRUCT_PROLOGUE(line_t);
ACTION_RETURN_BOOL(self->isVisualPortal());
}
DEFINE_ACTION_FUNCTION(_Line, getPortalDestination)
{
PARAM_SELF_STRUCT_PROLOGUE(line_t);
ACTION_RETURN_POINTER(self->getPortalDestination());
}
DEFINE_ACTION_FUNCTION(_Line, getPortalAlignment)
{
PARAM_SELF_STRUCT_PROLOGUE(line_t);
ACTION_RETURN_INT(self->getPortalAlignment());
}
DEFINE_ACTION_FUNCTION(_Line, Index)
{
PARAM_SELF_STRUCT_PROLOGUE(line_t);
unsigned ndx = self->Index();
if (ndx >= level.lines.Size())
{
ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Accessed invalid line");
}
ACTION_RETURN_INT(ndx);
}
//===========================================================================
//
//
//
//===========================================================================
DEFINE_ACTION_FUNCTION(_Side, GetTexture)
{
PARAM_SELF_STRUCT_PROLOGUE(side_t);
PARAM_INT(which);
ACTION_RETURN_INT(self->GetTexture(which).GetIndex());
}
DEFINE_ACTION_FUNCTION(_Side, SetTexture)
{
PARAM_SELF_STRUCT_PROLOGUE(side_t);
PARAM_INT(which);
PARAM_INT(tex);
self->SetTexture(which, FSetTextureID(tex));
return 0;
}
DEFINE_ACTION_FUNCTION(_Side, SetTextureXOffset)
{
PARAM_SELF_STRUCT_PROLOGUE(side_t);
PARAM_INT(which);
PARAM_FLOAT(ofs);
self->SetTextureXOffset(which, ofs);
return 0;
}
DEFINE_ACTION_FUNCTION(_Side, AddTextureXOffset)
{
PARAM_SELF_STRUCT_PROLOGUE(side_t);
PARAM_INT(which);
PARAM_FLOAT(ofs);
self->AddTextureXOffset(which, ofs);
return 0;
}
DEFINE_ACTION_FUNCTION(_Side, GetTextureXOffset)
{
PARAM_SELF_STRUCT_PROLOGUE(side_t);
PARAM_INT(which);
ACTION_RETURN_FLOAT(self->GetTextureXOffset(which));
}
DEFINE_ACTION_FUNCTION(_Side, SetTextureYOffset)
{
PARAM_SELF_STRUCT_PROLOGUE(side_t);
PARAM_INT(which);
PARAM_FLOAT(ofs);
self->SetTextureYOffset(which, ofs);
return 0;
}
DEFINE_ACTION_FUNCTION(_Side, AddTextureYOffset)
{
PARAM_SELF_STRUCT_PROLOGUE(side_t);
PARAM_INT(which);
PARAM_FLOAT(ofs);
self->AddTextureYOffset(which, ofs);
return 0;
}
DEFINE_ACTION_FUNCTION(_Side, GetTextureYOffset)
{
PARAM_SELF_STRUCT_PROLOGUE(side_t);
PARAM_INT(which);
ACTION_RETURN_FLOAT(self->GetTextureYOffset(which));
}
DEFINE_ACTION_FUNCTION(_Side, SetTextureXScale)
{
PARAM_SELF_STRUCT_PROLOGUE(side_t);
PARAM_INT(which);
PARAM_FLOAT(ofs);
self->SetTextureXScale(which, ofs);
return 0;
}
DEFINE_ACTION_FUNCTION(_Side, MultiplyTextureXScale)
{
PARAM_SELF_STRUCT_PROLOGUE(side_t);
PARAM_INT(which);
PARAM_FLOAT(ofs);
self->MultiplyTextureXScale(which, ofs);
return 0;
}
DEFINE_ACTION_FUNCTION(_Side, GetTextureXScale)
{
PARAM_SELF_STRUCT_PROLOGUE(side_t);
PARAM_INT(which);
ACTION_RETURN_FLOAT(self->GetTextureXScale(which));
}
DEFINE_ACTION_FUNCTION(_Side, SetTextureYScale)
{
PARAM_SELF_STRUCT_PROLOGUE(side_t);
PARAM_INT(which);
PARAM_FLOAT(ofs);
self->SetTextureYScale(which, ofs);
return 0;
}
DEFINE_ACTION_FUNCTION(_Side, MultiplyTextureYScale)
{
PARAM_SELF_STRUCT_PROLOGUE(side_t);
PARAM_INT(which);
PARAM_FLOAT(ofs);
self->MultiplyTextureYScale(which, ofs);
return 0;
}
DEFINE_ACTION_FUNCTION(_Side, GetTextureYScale)
{
PARAM_SELF_STRUCT_PROLOGUE(side_t);
PARAM_INT(which);
ACTION_RETURN_FLOAT(self->GetTextureYScale(which));
}
DEFINE_ACTION_FUNCTION(_Side, V1)
{
PARAM_SELF_STRUCT_PROLOGUE(side_t);
ACTION_RETURN_POINTER(self->V1());
}
DEFINE_ACTION_FUNCTION(_Side, V2)
{
PARAM_SELF_STRUCT_PROLOGUE(side_t);
ACTION_RETURN_POINTER(self->V2());
}
DEFINE_ACTION_FUNCTION(_Side, Index)
{
PARAM_SELF_STRUCT_PROLOGUE(side_t);
ACTION_RETURN_INT(self->Index());
}
DEFINE_ACTION_FUNCTION(_Vertex, Index)
{
PARAM_SELF_STRUCT_PROLOGUE(vertex_t);
ACTION_RETURN_INT(self->Index());
}
//===========================================================================
//
//
//
//===========================================================================
FSerializer &Serialize(FSerializer &arc, const char *key, secspecial_t &spec, secspecial_t *def)
{
if (arc.BeginObject(key))
{
arc("special", spec.special)
("damageamount", spec.damageamount)
("damagetype", spec.damagetype)
("damageinterval", spec.damageinterval)
("leakydamage", spec.leakydamage)
("flags", spec.Flags)
.EndObject();
}
return arc;
}
//===========================================================================
//
//
//
//===========================================================================
bool secplane_t::CopyPlaneIfValid (secplane_t *dest, const secplane_t *opp) const
{
bool copy = false;
// If the planes do not have matching slopes, then always copy them
// because clipping would require creating new sectors.
if (Normal() != dest->Normal())
{
copy = true;
}
else if (opp->Normal() != -dest->Normal())
{
if (fD() < dest->fD())
{
copy = true;
}
}
else if (fD() < dest->fD() && fD() > -opp->fD())
{
copy = true;
}
if (copy)
{
*dest = *this;
}
return copy;
}
//==========================================================================
//
// P_AlignFlat
//
//==========================================================================
bool P_AlignFlat (int linenum, int side, int fc)
{
line_t *line = &level.lines[linenum];
sector_t *sec = side ? line->backsector : line->frontsector;
if (!sec)
return false;
DAngle angle = line->Delta().Angle();
DAngle norm = angle - 90;
double dist = -(norm.Cos() * line->v1->fX() + norm.Sin() * line->v1->fY());
if (side)
{
angle += 180.;
dist = -dist;
}
sec->SetBase(fc, dist, -angle);
return true;
}
//==========================================================================
//
// P_ReplaceTextures
//
//==========================================================================
void P_ReplaceTextures(const char *fromname, const char *toname, int flags)
{
FTextureID picnum1, picnum2;
if (fromname == nullptr)
return;
if ((flags ^ (NOT_BOTTOM | NOT_MIDDLE | NOT_TOP)) != 0)
{
picnum1 = TexMan.GetTexture(fromname, ETextureType::Wall, FTextureManager::TEXMAN_Overridable);
picnum2 = TexMan.GetTexture(toname, ETextureType::Wall, FTextureManager::TEXMAN_Overridable);
for (auto &side : level.sides)
{
for (int j = 0; j<3; j++)
{
static uint8_t bits[] = { NOT_TOP, NOT_MIDDLE, NOT_BOTTOM };
if (!(flags & bits[j]) && side.GetTexture(j) == picnum1)
{
side.SetTexture(j, picnum2);
}
}
}
}
if ((flags ^ (NOT_FLOOR | NOT_CEILING)) != 0)
{
picnum1 = TexMan.GetTexture(fromname, ETextureType::Flat, FTextureManager::TEXMAN_Overridable);
picnum2 = TexMan.GetTexture(toname, ETextureType::Flat, FTextureManager::TEXMAN_Overridable);
for (auto &sec : level.sectors)
{
if (!(flags & NOT_FLOOR) && sec.GetTexture(sector_t::floor) == picnum1)
sec.SetTexture(sector_t::floor, picnum2);
if (!(flags & NOT_CEILING) && sec.GetTexture(sector_t::ceiling) == picnum1)
sec.SetTexture(sector_t::ceiling, picnum2);
}
}
}
DEFINE_ACTION_FUNCTION(_TexMan, ReplaceTextures)
{
PARAM_PROLOGUE;
PARAM_STRING(from);
PARAM_STRING(to);
PARAM_INT(flags);
P_ReplaceTextures(from, to, flags);
return 0;
}
//==========================================================================
//
// P_BuildPolyBSP
//
//==========================================================================
static FNodeBuilder::FLevel PolyNodeLevel;
static FNodeBuilder PolyNodeBuilder(PolyNodeLevel);
void subsector_t::BuildPolyBSP()
{
assert((BSP == NULL || BSP->bDirty) && "BSP computed more than once");
// Set up level information for the node builder.
PolyNodeLevel.Sides = &level.sides[0];
PolyNodeLevel.NumSides = level.sides.Size();
PolyNodeLevel.Lines = &level.lines[0];
PolyNodeLevel.NumLines = numlines; // is this correct???
// Feed segs to the nodebuilder and build the nodes.
PolyNodeBuilder.Clear();
PolyNodeBuilder.AddSegs(firstline, numlines);
for (FPolyNode *pn = polys; pn != NULL; pn = pn->pnext)
{
PolyNodeBuilder.AddPolySegs(&pn->segs[0], (int)pn->segs.Size());
}
PolyNodeBuilder.BuildMini(false);
if (BSP == NULL)
{
BSP = new FMiniBSP;
}
PolyNodeBuilder.ExtractMini(BSP);
for (unsigned int i = 0; i < BSP->Subsectors.Size(); ++i)
{
BSP->Subsectors[i].sector = sector;
}
}
//==========================================================================
//
//
//
//==========================================================================
CUSTOM_CVAR(Int, r_fakecontrast, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{
if (self < 0) self = 1;
else if (self > 2) self = 2;
}
//==========================================================================
//
//
//
//==========================================================================
int side_t::GetLightLevel (bool foggy, int baselight, bool is3dlight, int *pfakecontrast) const
{
if (!is3dlight && (Flags & WALLF_ABSLIGHTING))
{
baselight = Light;
}
if (pfakecontrast != NULL)
{
*pfakecontrast = 0;
}
if (!foggy || level.flags3 & LEVEL3_FORCEFAKECONTRAST) // Don't do relative lighting in foggy sectors
{
if (!(Flags & WALLF_NOFAKECONTRAST) && r_fakecontrast != 0)
{
DVector2 delta = linedef->Delta();
int rel;
if (((level.flags2 & LEVEL2_SMOOTHLIGHTING) || (Flags & WALLF_SMOOTHLIGHTING) || r_fakecontrast == 2) &&
delta.X != 0)
{
rel = xs_RoundToInt // OMG LEE KILLOUGH LIVES! :/
(
level.WallHorizLight
+ fabs(atan(delta.Y / delta.X) / 1.57079)
* (level.WallVertLight - level.WallHorizLight)
);
}
else
{
rel = delta.X == 0 ? level.WallVertLight :
delta.Y == 0 ? level.WallHorizLight : 0;
}
if (pfakecontrast != NULL)
{
*pfakecontrast = rel;
}
else
{
baselight += rel;
}
}
}
if (!is3dlight && !(Flags & WALLF_ABSLIGHTING) && (!foggy || (Flags & WALLF_LIGHT_FOG)))
{
baselight += this->Light;
}
return baselight;
}
//==========================================================================
//
// Recalculate all heights affecting this vertex.
//
//==========================================================================
void vertex_t::RecalcVertexHeights()
{
int i, j, k;
float height;
numheights = 0;
for (i = 0; i < numsectors; i++)
{
for (j = 0; j<2; j++)
{
if (j == 0) height = (float)sectors[i]->ceilingplane.ZatPoint(this);
else height = (float)sectors[i]->floorplane.ZatPoint(this);
for (k = 0; k < numheights; k++)
{
if (height == heightlist[k]) break;
if (height < heightlist[k])
{
memmove(&heightlist[k + 1], &heightlist[k], sizeof(float) * (numheights - k));
heightlist[k] = height;
numheights++;
break;
}
}
if (k == numheights) heightlist[numheights++] = height;
}
}
if (numheights <= 2) numheights = 0; // is not in need of any special attention
dirty = false;
}
DEFINE_ACTION_FUNCTION(_Secplane, isSlope)
{
PARAM_SELF_STRUCT_PROLOGUE(secplane_t);
ACTION_RETURN_BOOL(!self->normal.XY().isZero());
}
DEFINE_ACTION_FUNCTION(_Secplane, PointOnSide)
{
PARAM_SELF_STRUCT_PROLOGUE(secplane_t);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
PARAM_FLOAT(z);
ACTION_RETURN_INT(self->PointOnSide(DVector3(x, y, z)));
}
DEFINE_ACTION_FUNCTION(_Secplane, ZatPoint)
{
PARAM_SELF_STRUCT_PROLOGUE(secplane_t);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
ACTION_RETURN_FLOAT(self->ZatPoint(x, y));
}
DEFINE_ACTION_FUNCTION(_Secplane, ZatPointDist)
{
PARAM_SELF_STRUCT_PROLOGUE(secplane_t);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
PARAM_FLOAT(d);
ACTION_RETURN_FLOAT((d + self->normal.X*x + self->normal.Y*y) * self->negiC);
}
DEFINE_ACTION_FUNCTION(_Secplane, isEqual)
{
PARAM_SELF_STRUCT_PROLOGUE(secplane_t);
PARAM_POINTER(other, secplane_t);
ACTION_RETURN_BOOL(*self == *other);
}
DEFINE_ACTION_FUNCTION(_Secplane, ChangeHeight)
{
PARAM_SELF_STRUCT_PROLOGUE(secplane_t);
PARAM_FLOAT(hdiff);
self->ChangeHeight(hdiff);
return 0;
}
DEFINE_ACTION_FUNCTION(_Secplane, GetChangedHeight)
{
PARAM_SELF_STRUCT_PROLOGUE(secplane_t);
PARAM_FLOAT(hdiff);
ACTION_RETURN_FLOAT(self->GetChangedHeight(hdiff));
}
DEFINE_ACTION_FUNCTION(_Secplane, HeightDiff)
{
PARAM_SELF_STRUCT_PROLOGUE(secplane_t);
PARAM_FLOAT(oldd);
if (numparam == 2)
{
ACTION_RETURN_FLOAT(self->HeightDiff(oldd));
}
else
{
PARAM_FLOAT(newd);
ACTION_RETURN_FLOAT(self->HeightDiff(oldd, newd));
}
}
DEFINE_ACTION_FUNCTION(_Secplane, PointToDist)
{
PARAM_SELF_STRUCT_PROLOGUE(secplane_t);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
PARAM_FLOAT(z);
ACTION_RETURN_FLOAT(self->PointToDist(DVector2(x, y), z));
}
DEFINE_FIELD_X(Sector, sector_t, floorplane)
DEFINE_FIELD_X(Sector, sector_t, ceilingplane)
DEFINE_FIELD_X(Sector, sector_t, Colormap)
DEFINE_FIELD_X(Sector, sector_t, SpecialColors)
DEFINE_FIELD_X(Sector, sector_t, SoundTarget)
DEFINE_FIELD_X(Sector, sector_t, special)
DEFINE_FIELD_X(Sector, sector_t, lightlevel)
DEFINE_FIELD_X(Sector, sector_t, seqType)
DEFINE_FIELD_X(Sector, sector_t, sky)
DEFINE_FIELD_X(Sector, sector_t, SeqName)
DEFINE_FIELD_X(Sector, sector_t, centerspot)
DEFINE_FIELD_X(Sector, sector_t, validcount)
DEFINE_FIELD_X(Sector, sector_t, thinglist)
DEFINE_FIELD_X(Sector, sector_t, friction)
DEFINE_FIELD_X(Sector, sector_t, movefactor)
DEFINE_FIELD_X(Sector, sector_t, terrainnum)
DEFINE_FIELD_X(Sector, sector_t, floordata)
DEFINE_FIELD_X(Sector, sector_t, ceilingdata)
DEFINE_FIELD_X(Sector, sector_t, lightingdata)
DEFINE_FIELD_X(Sector, sector_t, interpolations)
DEFINE_FIELD_X(Sector, sector_t, soundtraversed)
DEFINE_FIELD_X(Sector, sector_t, stairlock)
DEFINE_FIELD_X(Sector, sector_t, prevsec)
DEFINE_FIELD_X(Sector, sector_t, nextsec)
DEFINE_FIELD_UNSIZED(Sector, sector_t, Lines)
DEFINE_FIELD_X(Sector, sector_t, heightsec)
DEFINE_FIELD_X(Sector, sector_t, bottommap)
DEFINE_FIELD_X(Sector, sector_t, midmap)
DEFINE_FIELD_X(Sector, sector_t, topmap)
DEFINE_FIELD_X(Sector, sector_t, touching_thinglist)
DEFINE_FIELD_X(Sector, sector_t, sectorportal_thinglist)
DEFINE_FIELD_X(Sector, sector_t, gravity)
DEFINE_FIELD_X(Sector, sector_t, damagetype)
DEFINE_FIELD_X(Sector, sector_t, damageamount)
DEFINE_FIELD_X(Sector, sector_t, damageinterval)
DEFINE_FIELD_X(Sector, sector_t, leakydamage)
DEFINE_FIELD_X(Sector, sector_t, ZoneNumber)
DEFINE_FIELD_X(Sector, sector_t, MoreFlags)
DEFINE_FIELD_X(Sector, sector_t, Flags)
DEFINE_FIELD_X(Sector, sector_t, SecActTarget)
DEFINE_FIELD_X(Sector, sector_t, Portals)
DEFINE_FIELD_X(Sector, sector_t, PortalGroup)
DEFINE_FIELD_X(Sector, sector_t, sectornum)
DEFINE_FIELD_X(Line, line_t, v1)
DEFINE_FIELD_X(Line, line_t, v2)
DEFINE_FIELD_X(Line, line_t, delta)
DEFINE_FIELD_X(Line, line_t, flags)
DEFINE_FIELD_X(Line, line_t, activation)
DEFINE_FIELD_X(Line, line_t, special)
DEFINE_FIELD_X(Line, line_t, args)
DEFINE_FIELD_X(Line, line_t, alpha)
DEFINE_FIELD_X(Line, line_t, sidedef)
DEFINE_FIELD_X(Line, line_t, bbox)
DEFINE_FIELD_X(Line, line_t, frontsector)
DEFINE_FIELD_X(Line, line_t, backsector)
DEFINE_FIELD_X(Line, line_t, validcount)
DEFINE_FIELD_X(Line, line_t, locknumber)
DEFINE_FIELD_X(Line, line_t, portalindex)
DEFINE_FIELD_X(Line, line_t, portaltransferred)
DEFINE_FIELD_X(Side, side_t, sector)
DEFINE_FIELD_X(Side, side_t, linedef)
DEFINE_FIELD_X(Side, side_t, Light)
DEFINE_FIELD_X(Side, side_t, Flags)
DEFINE_FIELD_X(Secplane, secplane_t, normal)
DEFINE_FIELD_X(Secplane, secplane_t, D)
DEFINE_FIELD_X(Secplane, secplane_t, negiC)
DEFINE_FIELD_X(Vertex, vertex_t, p)