- EDF parser for linedefs and sectors. Also extended the Eternity xlat table to handle the parameterized types to the point EDF needs.

This commit is contained in:
Christoph Oelckers 2016-01-06 22:40:11 +01:00
parent 9fe016d6d0
commit bdfac02f69
3 changed files with 406 additions and 83 deletions

View file

@ -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<int, EDFMapthing> 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)

View file

@ -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

View file

@ -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)