Merge branch 'edf-gl'

Conflicts:
	src/actor.h
	src/p_spec.cpp
This commit is contained in:
Christoph Oelckers 2016-01-12 00:02:17 +01:00
commit 7c8d48bbfc
10 changed files with 970 additions and 108 deletions

View File

@ -944,6 +944,7 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE
doomstat.cpp doomstat.cpp
dsectoreffect.cpp dsectoreffect.cpp
dthinker.cpp dthinker.cpp
edf.cpp
f_wipe.cpp f_wipe.cpp
farchive.cpp farchive.cpp
files.cpp files.cpp

784
src/edf.cpp Normal file
View File

@ -0,0 +1,784 @@
/*
** edf.cpp
** Parses Eternity EDF lumps
**
**---------------------------------------------------------------------------
** Copyright 2015 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** 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.
**---------------------------------------------------------------------------
**
** This code was written based on the documentation in the Eternity Wiki
**
*/
#include "w_wad.h"
#include "m_argv.h"
#include "zstring.h"
#include "sc_man.h"
#include "g_level.h"
#include "doomdata.h"
#include "r_defs.h"
#include "info.h"
#include "p_lnspec.h"
#include "p_setup.h"
#include "p_tags.h"
#include "p_terrain.h"
#include "v_palette.h"
#include "p_acs.h"
#include "r_data/colormaps.h"
struct FEdfOptions : public FOptionalMapinfoData
{
FEdfOptions()
{
identifier = "EDF";
}
virtual FOptionalMapinfoData *Clone() const
{
FEdfOptions *newopt = new FEdfOptions;
newopt->identifier = identifier;
newopt->edfName = edfName;
newopt->acsName = acsName;
return newopt;
}
FString edfName;
FString acsName;
};
DEFINE_MAP_OPTION(edf, false)
{
FEdfOptions *opt = info->GetOptData<FEdfOptions>("EDF");
parse.ParseAssign();
parse.sc.MustGetString();
opt->edfName = parse.sc.String;
}
DEFINE_MAP_OPTION(loadacs, false)
{
FEdfOptions *opt = info->GetOptData<FEdfOptions>("EDF");
parse.ParseAssign();
parse.sc.MustGetString();
opt->acsName = parse.sc.String;
}
struct EDFMapthing
{
int recordnum;
int tid;
int type;
fixed_t height;
int args[5];
WORD skillfilter;
DWORD flags;
};
struct EDFLinedef
{
int recordnum;
int special;
int tag;
int id;
int args[5];
fixed_t alpha;
DWORD flags;
DWORD activation;
};
struct EDFSector
{
int recordnum;
DWORD flags;
DWORD flagsRemove;
DWORD flagsAdd;
int damageamount;
int damageinterval;
FNameNoInit damagetype;
BYTE leaky;
BYTE leakyadd;
BYTE leakyremove;
int floorterrain;
int ceilingterrain;
DWORD color;
DWORD damageflags;
DWORD damageflagsAdd;
DWORD damageflagsRemove;
bool flagsSet;
bool damageflagsSet;
bool colorSet;
// colormaptop//bottom cannot be used because ZDoom has no corresponding properties.
FTransform planexform[2];
DWORD portalflags[2];
fixed_t overlayalpha[2];
};
static FString EDFMap;
static TMap<int, EDFLinedef> EDFLines;
static TMap<int, EDFSector> EDFSectors;
static TMap<int, EDFMapthing> EDFThings;
static void parseLinedef(FScanner &sc)
{
EDFLinedef ld;
bool argsset = false;
memset(&ld, 0, sizeof(ld));
ld.alpha = FRACUNIT;
sc.MustGetStringName("{");
while (!sc.CheckString("}"))
{
sc.MustGetString();
if (sc.Compare("recordnum"))
{
sc.CheckString("=");
sc.MustGetNumber();
ld.recordnum = sc.Number;
}
else if (sc.Compare("tag"))
{
sc.CheckString("=");
sc.MustGetNumber();
ld.tag = sc.Number;
}
else if (sc.Compare("id"))
{
sc.CheckString("=");
sc.MustGetNumber();
ld.id = sc.Number;
}
else if (sc.Compare("special"))
{
sc.CheckString("=");
if (sc.CheckNumber())
{
// Oh joy, this is going to be fun...
// Here we cannot do anything because we need the tag to make this work.
// For now just store a negative number and resolve this later.
ld.special = -sc.Number;
}
else
{
sc.MustGetString();
ld.special = P_FindLineSpecial(sc.String);
}
}
else if (sc.Compare("args"))
{
sc.CheckString("=");
sc.MustGetStringName("{");
int c = 0;
while (true)
{
sc.MustGetNumber();
ld.args[c++] = sc.Number;
if (sc.CheckString("}")) break;
sc.MustGetStringName(",");
}
argsset = true;
}
else if (sc.Compare("alpha"))
{
sc.CheckString("=");
sc.MustGetFloat();
ld.alpha = FLOAT2FIXED(sc.Float);
}
else if (sc.Compare("extflags"))
{
// these are needed to build the proper activation mask out of the possible flags which do not match ZDoom 1:1.
DWORD actmethod = 0;
DWORD acttype = 0;
do
{
sc.CheckString("=");
sc.MustGetString();
for (const char *tok = strtok(sc.String, ",+ \t"); tok != NULL; tok = strtok(NULL, ",+ \t"))
{
if (!stricmp(tok, "USE")) actmethod |= SPAC_Use | SPAC_MUse;
else if (!stricmp(tok, "CROSS")) actmethod |= SPAC_Cross | SPAC_MCross | SPAC_PCross;
else if (!stricmp(tok, "IMPACT")) ld.activation |= SPAC_Impact;
else if (!stricmp(tok, "PUSH")) actmethod |= SPAC_Push;
else if (!stricmp(tok, "PLAYER")) acttype |= SPAC_Use | SPAC_Cross | SPAC_Push;
else if (!stricmp(tok, "MONSTER")) acttype |= SPAC_MUse | SPAC_MCross | SPAC_MPush;
else if (!stricmp(tok, "MISSILE")) acttype |= SPAC_PCross;
else if (!stricmp(tok, "REPEAT")) ld.flags |= ML_REPEAT_SPECIAL;
else if (!stricmp(tok, "1SONLY")) ld.flags |= ML_FIRSTSIDEONLY;
else if (!stricmp(tok, "ADDITIVE")) ld.flags |= ML_ADDTRANS;
else if (!stricmp(tok, "BLOCKALL")) ld.flags |= ML_BLOCKEVERYTHING;
else if (!stricmp(tok, "ZONEBOUNDARY")) ld.flags |= ML_ZONEBOUNDARY;
else if (!stricmp(tok, "CLIPMIDTEX")) ld.flags |= ML_CLIP_MIDTEX;
else sc.ScriptError("Unknown option '%s'", tok);
}
} while (sc.CheckString("|")); // Unquoted strings with '|' separator - parse as a separate string in the loop.
// and finally we must mask in the activation method
ld.activation |= (actmethod & acttype);
}
else
{
sc.ScriptError("Unknown property '%s'", sc.String);
}
}
if (ld.tag == 0) ld.tag = ld.id; // urgh...
if (ld.special < 0) // translate numeric specials.
{
line_t line;
maplinedef_t mld;
mld.special = -ld.special;
mld.tag = ld.tag;
P_TranslateLineDef(&line, &mld);
ld.special = line.special;
ld.activation = line.activation;
ld.flags = (ld.flags & ~(ML_REPEAT_SPECIAL | ML_FIRSTSIDEONLY)) | (line.flags & (ML_REPEAT_SPECIAL | ML_FIRSTSIDEONLY));
if (!argsset) memcpy(ld.args, line.args, sizeof(ld.args));
}
EDFLines[ld.recordnum] = ld;
}
static void parseSector(FScanner &sc)
{
EDFSector sec;
memset(&sec, 0, sizeof(sec));
sec.overlayalpha[sector_t::floor] = sec.overlayalpha[sector_t::ceiling] = FRACUNIT;
sec.floorterrain = sec.ceilingterrain = -1;
sc.MustGetStringName("{");
while (!sc.CheckString("}"))
{
sc.MustGetString();
if (sc.Compare("recordnum"))
{
sc.CheckString("=");
sc.MustGetNumber();
sec.recordnum = sc.Number;
}
else if (sc.Compare("flags"))
{
DWORD *flagvar = NULL;
if (sc.CheckString("."))
{
sc.MustGetString();
if (sc.Compare("add"))
{
flagvar = &sec.flagsAdd;
}
else if (sc.Compare("remove"))
{
flagvar = &sec.flagsRemove;
}
else
{
sc.ScriptError("Invalid property 'flags.%s'", sc.String);
}
}
else
{
sec.flagsSet = true;
flagvar = &sec.flags;
}
sc.CheckString("=");
do
{
sc.MustGetString();
for (const char *tok = strtok(sc.String, ",+ \t"); tok != NULL; tok = strtok(NULL, ",+ \t"))
{
if (!stricmp(tok, "SECRET")) *flagvar |= SECF_SECRET | SECF_WASSECRET;
else if (!stricmp(tok, "FRICTION")) *flagvar |= SECF_FRICTION;
else if (!stricmp(tok, "PUSH")) *flagvar |= SECF_PUSH;
else if (!stricmp(tok, "KILLSOUND")) *flagvar |= SECF_SILENT;
else if (!stricmp(tok, "KILLMOVESOUND")) *flagvar |= SECF_SILENTMOVE;
else sc.ScriptError("Unknown option '%s'", tok);
}
} while (sc.CheckString("|")); // Unquoted strings with '|' separator - parse as a separate string in the loop.
}
else if (sc.Compare("damage"))
{
sc.CheckString("=");
sc.MustGetNumber();
sec.damageamount = sc.Number;
}
else if (sc.Compare("damagemask"))
{
sc.CheckString("=");
sc.MustGetNumber();
sec.damageinterval = sc.Number;
}
else if (sc.Compare("damageflags"))
{
DWORD *flagvar = NULL;
BYTE *leakvar = NULL;
if (sc.CheckString("."))
{
sc.MustGetString();
if (sc.Compare("add"))
{
flagvar = &sec.damageflagsAdd;
leakvar = &sec.leakyadd;
}
else if (sc.Compare("remove"))
{
flagvar = &sec.damageflagsRemove;
leakvar = &sec.leakyremove;
}
else
{
sc.ScriptError("Invalid property 'flags.%s'", sc.String);
}
}
else
{
sec.damageflagsSet = true;
flagvar = &sec.damageflags;
leakvar = &sec.leaky;
}
sc.CheckString("=");
do
{
sc.MustGetString();
for (const char *tok = strtok(sc.String, ",+ \t"); tok != NULL; tok = strtok(NULL, ",+ \t"))
{
if (!stricmp(tok, "LEAKYSUIT")) *leakvar |= 1;
else if (!stricmp(tok, "IGNORESUIT")) *leakvar |= 2; // these 2 bits will be used to set 'leakychance', but this can only be done when the sector gets initialized
else if (!stricmp(tok, "ENDGODMODE")) *flagvar |= SECF_ENDGODMODE;
else if (!stricmp(tok, "ENDLEVEL")) *flagvar |= SECF_ENDLEVEL;
else if (!stricmp(tok, "TERRAINHIT")) *flagvar |= SECF_DMGTERRAINFX;
else sc.ScriptError("Unknown option '%s'", tok);
}
} while (sc.CheckString("|")); // Unquoted strings with '|' separator - parse as a separate string in the loop.
}
else if (sc.Compare("floorterrain"))
{
sc.CheckString("=");
sc.MustGetString();
sec.floorterrain = P_FindTerrain(sc.String);
}
else if (sc.Compare("floorangle"))
{
sc.CheckString("=");
sc.MustGetFloat();
sec.planexform[sector_t::floor].angle = angle_t(sc.Float * ANGLE_90 / 90.);
}
else if (sc.Compare("flooroffsetx"))
{
sc.CheckString("=");
sc.MustGetFloat();
sec.planexform[sector_t::floor].xoffs = FLOAT2FIXED(sc.Float);
}
else if (sc.Compare("flooroffsety"))
{
sc.CheckString("=");
sc.MustGetFloat();
sec.planexform[sector_t::floor].yoffs = FLOAT2FIXED(sc.Float);
}
else if (sc.Compare("ceilingterrain"))
{
sc.CheckString("=");
sc.MustGetString();
sec.ceilingterrain = P_FindTerrain(sc.String);
}
else if (sc.Compare("ceilingangle"))
{
sc.CheckString("=");
sc.MustGetFloat();
sec.planexform[sector_t::ceiling].angle = angle_t(sc.Float * ANGLE_90 / 90.);
}
else if (sc.Compare("ceilingoffsetx"))
{
sc.CheckString("=");
sc.MustGetFloat();
sec.planexform[sector_t::ceiling].xoffs = FLOAT2FIXED(sc.Float);
}
else if (sc.Compare("ceilingoffsety"))
{
sc.CheckString("=");
sc.MustGetFloat();
sec.planexform[sector_t::ceiling].yoffs = FLOAT2FIXED(sc.Float);
}
else if (sc.Compare("colormaptop") || sc.Compare("colormapbottom"))
{
sc.CheckString("=");
sc.MustGetString();
// these properties are not implemented by ZDoom
}
else if (sc.Compare("colormapmid"))
{
sc.CheckString("=");
sc.MustGetString();
// Eternity is based on SMMU and uses colormaps differently than all other ports.
// The only solution here is to convert the colormap to an RGB value and set it as the sector's color.
DWORD cmap = R_ColormapNumForName(sc.String);
if (cmap != 0)
{
sec.color = R_BlendForColormap(cmap) & 0xff000000;
sec.colorSet = true;
}
}
else if (sc.Compare("overlayalpha"))
{
sc.MustGetStringName(".");
sc.MustGetString();
if (sc.Compare("floor"))
{
sc.MustGetNumber();
if (sc.CheckString("%")) sc.Float = sc.Number / 100.f;
else sc.Float = sc.Number / 255.f;
sec.overlayalpha[sector_t::floor] = FLOAT2FIXED(sc.Float);
}
else if (sc.Compare("ceiling"))
{
sc.MustGetFloat();
if (sc.CheckString("%")) sc.Float = sc.Number / 100.f;
else sc.Float = sc.Number / 255.f;
sec.overlayalpha[sector_t::floor] = FLOAT2FIXED(sc.Float);
}
}
else if (sc.Compare("portalflags"))
{
int dest = 0;
sc.MustGetStringName(".");
sc.MustGetString();
if (sc.Compare("floor")) dest = sector_t::floor;
else if (sc.Compare("ceiling")) dest = sector_t::ceiling;
else sc.ScriptError("Unknown portal type '%s'", sc.String);
sc.CheckString("=");
do
{
sc.MustGetString();
for (const char *tok = strtok(sc.String, ",+ \t"); tok != NULL; tok = strtok(NULL, ",+ \t"))
{
if (!stricmp(tok, "DISABLED")) sec.portalflags[dest] |= PLANEF_DISABLED;
else if (!stricmp(tok, "NORENDER")) sec.portalflags[dest] |= PLANEF_NORENDER;
else if (!stricmp(tok, "NOPASS")) sec.portalflags[dest] |= PLANEF_NOPASS;
else if (!stricmp(tok, "BLOCKSOUND")) sec.portalflags[dest] |= PLANEF_BLOCKSOUND;
else if (!stricmp(tok, "OVERLAY")) sec.portalflags[dest] |= 0; // we do not use this. Alpha is the sole determinant for overlay drawing
else if (!stricmp(tok, "ADDITIVE")) sec.portalflags[dest] |= PLANEF_ADDITIVE;
else if (!stricmp(tok, "USEGLOBALTEX")) {} // not implemented
else sc.ScriptError("Unknown option '%s'", tok);
}
} while (sc.CheckString("|")); // Unquoted strings with '|' separator - parse as a separate string in the loop.
}
else
{
sc.ScriptError("Unknown property '%s'", sc.String);
}
}
EDFSectors[sec.recordnum] = sec;
}
static void parseMapthing(FScanner &sc)
{
EDFMapthing mt;
memset(&mt, 0, sizeof(mt));
mt.flags |= MTF_SINGLE | MTF_COOPERATIVE | MTF_DEATHMATCH; // EDF uses inverse logic, like Doom.exe
sc.MustGetStringName("{");
while (!sc.CheckString("}"))
{
sc.MustGetString();
if (sc.Compare("recordnum"))
{
sc.CheckString("=");
sc.MustGetNumber();
mt.recordnum = sc.Number;
}
else if (sc.Compare("tid"))
{
sc.CheckString("=");
sc.MustGetNumber();
mt.tid = sc.Number;
}
else if (sc.Compare("type"))
{
sc.CheckString("=");
if (sc.CheckNumber())
{
mt.type = sc.Number;
}
else
{
// Class name.
sc.MustGetString();
// According to the Eternity Wiki a name may be prefixed with 'thing:'.
const char *pos = strchr(sc.String, ':'); // Eternity never checks if the prefix actually is 'thing'.
if (pos) pos++;
else pos = sc.String;
const PClass *cls = PClass::FindClass(pos);
if (cls != NULL)
{
FDoomEdMap::Iterator it(DoomEdMap);
FDoomEdMap::Pair *pair;
while (it.NextPair(pair))
{
if (pair->Value.Type == cls)
{
mt.type = pair->Key;
break;
}
}
}
else
{
// Let's hope this isn't an internal Eternity name.
// If so, a name mapping needs to be defined...
sc.ScriptError("Unknown type '%s'", sc.String);
}
}
}
else if (sc.Compare("args"))
{
sc.CheckString("=");
sc.MustGetStringName("{");
int c = 0;
while (!sc.CheckString("}"))
{
sc.MustGetNumber();
mt.args[c++] = sc.Number;
}
}
else if (sc.Compare("height"))
{
sc.CheckString("=");
sc.MustGetFloat(); // no idea if Eternity allows fractional numbers. Better be safe and do it anyway.
mt.height = FLOAT2FIXED(sc.Float);
}
else if (sc.Compare("options"))
{
sc.CheckString("=");
do
{
sc.MustGetString();
for (const char *tok = strtok(sc.String, ",+ \t"); tok != NULL; tok = strtok(NULL, ",+ \t"))
{
if (!stricmp(tok, "EASY")) mt.skillfilter |= 3;
else if (!stricmp(tok, "NORMAL")) mt.skillfilter |= 4;
else if (!stricmp(tok, "HARD")) mt.skillfilter |= 24;
else if (!stricmp(tok, "AMBUSH")) mt.flags |= MTF_AMBUSH;
else if (!stricmp(tok, "NOTSINGLE")) mt.flags &= ~MTF_SINGLE;
else if (!stricmp(tok, "NOTDM")) mt.flags &= ~MTF_DEATHMATCH;
else if (!stricmp(tok, "NOTCOOP")) mt.flags &= ~MTF_COOPERATIVE;
else if (!stricmp(tok, "FRIEND")) mt.flags |= MTF_FRIENDLY;
else if (!stricmp(tok, "DORMANT")) mt.flags |= MTF_DORMANT;
else sc.ScriptError("Unknown option '%s'", tok);
}
} while (sc.CheckString("|")); // Unquoted strings with '|' separator - parse as a separate string in the loop.
}
else
{
sc.ScriptError("Unknown property '%s'", sc.String);
}
}
EDFThings[mt.recordnum] = mt;
}
void InitEDF()
{
FString filename;
FScanner sc;
if (EDFMap.CompareNoCase(level.MapName) != 0)
{
EDFLines.Clear();
EDFSectors.Clear();
EDFThings.Clear();
EDFMap = level.MapName;
const char *arg = Args->CheckValue("-edf");
if (arg != NULL) filename = arg;
else
{
FEdfOptions *opt = level.info->GetOptData<FEdfOptions>("EDF", false);
if (opt != NULL)
{
filename = opt->edfName;
}
}
if (filename.IsEmpty()) return;
int lump = Wads.CheckNumForFullName(filename, true, ns_global);
if (lump == -1) return;
sc.OpenLumpNum(lump);
sc.SetCMode(true);
while (sc.GetString())
{
if (sc.Compare("linedef"))
{
parseLinedef(sc);
}
else if (sc.Compare("mapthing"))
{
parseMapthing(sc);
}
else if (sc.Compare("sector"))
{
parseSector(sc);
}
else
{
sc.ScriptError("Unknown keyword '%s'", sc.String);
}
}
}
}
void ProcessEDFMapthing(FMapThing *mt, int recordnum)
{
InitEDF();
EDFMapthing *emt = EDFThings.CheckKey(recordnum);
if (emt == NULL)
{
Printf("EDF Mapthing record %d not found\n", recordnum);
mt->EdNum = 0;
return;
}
mt->thingid = emt->tid;
mt->EdNum = emt->type;
mt->info = DoomEdMap.CheckKey(mt->EdNum);
mt->z = emt->height;
memcpy(mt->args, emt->args, sizeof(mt->args));
mt->SkillFilter = emt->skillfilter;
mt->flags = emt->flags;
}
void ProcessEDFLinedef(line_t *ld, int recordnum)
{
InitEDF();
EDFLinedef *eld = EDFLines.CheckKey(recordnum);
if (eld == NULL)
{
Printf("EDF Linedef record %d not found\n", recordnum);
ld->special = 0;
return;
}
const DWORD fmask = ML_REPEAT_SPECIAL | ML_FIRSTSIDEONLY | ML_ADDTRANS | ML_BLOCKEVERYTHING | ML_ZONEBOUNDARY | ML_CLIP_MIDTEX;
ld->special = eld->special;
ld->activation = eld->activation;
ld->flags = (ld->flags&~fmask) | eld->flags;
ld->Alpha = eld->alpha;
memcpy(ld->args, eld->args, sizeof(ld->args));
tagManager.AddLineID(int(ld - lines), eld->tag);
}
void ProcessEDFSector(sector_t *sec, int recordnum)
{
EDFSector *esec = EDFSectors.CheckKey(recordnum);
if (esec == NULL)
{
Printf("EDF Sector record %d not found\n", recordnum);
return;
}
// In ZDoom the regular and the damage flags are part of the same flag word so we need to do some masking.
const DWORD flagmask = SECF_SECRET | SECF_WASSECRET | SECF_FRICTION | SECF_PUSH | SECF_SILENT | SECF_SILENTMOVE;
if (esec->flagsSet) sec->Flags = (sec->Flags & ~flagmask);
sec->Flags = (sec->Flags | esec->flags | esec->flagsAdd) & ~esec->flagsRemove;
BYTE leak = 0;
if (esec->damageflagsSet) sec->Flags = (sec->Flags & ~SECF_DAMAGEFLAGS);
else leak = sec->leakydamage >= 256 ? 2 : sec->leakydamage >= 5 ? 1 : 0;
sec->Flags = (sec->Flags | esec->damageflags | esec->damageflagsAdd) & ~esec->damageflagsRemove;
leak = (leak | esec->leaky | esec->leakyadd) & ~esec->leakyremove;
// the damage properties will be unconditionally overridden by EDF.
sec->leakydamage = leak == 0 ? 0 : leak == 1 ? 5 : 256;
sec->damageamount = esec->damageamount;
sec->damageinterval = esec->damageinterval;
sec->damagetype = esec->damagetype;
sec->terrainnum[sector_t::floor] = esec->floorterrain;
sec->terrainnum[sector_t::ceiling] = esec->ceilingterrain;
if (esec->colorSet) sec->SetColor(RPART(esec->color), GPART(esec->color), BPART(esec->color), 0);
const DWORD pflagmask = PLANEF_DISABLED | PLANEF_NORENDER | PLANEF_NOPASS | PLANEF_BLOCKSOUND | PLANEF_ADDITIVE;
for (int i = 0; i < 2; i++)
{
sec->planes[i].xform.xoffs = esec->planexform[i].xoffs;
sec->planes[i].xform.yoffs = esec->planexform[i].yoffs;
sec->planes[i].xform.angle = esec->planexform[i].angle;
sec->planes[i].alpha = esec->overlayalpha[i];
sec->planes[i].Flags = (sec->planes[i].Flags & ~pflagmask) | esec->portalflags[i];
}
}
void ProcessEDFSectors()
{
int i;
InitEDF();
if (EDFSectors.CountUsed() == 0) return; // don't waste time if there's no records.
// collect all EDF sector records up front so we do not need to search the complete line array for each sector separately.
int *edfsectorrecord = new int[numsectors];
memset(edfsectorrecord, -1, numsectors * sizeof(int));
for (i = 0; i < numlines; i++)
{
if (lines[i].special == Static_Init && lines[i].args[1] == Init_EDFSector)
{
edfsectorrecord[lines[i].frontsector - sectors] = lines[i].args[0];
lines[i].special = 0;
}
}
for (i = 0; i < numsectors; i++)
{
if (edfsectorrecord[i] >= 0)
{
ProcessEDFSector(&sectors[i], edfsectorrecord[i]);
}
}
delete[] edfsectorrecord;
}
void LoadMapinfoACSLump()
{
FEdfOptions *opt = level.info->GetOptData<FEdfOptions>("EDF", false);
if (opt != NULL)
{
int lump = Wads.CheckNumForName(opt->acsName);
if (lump >= 0) FBehavior::StaticLoadModule(lump);
}
}

