mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-12-11 21:21:47 +00:00
5fcc96a0f2
The sections pointer was not copied here.
2704 lines
66 KiB
C++
2704 lines
66 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;
|
|
}
|
|
|
|
//=====================================================================================
|
|
//
|
|
//
|
|
//=====================================================================================
|
|
|
|
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(_Side, SetSpecialColor)
|
|
{
|
|
PARAM_SELF_STRUCT_PROLOGUE(side_t);
|
|
PARAM_INT(tier);
|
|
PARAM_INT(position);
|
|
PARAM_COLOR(color);
|
|
if (tier >= 0 && tier < 3 && position >= 0 && position < 2)
|
|
{
|
|
color.a = 255;
|
|
self->SetSpecialColor(tier, position, color);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
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;
|
|
BSP->Subsectors[i].section = section;
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
//
|
|
//
|
|
//==========================================================================
|
|
|
|
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, healthceiling)
|
|
DEFINE_FIELD_X(Sector, sector_t, healthfloor)
|
|
DEFINE_FIELD_X(Sector, sector_t, healthceilinggroup)
|
|
DEFINE_FIELD_X(Sector, sector_t, healthfloorgroup)
|
|
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(Line, line_t, health)
|
|
DEFINE_FIELD_X(Line, line_t, healthgroup)
|
|
|
|
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)
|