From 9fe016d6d087d8906307a5f77c3ee8edda7f52b1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 6 Jan 2016 17:15:08 +0100 Subject: [PATCH 1/7] - EDF parser part 1: Mapthings. --- src/CMakeLists.txt | 1 + src/edf.cpp | 295 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 296 insertions(+) create mode 100644 src/edf.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 90748f2572..1f60d686ad 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -880,6 +880,7 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE doomstat.cpp dsectoreffect.cpp dthinker.cpp + edf.cpp f_wipe.cpp farchive.cpp files.cpp diff --git a/src/edf.cpp b/src/edf.cpp new file mode 100644 index 0000000000..afc9e3f550 --- /dev/null +++ b/src/edf.cpp @@ -0,0 +1,295 @@ +/* +** 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. +**--------------------------------------------------------------------------- +** +*/ + +#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" + + +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("EDF"); + + parse.ParseAssign(); + parse.sc.MustGetString(); + opt->edfName = parse.sc.String; +} + +DEFINE_MAP_OPTION(loadacs, false) +{ + FEdfOptions *opt = info->GetOptData("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]; + float alpha; + DWORD flags; +}; + +struct EDFSector +{ + int recordnum; + + DWORD flags; + DWORD flagsRemove; + DWORD flagsAdd; + + int damageamount; + int damageinterval; + FNameNoInit damagetype; + + // These do not represent any of ZDoom's features. They are maintained like this so that the Add and Remove versions work as intended. + int damageflags; + int damageflagsAdd; + int damageflagsRemove; + + // floorterrain (Type TBD) + + // ceilingterrain is ignored + // colormaptop/mid/bottom need to be translated into color values (the colormap implementation in Eternity is not the same as in Boom!) + + FTransform planexform[2]; + DWORD portalflags[2]; + fixed_t overlayalpha[2]; +}; + +static TMap EDFLines; +static TMap EDFSectors; +static TMap EDFThings; + + +static void parseLinedef(FScanner &sc) +{ +} + +static void parseSector(FScanner &sc) +{ +} + +static void parseMapthing(FScanner &sc) +{ + sc.MustGetStringName("{"); + while (!sc.CheckString("}")) + { + EDFMapthing mt; + + memset(&mt, 0, sizeof(mt)); + mt.flags |= MTF_SINGLE | MTF_COOPERATIVE | MTF_DEATHMATCH; // EDF uses inverse logic, like Doom.exe + 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 not something internal to Eternity... + 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")) + { + 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); + } + } +} + +void loadEDF() +{ + FString filename; + FScanner sc; + + EDFLines.Clear(); + EDFSectors.Clear(); + EDFThings.Clear(); + + const char *arg = Args->CheckValue("-edf"); + + if (arg != NULL) filename = arg; + else + { + FEdfOptions *opt = level.info->GetOptData("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); + } + } + + +} \ No newline at end of file From bdfac02f696abc646f49e7b4614e289078251789 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 6 Jan 2016 22:40:11 +0100 Subject: [PATCH 2/7] - EDF parser for linedefs and sectors. Also extended the Eternity xlat table to handle the parameterized types to the point EDF needs. --- src/edf.cpp | 320 +++++++++++++++++++++++++++++++- src/p_spec.cpp | 2 + wadsrc/static/xlat/eternity.txt | 167 +++++++++-------- 3 files changed, 406 insertions(+), 83 deletions(-) diff --git a/src/edf.cpp b/src/edf.cpp index afc9e3f550..05c66ee8bc 100644 --- a/src/edf.cpp +++ b/src/edf.cpp @@ -40,6 +40,8 @@ #include "doomdata.h" #include "r_defs.h" #include "info.h" +#include "p_lnspec.h" +#include "p_setup.h" struct FEdfOptions : public FOptionalMapinfoData @@ -96,10 +98,13 @@ struct EDFLinedef int tag; int id; int args[5]; - float alpha; + fixed_t alpha; DWORD flags; + DWORD activation; }; + + struct EDFSector { int recordnum; @@ -113,9 +118,9 @@ struct EDFSector FNameNoInit damagetype; // These do not represent any of ZDoom's features. They are maintained like this so that the Add and Remove versions work as intended. - int damageflags; - int damageflagsAdd; - int damageflagsRemove; + DWORD damageflags; + DWORD damageflagsAdd; + DWORD damageflagsRemove; // floorterrain (Type TBD) @@ -134,10 +139,317 @@ static TMap EDFThings; static void parseLinedef(FScanner &sc) { + sc.MustGetStringName("{"); + while (!sc.CheckString("}")) + { + EDFLinedef ld; + bool argsset = false; + + memset(&ld, 0, sizeof(ld)); + ld.alpha = FRACUNIT; + 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. + 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 (!sc.CheckString("}")) + { + sc.MustGetNumber(); + ld.args[c++] = sc.Number; + + } + argsset = true; + } + else if (sc.Compare("alpha")) + { + sc.CheckString("="); + sc.MustGetFloat(); + ld.alpha = FLOAT2FIXED(sc.Float); + } + else if (sc.Compare("options")) + { + // 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.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; + if (!argsset) memcpy(ld.args, line.args, sizeof(ld.args)); + } + } } static void parseSector(FScanner &sc) { + sc.MustGetStringName("{"); + while (!sc.CheckString("}")) + { + EDFSector sec; + + memset(&sec, 0, sizeof(sec)); + sec.overlayalpha[sector_t::floor] = sec.overlayalpha[sector_t::ceiling] = FRACUNIT; + 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 + { + flagvar = &sec.flags; + } + do + { + sc.MustGetString(); + for (const char *tok = strtok(sc.String, ",+ \t"); tok != NULL; tok = strtok(NULL, ",+ \t")) + { + if (!stricmp(tok, "SECRET")) *flagvar |= SECF_SECRET; + 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; + if (sc.CheckString(".")) + { + sc.MustGetString(); + if (sc.Compare("add")) + { + flagvar = &sec.damageflagsAdd; + } + else if (sc.Compare("remove")) + { + flagvar = &sec.damageflagsRemove; + } + else + { + sc.ScriptError("Invalid property 'flags.%s'", sc.String); + } + } + else + { + flagvar = &sec.damageflags; + } + do + { + sc.MustGetString(); + for (const char *tok = strtok(sc.String, ",+ \t"); tok != NULL; tok = strtok(NULL, ",+ \t")) + { + if (!stricmp(tok, "LEAKYSUIT")) *flagvar |= 1; + else if (!stricmp(tok, "IGNORESUIT")) *flagvar |= 2; // these first 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(); + // ZDoom does not implement this yet. + } + 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("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(); + // not implemented by ZDoom + } + else if (sc.Compare("colormapmid")) + { + sc.CheckString("="); + sc.MustGetString(); + // the colormap should be analyzed and converted into an RGB color value. + } + else if (sc.Compare("overlayalpha")) + { + sc.MustGetStringName("."); + sc.MustGetString(); + if (sc.Compare("floor")) + { + sc.MustGetFloat(); + sec.overlayalpha[sector_t::floor] = FLOAT2FIXED(sc.Float); + } + else if (sc.Compare("ceiling")) + { + sc.MustGetFloat(); + 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); + + do + { + sc.MustGetString(); + for (const char *tok = strtok(sc.String, ",+ \t"); tok != NULL; tok = strtok(NULL, ",+ \t")) + { + if (!stricmp(tok, "DISABLED")) sec.portalflags[dest] |= 0; + else if (!stricmp(tok, "NORENDER")) sec.portalflags[dest] |= 0; + else if (!stricmp(tok, "NOPASS")) sec.portalflags[dest] |= 0; + else if (!stricmp(tok, "BLOCKSOUND")) sec.portalflags[dest] |= 0; + else if (!stricmp(tok, "OVERLAY")) sec.portalflags[dest] |= 0; + else if (!stricmp(tok, "ADDITIVE")) sec.portalflags[dest] |= 0; + 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); + } + } } static void parseMapthing(FScanner &sc) diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 918d07ed2e..1ce505da9f 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -1320,6 +1320,8 @@ void P_SpawnSpecials (void) P_InitSectorSpecial(sector, sector->special, false); } + + // Here is the place to handle EDF for sectors. // Init other misc stuff diff --git a/wadsrc/static/xlat/eternity.txt b/wadsrc/static/xlat/eternity.txt index 7b4367ee33..fe88e5cded 100644 --- a/wadsrc/static/xlat/eternity.txt +++ b/wadsrc/static/xlat/eternity.txt @@ -60,53 +60,52 @@ define Unsupported (0) // Parameterized linedefs // 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. -// So there is no need to bother with them and they are listed only for completeness' sake. -/* - 300: "Door_Raise" - 301: "Door_Open" - 302: "Door_Close" - 303: "Door_CloseWaitOpen" - 304: "Door_WaitRaise" - 305: "Door_WaitClose" - 306: "Floor_RaiseToHighest" - 307: "Floor_LowerToHighest" - 308: "Floor_RaiseToLowest" - 309: "Floor_LowerToLowest" - 310: "Floor_RaiseToNearest" - 311: "Floor_LowerToNearest" - 312: "Floor_RaiseToLowestCeiling" - 313: "Floor_LowerToLowestCeiling" - 314: "Floor_RaiseToCeiling" - 315: "Floor_RaiseByTexture" - 316: "Floor_LowerByTexture" - 317: "Floor_RaiseByValue" - 318: "Floor_LowerByValue" - 319: "Floor_MoveToValue" - 320: "Floor_RaiseInstant" - 321: "Floor_LowerInstant" - 322: "Floor_ToCeilingInstant" - 323: "Ceiling_RaiseToHighest" - 324: "Ceiling_ToHighestInstant" - 325: "Ceiling_RaiseToNearest" - 326: "Ceiling_LowerToNearest" - 327: "Ceiling_RaiseToLowest" - 328: "Ceiling_LowerToLowest" - 329: "Ceiling_RaiseToHighestFloor" - 330: "Ceiling_LowerToHighestFloor" - 331: "Ceiling_ToFloorInstant" - 332: "Ceiling_LowerToFloor" - 333: "Ceiling_RaiseByTexture" - 334: "Ceiling_LowerByTexture" - 335: "Ceiling_RaiseByValue" - 336: "Ceiling_LowerByValue" - 337: "Ceiling_MoveToValue" - 338: "Ceiling_RaiseInstant" - 339: "Ceiling_LowerInstant" - 340: "Stairs_BuildUpDoom" - 341: "Stairs_BuildDownDoom" - 342: "Stairs_BuildUpDoomSync" - 343: "Stairs_BuildDownDoomSync" -*/ +// The translation here is for the odd EDF that specifies them as numbers. + +300 = 0, Door_Raise(0) +301 = 0, Door_Open(0) +302 = 0, Door_Close(0) +303 = 0, Door_CloseWaitOpen(0) +304 = 0, Door_WaitRaise(0) +305 = 0, Door_WaitClose(0) +306 = 0, Floor_RaiseToHighest(0) +307 = 0, Floor_LowerToHighest(0) +308 = 0, Floor_RaiseToLowest(0) +309 = 0, Floor_LowerToLowest(0) +310 = 0, Floor_RaiseToNearest(0) +311 = 0, Floor_LowerToNearest(0) +312 = 0, Floor_RaiseToLowestCeiling(0) +313 = 0, Floor_LowerToLowestCeiling(0) +314 = 0, Floor_RaiseToCeiling(0) +315 = 0, Floor_RaiseByTexture(0) +316 = 0, Floor_LowerByTexture(0) +317 = 0, Floor_RaiseByValue(0) +318 = 0, Floor_LowerByValue(0) +319 = 0, Floor_MoveToValue(0) +320 = 0, Floor_RaiseInstant(0) +321 = 0, Floor_LowerInstant(0) +322 = 0, Floor_ToCeilingInstant(0) +323 = 0, Ceiling_RaiseToHighest(0) +324 = 0, Ceiling_ToHighestInstant(0) +325 = 0, Ceiling_RaiseToNearest(0) +326 = 0, Ceiling_LowerToNearest(0) +327 = 0, Ceiling_RaiseToLowest(0) +328 = 0, Ceiling_LowerToLowest(0) +329 = 0, Ceiling_RaiseToHighestFloor(0) +330 = 0, Ceiling_LowerToHighestFloor(0) +331 = 0, Ceiling_ToFloorInstant(0) +332 = 0, Ceiling_LowerToFloor(0) +333 = 0, Ceiling_RaiseByTexture(0) +334 = 0, Ceiling_LowerByTexture(0) +335 = 0, Ceiling_RaiseByValue(0) +336 = 0, Ceiling_LowerByValue(0) +337 = 0, Ceiling_MoveToValue(0) +338 = 0, Ceiling_RaiseInstant(0) +339 = 0, Ceiling_LowerInstant(0) +340 = 0, Stairs_BuildUpDoom(0) +341 = 0, Stairs_BuildDownDoom(0) +342 = 0, Stairs_BuildUpDoomSync(0) +343 = 0, Stairs_BuildDownDoomSync(0) // Two-way portals are not supported yet either 344 = 0, Unsupported() // "Portal_TwowayCeiling" @@ -115,18 +114,16 @@ define Unsupported (0) 347 = 0, Unsupported() // "Portal_TwowayAnchorLineFloor" // More parameterized linedefs -/* - 348: "Polyobj_StartLine" - 349: "Polyobj_ExplicitLine" - 350: "Polyobj_DoorSlide" - 351: "Polyobj_DoorSwing" - 352: "Polyobj_Move" - 353: "Polyobj_OR_Move" - 354: "Polyobj_RotateRight" - 355: "Polyobj_OR_RotateRight" - 356: "Polyobj_RotateLeft" - 357: "Polyobj_OR_RotateLeft" -*/ +348 = 0, Polyobj_StartLine(0) +349 = 0, Polyobj_ExplicitLine(0) +350 = 0, Polyobj_DoorSlide(0) +351 = 0, Polyobj_DoorSwing(0) +352 = 0, Polyobj_Move(0) +353 = 0, Polyobj_OR_Move(0) +354 = 0, Polyobj_RotateRight(0) +355 = 0, Polyobj_OR_RotateRight(0) +356 = 0, Polyobj_RotateLeft(0) +357 = 0, Polyobj_OR_RotateLeft(0) // Eternity's linked portals, vertical link version (floor-to-ceiling) 358 = 0, Unsupported() // "Portal_LinkedCeiling" @@ -135,22 +132,20 @@ define Unsupported (0) 361 = 0, Unsupported() // "Portal_LinkedAnchorLineFloor" // Even more parameterized linedefs -/* - 362: "Pillar_Build" - 363: "Pillar_BuildAndCrush" - 364: "Pillar_Open" - 365: "ACS_Execute" - 366: "ACS_Suspend" - 367: "ACS_Terminate" - 368: "Light_RaiseByValue" - 369: "Light_LowerByValue" - 370: "Light_ChangeToValue" - 371: "Light_Fade" - 372: "Light_Glow" - 373: "Light_Flicker" - 374: "Light_Strobe" - 375: "Radius_Quake" -*/ +362 = 0, Pillar_Build(0) +363 = 0, Pillar_BuildAndCrush(0) +364 = 0, Pillar_Open(0) +365 = 0, ACS_Execute(0) +366 = 0, ACS_Suspend(0) +367 = 0, ACS_Terminate(0) +368 = 0, Light_RaiseByValue(0) +369 = 0, Light_LowerByValue(0) +370 = 0, Light_ChangeToValue(0) +371 = 0, Light_Fade(0) +372 = 0, Light_Glow(0) +373 = 0, Light_Flicker(0) +374 = 0, Light_Strobe(0) +375 = 0, Radius_Quake(0) // Eternity's linked portals, horizontal link version (wall-to-wall) 376 = 0, Unsupported() // "Portal_LinkedLineToLine" @@ -186,7 +181,21 @@ define Unsupported (0) 396 = 0, Plane_Copy(tag, tag)// "Slope_FrontFloorAndCeilingToTaggedSlope" // Last parameterized linedefs -// 397 = Floor_Waggle -// 398 = Thing_Spawn -// 399 = Thing_SpawnNoFog -// 400 = Teleport_EndGame +397 = 0, Floor_Waggle(0) +398 = 0, Thing_Spawn(0) +399 = 0, Thing_SpawnNoFog(0) +400 = 0, Teleport_EndGame(0) + +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) From feeaf29c461d77c1e28ae9e9f5e920686ed1ab33 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 7 Jan 2016 22:20:01 +0100 Subject: [PATCH 3/7] - set translations for Eternity's linked portals for testing. --- wadsrc/static/xlat/eternity.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/wadsrc/static/xlat/eternity.txt b/wadsrc/static/xlat/eternity.txt index fe88e5cded..d1cb400f5a 100644 --- a/wadsrc/static/xlat/eternity.txt +++ b/wadsrc/static/xlat/eternity.txt @@ -125,11 +125,11 @@ define Unsupported (0) 356 = 0, Polyobj_RotateLeft(0) 357 = 0, Polyobj_OR_RotateLeft(0) -// Eternity's linked portals, vertical link version (floor-to-ceiling) -358 = 0, Unsupported() // "Portal_LinkedCeiling" -359 = 0, Unsupported() // "Portal_LinkedFloor" -360 = 0, Unsupported() // "Portal_LinkedAnchorLine" -361 = 0, Unsupported() // "Portal_LinkedAnchorLineFloor" +// Eternity's linked portals, vertical link version (floor-to-ceiling) (NOTE: Type needs changing!) +358 = 0, Sector_SetPortal(tag, 0, 1, 1, 0) // "Portal_AnchoredCeiling" +359 = 0, Sector_SetPortal(tag, 0, 0, 1, 0) // "Portal_AnchoredFloor" +360 = 0, Sector_SetPortal(tag, 0, 1, 0, 0) // "Portal_AnchorLine" +361 = 0, Sector_SetPortal(tag, 0, 0, 0, 0) // "Portal_AnchorLineFloor" // Even more parameterized linedefs 362 = 0, Pillar_Build(0) From 4fd0a726b1fe76ca35fefc3d154e05b5e66cfd81 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 9 Jan 2016 00:58:13 +0100 Subject: [PATCH 4/7] - more work on EDF handling. Vaporware demo is now loading. --- src/edf.cpp | 222 +++++++++++++++++++---------- src/g_doomedmap.cpp | 1 + src/info.h | 1 + src/p_lnspec.h | 2 + src/p_setup.cpp | 74 ++++++---- src/p_tags.cpp | 22 +++ src/p_tags.h | 1 + wadsrc/static/mapinfo/eternity.txt | 8 ++ wadsrc/static/xlat/eternity.txt | 15 +- 9 files changed, 246 insertions(+), 100 deletions(-) create mode 100644 wadsrc/static/mapinfo/eternity.txt diff --git a/src/edf.cpp b/src/edf.cpp index 05c66ee8bc..439cd542dd 100644 --- a/src/edf.cpp +++ b/src/edf.cpp @@ -30,6 +30,8 @@ ** 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" @@ -42,6 +44,8 @@ #include "info.h" #include "p_lnspec.h" #include "p_setup.h" +#include "p_tags.h" +#include "r_data/colormaps.h" struct FEdfOptions : public FOptionalMapinfoData @@ -116,22 +120,23 @@ struct EDFSector int damageamount; int damageinterval; FNameNoInit damagetype; + FNameNoInit floorterrain; + + DWORD color; - // These do not represent any of ZDoom's features. They are maintained like this so that the Add and Remove versions work as intended. DWORD damageflags; DWORD damageflagsAdd; DWORD damageflagsRemove; - // floorterrain (Type TBD) - // ceilingterrain is ignored - // colormaptop/mid/bottom need to be translated into color values (the colormap implementation in Eternity is not the same as in Boom!) + // 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 EDFLines; static TMap EDFSectors; static TMap EDFThings; @@ -139,14 +144,15 @@ static TMap EDFThings; static void parseLinedef(FScanner &sc) { + EDFLinedef ld; + bool argsset = false; + + memset(&ld, 0, sizeof(ld)); + ld.alpha = FRACUNIT; + sc.MustGetStringName("{"); while (!sc.CheckString("}")) { - EDFLinedef ld; - bool argsset = false; - - memset(&ld, 0, sizeof(ld)); - ld.alpha = FRACUNIT; sc.MustGetString(); if (sc.Compare("recordnum")) { @@ -173,7 +179,7 @@ static void parseLinedef(FScanner &sc) { // 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. + // For now just store a negative number and resolve this later. ld.special = -sc.Number; } else @@ -187,11 +193,12 @@ static void parseLinedef(FScanner &sc) sc.CheckString("="); sc.MustGetStringName("{"); int c = 0; - while (!sc.CheckString("}")) + while (true) { sc.MustGetNumber(); ld.args[c++] = sc.Number; - + if (sc.CheckString("}")) break; + sc.MustGetStringName(","); } argsset = true; } @@ -201,13 +208,14 @@ static void parseLinedef(FScanner &sc) sc.MustGetFloat(); ld.alpha = FLOAT2FIXED(sc.Float); } - else if (sc.Compare("options")) + 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")) { @@ -235,29 +243,33 @@ static void parseLinedef(FScanner &sc) { 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; - if (!argsset) memcpy(ld.args, line.args, sizeof(ld.args)); - } } + 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; + sc.MustGetStringName("{"); while (!sc.CheckString("}")) { - EDFSector sec; - - memset(&sec, 0, sizeof(sec)); - sec.overlayalpha[sector_t::floor] = sec.overlayalpha[sector_t::ceiling] = FRACUNIT; sc.MustGetString(); if (sc.Compare("recordnum")) { @@ -288,6 +300,7 @@ static void parseSector(FScanner &sc) { flagvar = &sec.flags; } + sc.CheckString("="); do { sc.MustGetString(); @@ -337,6 +350,7 @@ static void parseSector(FScanner &sc) { flagvar = &sec.damageflags; } + sc.CheckString("="); do { sc.MustGetString(); @@ -355,7 +369,8 @@ static void parseSector(FScanner &sc) { sc.CheckString("="); sc.MustGetString(); - // ZDoom does not implement this yet. + sec.floorterrain = sc.String; // Todo: ZDoom does not implement this yet. + } else if (sc.Compare("floorangle")) { @@ -393,17 +408,23 @@ static void parseSector(FScanner &sc) sc.MustGetFloat(); sec.planexform[sector_t::ceiling].yoffs = FLOAT2FIXED(sc.Float); } - else if (sc.Compare("colormaptop") || sc.Compare("colormapbottom")) + else if (sc.Compare("colormaptop") || sc.Compare("colormapbottom") || sc.Compare("ceilingterrain")) { sc.CheckString("="); sc.MustGetString(); - // not implemented by ZDoom + // these properties are not implemented by ZDoom } else if (sc.Compare("colormapmid")) { sc.CheckString("="); sc.MustGetString(); - // the colormap should be analyzed and converted into an RGB color value. + // 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; + } } else if (sc.Compare("overlayalpha")) { @@ -411,12 +432,16 @@ static void parseSector(FScanner &sc) sc.MustGetString(); if (sc.Compare("floor")) { - sc.MustGetFloat(); + 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); } } @@ -429,6 +454,7 @@ static void parseSector(FScanner &sc) else if (sc.Compare("ceiling")) dest = sector_t::ceiling; else sc.ScriptError("Unknown portal type '%s'", sc.String); + sc.CheckString("="); do { sc.MustGetString(); @@ -450,17 +476,19 @@ static void parseSector(FScanner &sc) 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("}")) { - EDFMapthing mt; - - memset(&mt, 0, sizeof(mt)); - mt.flags |= MTF_SINGLE | MTF_COOPERATIVE | MTF_DEATHMATCH; // EDF uses inverse logic, like Doom.exe sc.MustGetString(); if (sc.Compare("recordnum")) { @@ -505,7 +533,8 @@ static void parseMapthing(FScanner &sc) } else { - //Let's hope not something internal to Eternity... + // 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); } @@ -531,6 +560,7 @@ static void parseMapthing(FScanner &sc) } else if (sc.Compare("options")) { + sc.CheckString("="); do { sc.MustGetString(); @@ -554,54 +584,98 @@ static void parseMapthing(FScanner &sc) sc.ScriptError("Unknown property '%s'", sc.String); } } + EDFThings[mt.recordnum] = mt; } -void loadEDF() +void InitEDF() { FString filename; FScanner sc; - EDFLines.Clear(); - EDFSectors.Clear(); - EDFThings.Clear(); - - const char *arg = Args->CheckValue("-edf"); - - if (arg != NULL) filename = arg; - else + if (EDFMap.CompareNoCase(level.MapName) != 0) { - FEdfOptions *opt = level.info->GetOptData("EDF", false); - if (opt != NULL) - { - filename = opt->edfName; - } - } + EDFLines.Clear(); + EDFSectors.Clear(); + EDFThings.Clear(); + EDFMap = level.MapName; - if (filename.IsEmpty()) return; - int lump = Wads.CheckNumForFullName(filename, true, ns_global); - if (lump == -1) return; - sc.OpenLumpNum(lump); + const char *arg = Args->CheckValue("-edf"); - 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); - } + if (arg != NULL) filename = arg; else { - sc.ScriptError("Unknown keyword '%s'", sc.String); + FEdfOptions *opt = level.info->GetOptData("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); +} -} \ No newline at end of file diff --git a/src/g_doomedmap.cpp b/src/g_doomedmap.cpp index 42157101d0..9a2cc137d0 100644 --- a/src/g_doomedmap.cpp +++ b/src/g_doomedmap.cpp @@ -69,6 +69,7 @@ const char *SpecialMapthingNames[] = { "$CopyCeilingPlane", "$VertexFloorZ", "$VertexCeilingZ", + "$EDFThing", }; //========================================================================== diff --git a/src/info.h b/src/info.h index 22e3b2f5cd..cd32f2f1b4 100644 --- a/src/info.h +++ b/src/info.h @@ -313,6 +313,7 @@ enum ESpecialMapthings SMT_CopyCeilingPlane, SMT_VertexFloorZ, SMT_VertexCeilingZ, + SMT_EDFThing, }; diff --git a/src/p_lnspec.h b/src/p_lnspec.h index 9fb4c17b38..3f97c75e67 100644 --- a/src/p_lnspec.h +++ b/src/p_lnspec.h @@ -60,6 +60,8 @@ typedef enum { Init_Damage = 2, Init_SectorLink = 3, NUM_STATIC_INITS, + Init_EDFSector = 253, + Init_EDFLine = 254, Init_TransferSky = 255 } staticinit_t; diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 3749e97aae..6bbb850359 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -68,6 +68,9 @@ #include "po_man.h" #include "r_renderer.h" #include "r_data/colormaps.h" +#ifndef NO_EDF +#include "edf.h" +#endif #include "fragglescript/t_fs.h" @@ -1759,34 +1762,45 @@ void P_LoadThings (MapData * map) mti[i].alpha = -1; mti[i].health = 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].y = LittleShort(mt->y) << FRACBITS; mti[i].angle = LittleShort(mt->angle); mti[i].EdNum = LittleShort(mt->type); 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; } @@ -2157,7 +2171,19 @@ void P_LoadLineDefs (MapData * map) // [RH] Translate old linedef special and flags to be // 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->v2 = &vertexes[LittleShort(mld->v2)]; @@ -3325,7 +3351,7 @@ void P_LoadBehavior (MapData * map) void P_GetPolySpots (MapData * map, TArray &spots, TArray &anchors) { - if (map->HasBehavior) + //if (map->HasBehavior) { for (unsigned int i = 0; i < MapThingsConverted.Size(); ++i) { diff --git a/src/p_tags.cpp b/src/p_tags.cpp index 15528378b0..50e5694a30 100644 --- a/src/p_tags.cpp +++ b/src/p_tags.cpp @@ -118,6 +118,28 @@ void FTagManager::RemoveSectorTags(int sect) // //----------------------------------------------------------------------------- +void FTagManager::RemoveLineIDs(int sect) +{ + if (startForLine.Size() > (unsigned int)sect) + { + int start = startForLine[sect]; + if (start >= 0) + { + while (allIDs[start].target == sect) + { + allIDs[start].tag = allIDs[start].target = -1; + start++; + } + } + } +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + void FTagManager::AddLineID(int line, int tag) { if (tag == -1) return; // For line IDs -1 means 'not set', unlike sectors. diff --git a/src/p_tags.h b/src/p_tags.h index c3162d9b56..e196600a62 100644 --- a/src/p_tags.h +++ b/src/p_tags.h @@ -64,6 +64,7 @@ public: void AddSectorTag(int sector, int tag); void AddLineID(int line, int tag); void RemoveSectorTags(int sect); + void RemoveLineIDs(int sect); void DumpTags(); }; diff --git a/wadsrc/static/mapinfo/eternity.txt b/wadsrc/static/mapinfo/eternity.txt new file mode 100644 index 0000000000..ad0bab886e --- /dev/null +++ b/wadsrc/static/mapinfo/eternity.txt @@ -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" +} + diff --git a/wadsrc/static/xlat/eternity.txt b/wadsrc/static/xlat/eternity.txt index d1cb400f5a..02fbc03033 100644 --- a/wadsrc/static/xlat/eternity.txt +++ b/wadsrc/static/xlat/eternity.txt @@ -8,11 +8,18 @@ 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 // indicated for the current level by the EMAPINFO lump, what line special // to actually use. This is how parameterized linedefs are used by Eternity -// in the Doom format. "xlating" this would thus be quite complicated... -270 = 0, Unsupported() // "ExtraDataSpecial" +// in the Doom format. + +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 // 271 = 0, Static_Init (tag, Init_TransferSky, 0) @@ -62,6 +69,7 @@ define Unsupported (0) // Hexen format is incomplete; and Quasar wants to use ZDoom-compatible special values for UDMF. // The translation here is for the odd EDF that specifies them as numbers. +/* 300 = 0, Door_Raise(0) 301 = 0, Door_Open(0) 302 = 0, Door_Close(0) @@ -106,6 +114,7 @@ define Unsupported (0) 341 = 0, Stairs_BuildDownDoom(0) 342 = 0, Stairs_BuildUpDoomSync(0) 343 = 0, Stairs_BuildDownDoomSync(0) +*/ // Two-way portals are not supported yet either 344 = 0, Unsupported() // "Portal_TwowayCeiling" @@ -186,6 +195,8 @@ define Unsupported (0) 399 = 0, Thing_SpawnNoFog(0) 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) From d0978d07602307e5523989dd7302cbd7c6c9dbb8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 10 Jan 2016 09:52:02 +0100 Subject: [PATCH 5/7] - added EDF sector handling. --- src/edf.cpp | 120 +++++++++++++++++++++++++++++++++++++++++++------ src/p_spec.cpp | 9 +++- src/r_defs.h | 6 +++ 3 files changed, 120 insertions(+), 15 deletions(-) diff --git a/src/edf.cpp b/src/edf.cpp index 439cd542dd..3676e445c6 100644 --- a/src/edf.cpp +++ b/src/edf.cpp @@ -45,6 +45,8 @@ #include "p_lnspec.h" #include "p_setup.h" #include "p_tags.h" +#include "p_terrain.h" +#include "v_palette.h" #include "r_data/colormaps.h" @@ -120,7 +122,11 @@ struct EDFSector int damageamount; int damageinterval; FNameNoInit damagetype; - FNameNoInit floorterrain; + BYTE leaky; + BYTE leakyadd; + BYTE leakyremove; + int floorterrain; + int ceilingterrain; DWORD color; @@ -128,7 +134,10 @@ struct EDFSector DWORD damageflagsAdd; DWORD damageflagsRemove; - // ceilingterrain is ignored + bool flagsSet; + bool damageflagsSet; + bool colorSet; + // colormaptop//bottom cannot be used because ZDoom has no corresponding properties. FTransform planexform[2]; @@ -266,6 +275,7 @@ static void parseSector(FScanner &sc) 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("}")) @@ -298,6 +308,7 @@ static void parseSector(FScanner &sc) } else { + sec.flagsSet = true; flagvar = &sec.flags; } sc.CheckString("="); @@ -306,7 +317,7 @@ static void parseSector(FScanner &sc) sc.MustGetString(); for (const char *tok = strtok(sc.String, ",+ \t"); tok != NULL; tok = strtok(NULL, ",+ \t")) { - if (!stricmp(tok, "SECRET")) *flagvar |= SECF_SECRET; + 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; @@ -330,16 +341,19 @@ static void parseSector(FScanner &sc) 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 { @@ -348,7 +362,9 @@ static void parseSector(FScanner &sc) } else { + sec.damageflagsSet = true; flagvar = &sec.damageflags; + leakvar = &sec.leaky; } sc.CheckString("="); do @@ -356,8 +372,8 @@ static void parseSector(FScanner &sc) sc.MustGetString(); for (const char *tok = strtok(sc.String, ",+ \t"); tok != NULL; tok = strtok(NULL, ",+ \t")) { - if (!stricmp(tok, "LEAKYSUIT")) *flagvar |= 1; - else if (!stricmp(tok, "IGNORESUIT")) *flagvar |= 2; // these first 2 bits will be used to set 'leakychance', but this can only be done when the sector gets initialized + 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; @@ -369,8 +385,7 @@ static void parseSector(FScanner &sc) { sc.CheckString("="); sc.MustGetString(); - sec.floorterrain = sc.String; // Todo: ZDoom does not implement this yet. - + sec.floorterrain = P_FindTerrain(sc.String); } else if (sc.Compare("floorangle")) { @@ -390,6 +405,12 @@ static void parseSector(FScanner &sc) 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("="); @@ -408,7 +429,7 @@ static void parseSector(FScanner &sc) sc.MustGetFloat(); sec.planexform[sector_t::ceiling].yoffs = FLOAT2FIXED(sc.Float); } - else if (sc.Compare("colormaptop") || sc.Compare("colormapbottom") || sc.Compare("ceilingterrain")) + else if (sc.Compare("colormaptop") || sc.Compare("colormapbottom")) { sc.CheckString("="); sc.MustGetString(); @@ -424,6 +445,7 @@ static void parseSector(FScanner &sc) if (cmap != 0) { sec.color = R_BlendForColormap(cmap) & 0xff000000; + sec.colorSet = true; } } else if (sc.Compare("overlayalpha")) @@ -460,12 +482,12 @@ static void parseSector(FScanner &sc) sc.MustGetString(); for (const char *tok = strtok(sc.String, ",+ \t"); tok != NULL; tok = strtok(NULL, ",+ \t")) { - if (!stricmp(tok, "DISABLED")) sec.portalflags[dest] |= 0; - else if (!stricmp(tok, "NORENDER")) sec.portalflags[dest] |= 0; - else if (!stricmp(tok, "NOPASS")) sec.portalflags[dest] |= 0; - else if (!stricmp(tok, "BLOCKSOUND")) sec.portalflags[dest] |= 0; - else if (!stricmp(tok, "OVERLAY")) sec.portalflags[dest] |= 0; - else if (!stricmp(tok, "ADDITIVE")) sec.portalflags[dest] |= 0; + 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); } @@ -679,3 +701,73 @@ void ProcessEDFLinedef(line_t *ld, int recordnum) 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(§ors[i], edfsectorrecord[i]); + } + } + delete[] edfsectorrecord; +} \ No newline at end of file diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 1ce505da9f..18f6cc26fe 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -62,6 +62,9 @@ #include "farchive.h" #include "a_keys.h" #include "c_dispatch.h" +#ifndef NO_EDF +#include "edf.h" +#endif // State. #include "r_state.h" @@ -1313,6 +1316,7 @@ void P_SpawnSpecials (void) // Init special SECTORs. sector = sectors; + for (i = 0; i < numsectors; i++, sector++) { if (sector->special == 0) @@ -1321,7 +1325,10 @@ void P_SpawnSpecials (void) P_InitSectorSpecial(sector, sector->special, false); } - // Here is the place to handle EDF for sectors. +#ifndef NO_EDF + ProcessEDFSectors(); +#endif + // Init other misc stuff diff --git a/src/r_defs.h b/src/r_defs.h index a7e37f369e..c05fdf2fc4 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -331,6 +331,12 @@ enum PLANEF_ABSLIGHTING = 1, // floor/ceiling light is absolute, not relative PLANEF_BLOCKED = 2, // can not be moved anymore. PLANEF_ADDITIVE = 4, // rendered additive + + // linked portal stuff + PLANEF_NORENDER = 8, + PLANEF_NOPASS = 16, + PLANEF_BLOCKSOUND = 32, + PLANEF_DISABLED = 64, }; // Internal sector flags From 1e193206bf27d6ae79507b4c16109b432bca8159 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 10 Jan 2016 10:08:06 +0100 Subject: [PATCH 6/7] - removed unused RemoveLineIDs function. --- src/p_tags.cpp | 22 ---------------------- src/p_tags.h | 1 - 2 files changed, 23 deletions(-) diff --git a/src/p_tags.cpp b/src/p_tags.cpp index 50e5694a30..15528378b0 100644 --- a/src/p_tags.cpp +++ b/src/p_tags.cpp @@ -118,28 +118,6 @@ void FTagManager::RemoveSectorTags(int sect) // //----------------------------------------------------------------------------- -void FTagManager::RemoveLineIDs(int sect) -{ - if (startForLine.Size() > (unsigned int)sect) - { - int start = startForLine[sect]; - if (start >= 0) - { - while (allIDs[start].target == sect) - { - allIDs[start].tag = allIDs[start].target = -1; - start++; - } - } - } -} - -//----------------------------------------------------------------------------- -// -// -// -//----------------------------------------------------------------------------- - void FTagManager::AddLineID(int line, int tag) { if (tag == -1) return; // For line IDs -1 means 'not set', unlike sectors. diff --git a/src/p_tags.h b/src/p_tags.h index e196600a62..c3162d9b56 100644 --- a/src/p_tags.h +++ b/src/p_tags.h @@ -64,7 +64,6 @@ public: void AddSectorTag(int sector, int tag); void AddLineID(int line, int tag); void RemoveSectorTags(int sect); - void RemoveLineIDs(int sect); void DumpTags(); }; From 39cdb7cf30d5b6ddbee19c6c968a1da434b85ea0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 10 Jan 2016 10:21:17 +0100 Subject: [PATCH 7/7] - implement 'loadacs' option for MAPINFO. --- src/edf.cpp | 13 ++++++++++++- src/p_setup.cpp | 4 ++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/edf.cpp b/src/edf.cpp index 3676e445c6..50ac2835c2 100644 --- a/src/edf.cpp +++ b/src/edf.cpp @@ -47,6 +47,7 @@ #include "p_tags.h" #include "p_terrain.h" #include "v_palette.h" +#include "p_acs.h" #include "r_data/colormaps.h" @@ -770,4 +771,14 @@ void ProcessEDFSectors() } } delete[] edfsectorrecord; -} \ No newline at end of file +} + +void LoadMapinfoACSLump() +{ + FEdfOptions *opt = level.info->GetOptData("EDF", false); + if (opt != NULL) + { + int lump = Wads.CheckNumForName(opt->acsName); + if (lump >= 0) FBehavior::StaticLoadModule(lump); + } +} diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 6bbb850359..46f984bf10 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -3702,6 +3702,10 @@ void P_SetupLevel (const char *lumpname, int position) } FBehavior::StaticLoadDefaultModules (); +#ifndef NO_EDF + LoadMapinfoACSLump(); +#endif + P_LoadStrifeConversations (map, lumpname);