View File

@ -69,6 +69,7 @@ const char *SpecialMapthingNames[] = {
"$CopyCeilingPlane", "$CopyCeilingPlane",
"$VertexFloorZ", "$VertexFloorZ",
"$VertexCeilingZ", "$VertexCeilingZ",
"$EDFThing",
}; };
//========================================================================== //==========================================================================

View File

@ -313,6 +313,7 @@ enum ESpecialMapthings
SMT_CopyCeilingPlane, SMT_CopyCeilingPlane,
SMT_VertexFloorZ, SMT_VertexFloorZ,
SMT_VertexCeilingZ, SMT_VertexCeilingZ,
SMT_EDFThing,
}; };

View File

@ -60,6 +60,8 @@ typedef enum {
Init_Damage = 2, Init_Damage = 2,
Init_SectorLink = 3, Init_SectorLink = 3,
NUM_STATIC_INITS, NUM_STATIC_INITS,
Init_EDFSector = 253,
Init_EDFLine = 254,
Init_TransferSky = 255 Init_TransferSky = 255
} staticinit_t; } staticinit_t;

View File

@ -68,6 +68,9 @@
#include "po_man.h" #include "po_man.h"
#include "r_renderer.h" #include "r_renderer.h"
#include "r_data/colormaps.h" #include "r_data/colormaps.h"
#ifndef NO_EDF
#include "edf.h"
#endif
#include "fragglescript/t_fs.h" #include "fragglescript/t_fs.h"
@ -1759,34 +1762,45 @@ void P_LoadThings (MapData * map)
mti[i].alpha = -1; mti[i].alpha = -1;
mti[i].health = 1; mti[i].health = 1;
mti[i].FloatbobPhase = -1; mti[i].FloatbobPhase = -1;
flags &= ~MTF_SKILLMASK;
mti[i].flags = (short)((flags & 0xf) | 0x7e0);
if (gameinfo.gametype == GAME_Strife)
{
mti[i].flags &= ~MTF_AMBUSH;
if (flags & STF_SHADOW) mti[i].flags |= MTF_SHADOW;
if (flags & STF_ALTSHADOW) mti[i].flags |= MTF_ALTSHADOW;
if (flags & STF_STANDSTILL) mti[i].flags |= MTF_STANDSTILL;
if (flags & STF_AMBUSH) mti[i].flags |= MTF_AMBUSH;
if (flags & STF_FRIENDLY) mti[i].flags |= MTF_FRIENDLY;
}
else
{
if (flags & BTF_BADEDITORCHECK)
{
flags &= 0x1F;
}
if (flags & BTF_NOTDEATHMATCH) mti[i].flags &= ~MTF_DEATHMATCH;
if (flags & BTF_NOTCOOPERATIVE) mti[i].flags &= ~MTF_COOPERATIVE;
if (flags & BTF_FRIENDLY) mti[i].flags |= MTF_FRIENDLY;
}
if (flags & BTF_NOTSINGLE) mti[i].flags &= ~MTF_SINGLE;
mti[i].x = LittleShort(mt->x) << FRACBITS; mti[i].x = LittleShort(mt->x) << FRACBITS;
mti[i].y = LittleShort(mt->y) << FRACBITS; mti[i].y = LittleShort(mt->y) << FRACBITS;
mti[i].angle = LittleShort(mt->angle); mti[i].angle = LittleShort(mt->angle);
mti[i].EdNum = LittleShort(mt->type); mti[i].EdNum = LittleShort(mt->type);
mti[i].info = DoomEdMap.CheckKey(mti[i].EdNum); mti[i].info = DoomEdMap.CheckKey(mti[i].EdNum);
#ifndef NO_EDF
if (mti[i].info != NULL && mti[i].info->Special == SMT_EDFThing)
{
ProcessEDFMapthing(&mti[i], flags);
}
else
#endif
{
flags &= ~MTF_SKILLMASK;
mti[i].flags = (short)((flags & 0xf) | 0x7e0);
if (gameinfo.gametype == GAME_Strife)
{
mti[i].flags &= ~MTF_AMBUSH;
if (flags & STF_SHADOW) mti[i].flags |= MTF_SHADOW;
if (flags & STF_ALTSHADOW) mti[i].flags |= MTF_ALTSHADOW;
if (flags & STF_STANDSTILL) mti[i].flags |= MTF_STANDSTILL;
if (flags & STF_AMBUSH) mti[i].flags |= MTF_AMBUSH;
if (flags & STF_FRIENDLY) mti[i].flags |= MTF_FRIENDLY;
}
else
{
if (flags & BTF_BADEDITORCHECK)
{
flags &= 0x1F;
}
if (flags & BTF_NOTDEATHMATCH) mti[i].flags &= ~MTF_DEATHMATCH;
if (flags & BTF_NOTCOOPERATIVE) mti[i].flags &= ~MTF_COOPERATIVE;
if (flags & BTF_FRIENDLY) mti[i].flags |= MTF_FRIENDLY;
}
if (flags & BTF_NOTSINGLE) mti[i].flags &= ~MTF_SINGLE;
}
} }
delete [] mtp; delete [] mtp;
} }
@ -2157,7 +2171,19 @@ void P_LoadLineDefs (MapData * map)
// [RH] Translate old linedef special and flags to be // [RH] Translate old linedef special and flags to be
// compatible with the new format. // compatible with the new format.
P_TranslateLineDef (ld, mld, i);
P_TranslateLineDef (ld, mld, -1);
// do not assign the tag for EDF lines.
if (ld->special != Static_Init || (ld->args[1] != Init_EDFLine && ld->args[1] != Init_EDFSector))
{
tagManager.AddLineID(i, mld->tag);
}
#ifndef NO_EDF
if (ld->special == Static_Init && ld->args[1] == Init_EDFLine)
{
ProcessEDFLinedef(ld, mld->tag);
}
#endif
ld->v1 = &vertexes[LittleShort(mld->v1)]; ld->v1 = &vertexes[LittleShort(mld->v1)];
ld->v2 = &vertexes[LittleShort(mld->v2)]; ld->v2 = &vertexes[LittleShort(mld->v2)];
@ -3325,7 +3351,7 @@ void P_LoadBehavior (MapData * map)
void P_GetPolySpots (MapData * map, TArray<FNodeBuilder::FPolyStart> &spots, TArray<FNodeBuilder::FPolyStart> &anchors) void P_GetPolySpots (MapData * map, TArray<FNodeBuilder::FPolyStart> &spots, TArray<FNodeBuilder::FPolyStart> &anchors)
{ {
if (map->HasBehavior) //if (map->HasBehavior)
{ {
for (unsigned int i = 0; i < MapThingsConverted.Size(); ++i) for (unsigned int i = 0; i < MapThingsConverted.Size(); ++i)
{ {
@ -3676,6 +3702,10 @@ void P_SetupLevel (const char *lumpname, int position)
} }
FBehavior::StaticLoadDefaultModules (); FBehavior::StaticLoadDefaultModules ();
#ifndef NO_EDF
LoadMapinfoACSLump();
#endif
P_LoadStrifeConversations (map, lumpname); P_LoadStrifeConversations (map, lumpname);

View File

@ -63,6 +63,9 @@
#include "a_keys.h" #include "a_keys.h"
#include "c_dispatch.h" #include "c_dispatch.h"
#include "r_sky.h" #include "r_sky.h"
#ifndef NO_EDF
#include "edf.h"
#endif
// State. // State.
#include "r_state.h" #include "r_state.h"
@ -1365,6 +1368,7 @@ void P_SpawnSpecials (void)
// Init special SECTORs. // Init special SECTORs.
sector = sectors; sector = sectors;
for (i = 0; i < numsectors; i++, sector++) for (i = 0; i < numsectors; i++, sector++)
{ {
if (sector->special == 0) if (sector->special == 0)
@ -1372,6 +1376,11 @@ void P_SpawnSpecials (void)
P_InitSectorSpecial(sector, sector->special, false); P_InitSectorSpecial(sector, sector->special, false);
} }
#ifndef NO_EDF
ProcessEDFSectors();
#endif
// Init other misc stuff // Init other misc stuff

View File

@ -368,6 +368,12 @@ enum
PLANEF_ABSLIGHTING = 1, // floor/ceiling light is absolute, not relative PLANEF_ABSLIGHTING = 1, // floor/ceiling light is absolute, not relative
PLANEF_BLOCKED = 2, // can not be moved anymore. PLANEF_BLOCKED = 2, // can not be moved anymore.
PLANEF_ADDITIVE = 4, // rendered additive PLANEF_ADDITIVE = 4, // rendered additive
// linked portal stuff
PLANEF_NORENDER = 8,
PLANEF_NOPASS = 16,
PLANEF_BLOCKSOUND = 32,
PLANEF_DISABLED = 64,
}; };
// Internal sector flags // Internal sector flags

View File

@ -0,0 +1,8 @@
// This should be included by any converted Eternity project so set the DoomEdNums that conflict with regular ZDoom get set.
DoomEdNums
{
5003 = none
5004 = "$EDFThing"
}

View File

@ -8,11 +8,18 @@
define Unsupported (0) define Unsupported (0)
enum
{
Init_EDFSector = 253,
Init_EDFLine = 254
}
// The tag for such a line is actually a key to find, in an ExtraData lump // The tag for such a line is actually a key to find, in an ExtraData lump
// indicated for the current level by the EMAPINFO lump, what line special // indicated for the current level by the EMAPINFO lump, what line special
// to actually use. This is how parameterized linedefs are used by Eternity // to actually use. This is how parameterized linedefs are used by Eternity
// in the Doom format. "xlating" this would thus be quite complicated... // in the Doom format.
270 = 0, Unsupported() // "ExtraDataSpecial"
270 = 0, Static_Init(tag, Init_EDFLine) // "ExtraDataSpecial"
// These two are standard MBF specials, no need to redefine them, they're in xlat/doom.txt // These two are standard MBF specials, no need to redefine them, they're in xlat/doom.txt
// 271 = 0, Static_Init (tag, Init_TransferSky, 0) // 271 = 0, Static_Init (tag, Init_TransferSky, 0)
@ -60,52 +67,53 @@ define Unsupported (0)
// Parameterized linedefs // Parameterized linedefs
// They are never used directly in Doom-format maps. Instead, it passes through ExtraData and 270. // They are never used directly in Doom-format maps. Instead, it passes through ExtraData and 270.
// Hexen format is incomplete; and Quasar wants to use ZDoom-compatible special values for UDMF. // Hexen format is incomplete; and Quasar wants to use ZDoom-compatible special values for UDMF.
// So there is no need to bother with them and they are listed only for completeness' sake. // The translation here is for the odd EDF that specifies them as numbers.
/* /*
300: "Door_Raise" 300 = 0, Door_Raise(0)
301: "Door_Open" 301 = 0, Door_Open(0)
302: "Door_Close" 302 = 0, Door_Close(0)
303: "Door_CloseWaitOpen" 303 = 0, Door_CloseWaitOpen(0)
304: "Door_WaitRaise" 304 = 0, Door_WaitRaise(0)
305: "Door_WaitClose" 305 = 0, Door_WaitClose(0)
306: "Floor_RaiseToHighest" 306 = 0, Floor_RaiseToHighest(0)
307: "Floor_LowerToHighest" 307 = 0, Floor_LowerToHighest(0)
308: "Floor_RaiseToLowest" 308 = 0, Floor_RaiseToLowest(0)
309: "Floor_LowerToLowest" 309 = 0, Floor_LowerToLowest(0)
310: "Floor_RaiseToNearest" 310 = 0, Floor_RaiseToNearest(0)
311: "Floor_LowerToNearest" 311 = 0, Floor_LowerToNearest(0)
312: "Floor_RaiseToLowestCeiling" 312 = 0, Floor_RaiseToLowestCeiling(0)
313: "Floor_LowerToLowestCeiling" 313 = 0, Floor_LowerToLowestCeiling(0)
314: "Floor_RaiseToCeiling" 314 = 0, Floor_RaiseToCeiling(0)
315: "Floor_RaiseByTexture" 315 = 0, Floor_RaiseByTexture(0)
316: "Floor_LowerByTexture" 316 = 0, Floor_LowerByTexture(0)
317: "Floor_RaiseByValue" 317 = 0, Floor_RaiseByValue(0)
318: "Floor_LowerByValue" 318 = 0, Floor_LowerByValue(0)
319: "Floor_MoveToValue" 319 = 0, Floor_MoveToValue(0)
320: "Floor_RaiseInstant" 320 = 0, Floor_RaiseInstant(0)
321: "Floor_LowerInstant" 321 = 0, Floor_LowerInstant(0)
322: "Floor_ToCeilingInstant" 322 = 0, Floor_ToCeilingInstant(0)
323: "Ceiling_RaiseToHighest" 323 = 0, Ceiling_RaiseToHighest(0)
324: "Ceiling_ToHighestInstant" 324 = 0, Ceiling_ToHighestInstant(0)
325: "Ceiling_RaiseToNearest" 325 = 0, Ceiling_RaiseToNearest(0)
326: "Ceiling_LowerToNearest" 326 = 0, Ceiling_LowerToNearest(0)
327: "Ceiling_RaiseToLowest" 327 = 0, Ceiling_RaiseToLowest(0)
328: "Ceiling_LowerToLowest" 328 = 0, Ceiling_LowerToLowest(0)
329: "Ceiling_RaiseToHighestFloor" 329 = 0, Ceiling_RaiseToHighestFloor(0)
330: "Ceiling_LowerToHighestFloor" 330 = 0, Ceiling_LowerToHighestFloor(0)
331: "Ceiling_ToFloorInstant" 331 = 0, Ceiling_ToFloorInstant(0)
332: "Ceiling_LowerToFloor" 332 = 0, Ceiling_LowerToFloor(0)
333: "Ceiling_RaiseByTexture" 333 = 0, Ceiling_RaiseByTexture(0)
334: "Ceiling_LowerByTexture" 334 = 0, Ceiling_LowerByTexture(0)
335: "Ceiling_RaiseByValue" 335 = 0, Ceiling_RaiseByValue(0)
336: "Ceiling_LowerByValue" 336 = 0, Ceiling_LowerByValue(0)
337: "Ceiling_MoveToValue" 337 = 0, Ceiling_MoveToValue(0)
338: "Ceiling_RaiseInstant" 338 = 0, Ceiling_RaiseInstant(0)
339: "Ceiling_LowerInstant" 339 = 0, Ceiling_LowerInstant(0)
340: "Stairs_BuildUpDoom" 340 = 0, Stairs_BuildUpDoom(0)
341: "Stairs_BuildDownDoom" 341 = 0, Stairs_BuildDownDoom(0)
342: "Stairs_BuildUpDoomSync" 342 = 0, Stairs_BuildUpDoomSync(0)
343: "Stairs_BuildDownDoomSync" 343 = 0, Stairs_BuildDownDoomSync(0)
*/ */
// Two-way portals are not supported yet either // Two-way portals are not supported yet either
@ -115,42 +123,38 @@ define Unsupported (0)
347 = 0, Unsupported() // "Portal_TwowayAnchorLineFloor" 347 = 0, Unsupported() // "Portal_TwowayAnchorLineFloor"
// More parameterized linedefs // More parameterized linedefs
/* 348 = 0, Polyobj_StartLine(0)
348: "Polyobj_StartLine" 349 = 0, Polyobj_ExplicitLine(0)
349: "Polyobj_ExplicitLine" 350 = 0, Polyobj_DoorSlide(0)
350: "Polyobj_DoorSlide" 351 = 0, Polyobj_DoorSwing(0)
351: "Polyobj_DoorSwing" 352 = 0, Polyobj_Move(0)
352: "Polyobj_Move" 353 = 0, Polyobj_OR_Move(0)
353: "Polyobj_OR_Move" 354 = 0, Polyobj_RotateRight(0)
354: "Polyobj_RotateRight" 355 = 0, Polyobj_OR_RotateRight(0)
355: "Polyobj_OR_RotateRight" 356 = 0, Polyobj_RotateLeft(0)
356: "Polyobj_RotateLeft" 357 = 0, Polyobj_OR_RotateLeft(0)
357: "Polyobj_OR_RotateLeft"
*/
// Eternity's linked portals, vertical link version (floor-to-ceiling) // Eternity's linked portals, vertical link version (floor-to-ceiling) (NOTE: Type needs changing!)
358 = 0, Unsupported() // "Portal_LinkedCeiling" 358 = 0, Sector_SetPortal(tag, 0, 1, 1, 0) // "Portal_AnchoredCeiling"
359 = 0, Unsupported() // "Portal_LinkedFloor" 359 = 0, Sector_SetPortal(tag, 0, 0, 1, 0) // "Portal_AnchoredFloor"
360 = 0, Unsupported() // "Portal_LinkedAnchorLine" 360 = 0, Sector_SetPortal(tag, 0, 1, 0, 0) // "Portal_AnchorLine"
361 = 0, Unsupported() // "Portal_LinkedAnchorLineFloor" 361 = 0, Sector_SetPortal(tag, 0, 0, 0, 0) // "Portal_AnchorLineFloor"
// Even more parameterized linedefs // Even more parameterized linedefs
/* 362 = 0, Pillar_Build(0)
362: "Pillar_Build" 363 = 0, Pillar_BuildAndCrush(0)
363: "Pillar_BuildAndCrush" 364 = 0, Pillar_Open(0)
364: "Pillar_Open" 365 = 0, ACS_Execute(0)
365: "ACS_Execute" 366 = 0, ACS_Suspend(0)
366: "ACS_Suspend" 367 = 0, ACS_Terminate(0)
367: "ACS_Terminate" 368 = 0, Light_RaiseByValue(0)
368: "Light_RaiseByValue" 369 = 0, Light_LowerByValue(0)
369: "Light_LowerByValue" 370 = 0, Light_ChangeToValue(0)
370: "Light_ChangeToValue" 371 = 0, Light_Fade(0)
371: "Light_Fade" 372 = 0, Light_Glow(0)
372: "Light_Glow" 373 = 0, Light_Flicker(0)
373: "Light_Flicker" 374 = 0, Light_Strobe(0)
374: "Light_Strobe" 375 = 0, Radius_Quake(0)
375: "Radius_Quake"
*/
// Eternity's linked portals, horizontal link version (wall-to-wall) // Eternity's linked portals, horizontal link version (wall-to-wall)
376 = 0, Unsupported() // "Portal_LinkedLineToLine" 376 = 0, Unsupported() // "Portal_LinkedLineToLine"
@ -186,7 +190,23 @@ define Unsupported (0)
396 = 0, Plane_Copy(tag, tag)// "Slope_FrontFloorAndCeilingToTaggedSlope" 396 = 0, Plane_Copy(tag, tag)// "Slope_FrontFloorAndCeilingToTaggedSlope"
// Last parameterized linedefs // Last parameterized linedefs
// 397 = Floor_Waggle 397 = 0, Floor_Waggle(0)
// 398 = Thing_Spawn 398 = 0, Thing_Spawn(0)
// 399 = Thing_SpawnNoFog 399 = 0, Thing_SpawnNoFog(0)
// 400 = Teleport_EndGame 400 = 0, Teleport_EndGame(0)
401 = 0, Static_Init(tag, Init_EDFSector)
402 = 0, Thing_Projectile(0)
403 = 0, Thing_ProjectileGravity(0)
404 = 0, Thing_Activate(0)
405 = 0, Thing_Deactivate(0)
410 = 0, Plat_PerpetualRaise(0)
411 = 0, Plat_Stop(0)
412 = 0, Plat_DownWaitUpStay(0)
413 = 0, Plat_DownByValue(0)
414 = 0, Plat_UpWaitDownStay(0)
415 = 0, Plat_UpByValue(0)
416 = 0, Floor_LowerToHighest(0)
420 = 0, ACS_ExecuteWithResult(0)
421 = 0, Thing_ChangeTID(0)