- moved a large batch of code from p_spec.cpp and a few other files into the maploader folder.

This commit is contained in:
Christoph Oelckers 2019-01-24 20:27:34 +01:00
commit 4d55c28b60
9 changed files with 1579 additions and 1406 deletions

View file

@ -98,7 +98,7 @@
#include "p_setup.h"
#include "c_console.h"
#include "maploader/maploader.h"
#include "p_spec_thinkers.h"
static FRandom pr_playerinspecialsector ("PlayerInSpecialSector");
@ -709,25 +709,6 @@ CUSTOM_CVAR (Bool, forcewater, false, CVAR_ARCHIVE|CVAR_SERVERINFO)
}
}
class DLightTransfer : public DThinker
{
DECLARE_CLASS (DLightTransfer, DThinker)
DLightTransfer() {}
public:
DLightTransfer (sector_t *srcSec, int target, bool copyFloor);
void Serialize(FSerializer &arc);
void Tick ();
protected:
void DoTransfer (int level, int target, bool floor);
sector_t *Source;
int TargetTag;
bool CopyFloor;
short LastLight;
};
IMPLEMENT_CLASS(DLightTransfer, false, false)
void DLightTransfer::Serialize(FSerializer &arc)
@ -795,31 +776,6 @@ void DLightTransfer::DoTransfer (int llevel, int target, bool floor)
}
class DWallLightTransfer : public DThinker
{
enum
{
WLF_SIDE1=1,
WLF_SIDE2=2,
WLF_NOFAKECONTRAST=4
};
DECLARE_CLASS (DWallLightTransfer, DThinker)
DWallLightTransfer() {}
public:
DWallLightTransfer (sector_t *srcSec, int target, uint8_t flags);
void Serialize(FSerializer &arc);
void Tick ();
protected:
void DoTransfer (short level, int target, uint8_t flags);
sector_t *Source;
int TargetID;
short LastLight;
uint8_t Flags;
};
IMPLEMENT_CLASS(DWallLightTransfer, false, false)
void DWallLightTransfer::Serialize(FSerializer &arc)
@ -900,611 +856,6 @@ void DWallLightTransfer::DoTransfer (short lightlevel, int target, uint8_t flags
}
}
//-----------------------------------------------------------------------------
//
// Portals
//
//-----------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Upper stacks go in the top sector. Lower stacks go in the bottom sector.
void MapLoader::SetupFloorPortal (AActor *point)
{
auto it = Level->GetActorIterator(NAME_LowerStackLookOnly, point->tid);
sector_t *Sector = point->Sector;
auto skyv = it.Next();
if (skyv != nullptr)
{
skyv->target = point;
if (Sector->GetAlpha(sector_t::floor) == 1.)
Sector->SetAlpha(sector_t::floor, clamp(point->args[0], 0, 255) / 255.);
Sector->Portals[sector_t::floor] = P_GetStackPortal(skyv, sector_t::floor);
}
}
void MapLoader::SetupCeilingPortal (AActor *point)
{
auto it = Level->GetActorIterator(NAME_UpperStackLookOnly, point->tid);
sector_t *Sector = point->Sector;
auto skyv = it.Next();
if (skyv != nullptr)
{
skyv->target = point;
if (Sector->GetAlpha(sector_t::ceiling) == 1.)
Sector->SetAlpha(sector_t::ceiling, clamp(point->args[0], 0, 255) / 255.);
Sector->Portals[sector_t::ceiling] = P_GetStackPortal(skyv, sector_t::ceiling);
}
}
void MapLoader::SetupPortals()
{
auto it = Level->GetThinkerIterator<AActor>(NAME_StackPoint);
AActor *pt;
TArray<AActor *> points;
while ((pt = it.Next()))
{
FName nm = pt->GetClass()->TypeName;
if (nm == NAME_UpperStackLookOnly)
{
SetupFloorPortal(pt);
}
else if (nm == NAME_LowerStackLookOnly)
{
SetupCeilingPortal(pt);
}
pt->special1 = 0;
points.Push(pt);
}
// the semantics here are incredibly lax so the final setup can only be done once all portals have been created,
// because later stackpoints will happily overwrite info in older ones, if there are multiple links.
for (auto &s : Level->sectorPortals)
{
if (s.mType == PORTS_STACKEDSECTORTHING && s.mSkybox)
{
for (auto &ss : Level->sectorPortals)
{
if (ss.mType == PORTS_STACKEDSECTORTHING && ss.mSkybox == s.mSkybox->target)
{
s.mPartner = unsigned((&ss) - &Level->sectorPortals[0]);
}
}
}
}
// Now we can finally set the displacement and delete the stackpoint reference.
for (auto &s : Level->sectorPortals)
{
if (s.mType == PORTS_STACKEDSECTORTHING && s.mSkybox)
{
s.mDisplacement = s.mSkybox->Pos() - s.mSkybox->target->Pos();
s.mSkybox = nullptr;
}
}
}
void MapLoader::SetPortal(sector_t *sector, int plane, unsigned pnum, double alpha)
{
// plane: 0=floor, 1=ceiling, 2=both
if (plane > 0)
{
if (sector->GetPortalType(sector_t::ceiling) == PORTS_SKYVIEWPOINT)
{
sector->Portals[sector_t::ceiling] = pnum;
if (sector->GetAlpha(sector_t::ceiling) == 1.)
sector->SetAlpha(sector_t::ceiling, alpha);
if (Level->sectorPortals[pnum].mFlags & PORTSF_SKYFLATONLY)
sector->SetTexture(sector_t::ceiling, skyflatnum);
}
}
if (plane == 2 || plane == 0)
{
if (sector->GetPortalType(sector_t::floor) == PORTS_SKYVIEWPOINT)
{
sector->Portals[sector_t::floor] = pnum;
}
if (sector->GetAlpha(sector_t::floor) == 1.)
sector->SetAlpha(sector_t::floor, alpha);
if (Level->sectorPortals[pnum].mFlags & PORTSF_SKYFLATONLY)
sector->SetTexture(sector_t::floor, skyflatnum);
}
}
void MapLoader::CopyPortal(int sectortag, int plane, unsigned pnum, double alpha, bool tolines)
{
int s;
auto itr = Level->GetSectorTagIterator(sectortag);
while ((s = itr.Next()) >= 0)
{
SetPortal(&Level->sectors[s], plane, pnum, alpha);
}
for (auto &line : Level->lines)
{
// Check if this portal needs to be copied to other sectors
// This must be done here to ensure that it gets done only after the portal is set up
if (line.special == Sector_SetPortal &&
line.args[1] == 1 &&
(line.args[2] == plane || line.args[2] == 3) &&
line.args[3] == sectortag)
{
if (line.args[0] == 0)
{
SetPortal(line.frontsector, plane, pnum, alpha);
}
else
{
auto itr = Level->GetSectorTagIterator(line.args[0]);
while ((s = itr.Next()) >= 0)
{
SetPortal(&Level->sectors[s], plane, pnum, alpha);
}
}
}
if (tolines && line.special == Sector_SetPortal &&
line.args[1] == 5 &&
line.args[3] == sectortag)
{
if (line.args[0] == 0)
{
line.portaltransferred = pnum;
}
else
{
auto itr = Level->GetLineIdIterator(line.args[0]);
while ((s = itr.Next()) >= 0)
{
Level->lines[s].portaltransferred = pnum;
}
}
}
}
}
void MapLoader::SpawnPortal(line_t *line, int sectortag, int plane, int bytealpha, int linked)
{
if (plane < 0 || plane > 2 || (linked && plane == 2)) return;
for (auto &oline : Level->lines)
{
// We must look for the reference line with a linear search unless we want to waste the line ID for it
// which is not a good idea.
if (oline.special == Sector_SetPortal &&
oline.args[0] == sectortag &&
oline.args[1] == linked &&
oline.args[2] == plane &&
oline.args[3] == 1)
{
// beware of overflows.
DVector2 pos1 = line->v1->fPos() + line->Delta() / 2;
DVector2 pos2 = oline.v1->fPos() + oline.Delta() / 2;
unsigned pnum = P_GetPortal(linked ? PORTS_LINKEDPORTAL : PORTS_PORTAL, plane, line->frontsector, oline.frontsector, pos2 - pos1);
CopyPortal(sectortag, plane, pnum, bytealpha / 255., false);
return;
}
}
}
// This searches the viewpoint's sector
// for a skybox line special, gets its tag and transfers the skybox to all tagged sectors.
void MapLoader::SpawnSkybox(AActor *origin)
{
sector_t *Sector = origin->Sector;
if (Sector == NULL)
{
Printf("Sector not initialized for SkyCamCompat\n");
origin->Sector = Sector = P_PointInSector(origin->Pos());
}
if (Sector)
{
for(auto refline : Sector->Lines)
{
if (refline->special == Sector_SetPortal && refline->args[1] == 2)
{
// We found the setup linedef for this skybox, so let's use it for our init.
unsigned pnum = P_GetSkyboxPortal(origin);
CopyPortal(refline->args[0], refline->args[2], pnum, 0, true);
return;
}
}
}
}
//
// P_SetSectorDamage
//
// Sets damage properties for one sector. Allows combination of original specials with explicit use of the damage properties
//
static void SetupSectorDamage(sector_t *sector, int damage, int interval, int leakchance, FName type, int flags)
{
// Only set if damage is not yet initialized. This ensures that UDMF takes precedence over sector specials.
if (sector->damageamount == 0)
{
sector->damageamount = damage;
sector->damageinterval = MAX(1, interval);
sector->leakydamage = leakchance;
sector->damagetype = type;
sector->Flags = (sector->Flags & ~SECF_DAMAGEFLAGS) | (flags & SECF_DAMAGEFLAGS);
}
}
//
// P_InitSectorSpecial
//
// Sets up everything derived from 'sector->special' for one sector
// ('fromload' is necessary to allow conversion upon savegame load.)
//
void MapLoader::InitSectorSpecial(sector_t *sector, int special)
{
// [RH] All secret sectors are marked with a BOOM-ish bitfield
if (sector->special & SECRET_MASK)
{
sector->Flags |= SECF_SECRET | SECF_WASSECRET;
Level->total_secrets++;
}
if (sector->special & FRICTION_MASK)
{
sector->Flags |= SECF_FRICTION;
}
if (sector->special & PUSH_MASK)
{
sector->Flags |= SECF_PUSH;
}
if ((sector->special & DAMAGE_MASK) == 0x100)
{
SetupSectorDamage(sector, 5, 32, 0, NAME_Fire, 0);
}
else if ((sector->special & DAMAGE_MASK) == 0x200)
{
SetupSectorDamage(sector, 10, 32, 0, NAME_Slime, 0);
}
else if ((sector->special & DAMAGE_MASK) == 0x300)
{
SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0);
}
sector->special &= 0xff;
// [RH] Normal DOOM special or BOOM specialized?
bool keepspecial = false;
SpawnLights(sector);
switch (sector->special)
{
case dLight_Strobe_Hurt:
SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0);
break;
case dDamage_Hellslime:
SetupSectorDamage(sector, 10, 32, 0, NAME_Slime, 0);
break;
case dDamage_Nukage:
SetupSectorDamage(sector, 5, 32, 0, NAME_Slime, 0);
break;
case dSector_DoorCloseIn30:
Create<DDoor>(sector, DDoor::doorWaitClose, 2, 0, 0, 30 * TICRATE);
break;
case dDamage_End:
SetupSectorDamage(sector, 20, 32, 256, NAME_None, SECF_ENDGODMODE|SECF_ENDLEVEL);
break;
case dSector_DoorRaiseIn5Mins:
Create<DDoor> (sector, DDoor::doorWaitRaise, 2, TICRATE*30/7, 0, 5*60*TICRATE);
break;
case dFriction_Low:
sector->friction = FRICTION_LOW;
sector->movefactor = 0x269/65536.;
sector->Flags |= SECF_FRICTION;
break;
case dDamage_SuperHellslime:
SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0);
break;
case dDamage_LavaWimpy:
SetupSectorDamage(sector, 5, 16, 256, NAME_Fire, SECF_DMGTERRAINFX);
break;
case dDamage_LavaHefty:
SetupSectorDamage(sector, 8, 16, 256, NAME_Fire, SECF_DMGTERRAINFX);
break;
case dScroll_EastLavaDamage:
SetupSectorDamage(sector, 5, 16, 256, NAME_Fire, SECF_DMGTERRAINFX);
CreateScroller(EScroll::sc_floor, -4., 0, sector, 0);
keepspecial = true;
break;
case hDamage_Sludge:
SetupSectorDamage(sector, 4, 32, 0, NAME_Slime, 0);
break;
case sLight_Strobe_Hurt:
SetupSectorDamage(sector, 5, 32, 0, NAME_Slime, 0);
break;
case sDamage_Hellslime:
SetupSectorDamage(sector, 2, 32, 0, NAME_Slime, SECF_HAZARD);
break;
case Damage_InstantDeath:
// Strife's instant death sector
SetupSectorDamage(sector, TELEFRAG_DAMAGE, 1, 256, NAME_InstantDeath, 0);
break;
case sDamage_SuperHellslime:
SetupSectorDamage(sector, 4, 32, 0, NAME_Slime, SECF_HAZARD);
break;
case Sector_Hidden:
sector->MoreFlags |= SECMF_HIDDEN;
break;
case Sector_Heal:
// CoD's healing sector
SetupSectorDamage(sector, -1, 32, 0, NAME_None, 0);
break;
case Sky2:
sector->sky = PL_SKYFLAT;
break;
default:
if (sector->special >= Scroll_North_Slow && sector->special <= Scroll_SouthWest_Fast)
{ // Hexen scroll special
static const int8_t hexenScrollies[24][2] =
{
{ 0, 1 }, { 0, 2 }, { 0, 4 },
{ -1, 0 }, { -2, 0 }, { -4, 0 },
{ 0, -1 }, { 0, -2 }, { 0, -4 },
{ 1, 0 }, { 2, 0 }, { 4, 0 },
{ 1, 1 }, { 2, 2 }, { 4, 4 },
{ -1, 1 }, { -2, 2 }, { -4, 4 },
{ -1, -1 }, { -2, -2 }, { -4, -4 },
{ 1, -1 }, { 2, -2 }, { 4, -4 }
};
int i = sector->special - Scroll_North_Slow;
double dx = hexenScrollies[i][0] / 2.;
double dy = hexenScrollies[i][1] / 2.;
CreateScroller(EScroll::sc_floor, dx, dy, sector, 0);
}
else if (sector->special >= Carry_East5 && sector->special <= Carry_East35)
{
// Heretic scroll special
// Only east scrollers also scroll the texture
CreateScroller(EScroll::sc_floor, -0.5 * (1 << ((sector->special & 0xff) - Carry_East5)), 0, sector, 0);
}
keepspecial = true;
break;
}
if (!keepspecial) sector->special = 0;
}
//
// P_SpawnSpecials
//
// After the map has been loaded, scan for specials that spawn thinkers
//
void MapLoader::SpawnSpecials ()
{
SetupPortals();
for (auto &sec : Level->sectors)
{
if (sec.special == 0)
continue;
InitSectorSpecial(&sec, sec.special);
}
ProcessEDSectors();
// Init other misc stuff
SpawnScrollers(); // killough 3/7/98: Add generalized scrollers
SpawnFriction(); // phares 3/12/98: New friction model using linedefs
SpawnPushers(); // phares 3/20/98: New pusher model using linedefs
auto it2 = Level->GetThinkerIterator<AActor>(NAME_SkyCamCompat);
AActor *pt2;
while ((pt2 = it2.Next()))
{
SpawnSkybox(pt2);
}
for (auto &line : Level->lines)
{
switch (line.special)
{
int s;
sector_t *sec;
// killough 3/7/98:
// support for drawn heights coming from different sector
case Transfer_Heights:
{
sec = line.frontsector;
if (line.args[1] & 2)
{
sec->MoreFlags |= SECMF_FAKEFLOORONLY;
}
if (line.args[1] & 4)
{
sec->MoreFlags |= SECMF_CLIPFAKEPLANES;
}
if (line.args[1] & 8)
{
sec->MoreFlags |= SECMF_UNDERWATER;
}
else if (forcewater)
{
sec->MoreFlags |= SECMF_FORCEDUNDERWATER;
}
if (line.args[1] & 16)
{
sec->MoreFlags |= SECMF_IGNOREHEIGHTSEC;
}
else Level->HasHeightSecs = true;
if (line.args[1] & 32)
{
sec->MoreFlags |= SECMF_NOFAKELIGHT;
}
auto itr = Level->GetSectorTagIterator(line.args[0]);
while ((s = itr.Next()) >= 0)
{
Level->sectors[s].heightsec = sec;
sec->e->FakeFloor.Sectors.Push(&Level->sectors[s]);
Level->sectors[s].MoreFlags |= (sec->MoreFlags & SECMF_IGNOREHEIGHTSEC); // copy this to the destination sector for easier checking.
Level->sectors[s].AdjustFloorClip();
}
break;
}
// killough 3/16/98: Add support for setting
// floor lighting independently (e.g. lava)
case Transfer_FloorLight:
Create<DLightTransfer> (line.frontsector, line.args[0], true);
break;
// killough 4/11/98: Add support for setting
// ceiling lighting independently
case Transfer_CeilingLight:
Create<DLightTransfer> (line.frontsector, line.args[0], false);
break;
// [Graf Zahl] Add support for setting lighting
// per wall independently
case Transfer_WallLight:
Create<DWallLightTransfer> (line.frontsector, line.args[0], line.args[1]);
break;
case Sector_Attach3dMidtex:
P_Attach3dMidtexLinesToSector(line.frontsector, line.args[0], line.args[1], !!line.args[2]);
break;
case Sector_SetLink:
if (line.args[0] == 0)
{
P_AddSectorLinks(line.frontsector, line.args[1], line.args[2], line.args[3]);
}
break;
case Sector_SetPortal:
// arg 0 = sector tag
// arg 1 = type
// - 0: normal (handled here)
// - 1: copy (handled by the portal they copy)
// - 2: EE-style skybox (handled by the camera object)
// - 3: EE-style flat portal (GZDoom HW renderer only for now)
// - 4: EE-style horizon portal (GZDoom HW renderer only for now)
// - 5: copy portal to line (GZDoom HW renderer only for now)
// - 6: linked portal
// other values reserved for later use
// arg 2 = 0:floor, 1:ceiling, 2:both
// arg 3 = 0: anchor, 1: reference line
// arg 4 = for the anchor only: alpha
if ((line.args[1] == 0 || line.args[1] == 6) && line.args[3] == 0)
{
SpawnPortal(&line, line.args[0], line.args[2], line.args[4], line.args[1]);
}
else if (line.args[1] == 3 || line.args[1] == 4)
{
unsigned pnum = P_GetPortal(line.args[1] == 3 ? PORTS_PLANE : PORTS_HORIZON, line.args[2], line.frontsector, NULL, { 0,0 });
CopyPortal(line.args[0], line.args[2], pnum, 0, true);
}
break;
case Line_SetPortal:
P_SpawnLinePortal(&line);
break;
// [RH] ZDoom Static_Init settings
case Static_Init:
switch (line.args[1])
{
case Init_Gravity:
{
double grav = line.Delta().Length() / 100.;
auto itr = Level->GetSectorTagIterator(line.args[0]);
while ((s = itr.Next()) >= 0)
Level->sectors[s].gravity = grav;
}
break;
//case Init_Color:
// handled in P_LoadSideDefs2()
case Init_Damage:
{
int damage = int(line.Delta().Length());
auto itr = Level->GetSectorTagIterator(line.args[0]);
while ((s = itr.Next()) >= 0)
{
sector_t *sec = &Level->sectors[s];
sec->damageamount = damage;
sec->damagetype = NAME_None;
if (sec->damageamount < 20)
{
sec->leakydamage = 0;
sec->damageinterval = 32;
}
else if (sec->damageamount < 50)
{
sec->leakydamage = 5;
sec->damageinterval = 32;
}
else
{
sec->leakydamage = 256;
sec->damageinterval = 1;
}
}
}
break;
case Init_SectorLink:
if (line.args[3] == 0)
P_AddSectorLinksByID(line.frontsector, line.args[0], line.args[2]);
break;
// killough 10/98:
//
// Support for sky textures being transferred from sidedefs.
// Allows scrolling and other effects (but if scrolling is
// used, then the same sector tag needs to be used for the
// sky sector, the sky-transfer linedef, and the scroll-effect
// linedef). Still requires user to use F_SKY1 for the floor
// or ceiling texture, to distinguish floor and ceiling sky.
case Init_TransferSky:
{
auto itr = Level->GetSectorTagIterator(line.args[0]);
while ((s = itr.Next()) >= 0)
Level->sectors[s].sky = (line.Index() + 1) | PL_SKYFLAT;
break;
}
}
break;
}
}
// [RH] Start running any open scripts on this map
Level->Behaviors.StartTypedScripts (SCRIPT_Open, NULL, false);
}
////////////////////////////////////////////////////////////////////////////
//
// FRICTION EFFECTS
@ -1558,31 +909,6 @@ void MapLoader::SpawnSpecials ()
//
// Initialize the sectors where friction is increased or decreased
void MapLoader::SpawnFriction()
{
line_t *l = &Level->lines[0];
for (unsigned i = 0 ; i < Level->lines.Size() ; i++,l++)
{
if (l->special == Sector_SetFriction)
{
int length;
if (l->args[1])
{ // [RH] Allow setting friction amount from parameter
length = l->args[1] <= 200 ? l->args[1] : 200;
}
else
{
length = int(l->Delta().Length());
}
P_SetSectorFriction (Level, l->args[0], length, false);
l->special = 0;
}
}
}
void P_SetSectorFriction (FLevelLocals *Level, int tag, int amount, bool alterFlag)
{
int s;