- 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 "doomdata.h"
#include "r_defs.h" #include "r_defs.h"
#include "info.h" #include "info.h"
#include "p_lnspec.h"
#include "p_setup.h"
struct FEdfOptions : public FOptionalMapinfoData struct FEdfOptions : public FOptionalMapinfoData
@ -96,10 +98,13 @@ struct EDFLinedef
int tag; int tag;
int id; int id;
int args[5]; int args[5];
float alpha; fixed_t alpha;
DWORD flags; DWORD flags;
DWORD activation;
}; };
struct EDFSector struct EDFSector
{ {
int recordnum; int recordnum;
@ -113,9 +118,9 @@ struct EDFSector
FNameNoInit damagetype; 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. // 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; DWORD damageflags;
int damageflagsAdd; DWORD damageflagsAdd;
int damageflagsRemove; DWORD damageflagsRemove;
// floorterrain (Type TBD) // floorterrain (Type TBD)
@ -134,10 +139,317 @@ static TMap<int, EDFMapthing> EDFThings;
static void parseLinedef(FScanner &sc) 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) 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) static void parseMapthing(FScanner &sc)

View file

@ -1320,6 +1320,8 @@ void P_SpawnSpecials (void)
P_InitSectorSpecial(sector, sector->special, false); P_InitSectorSpecial(sector, sector->special, false);
} }
// Here is the place to handle EDF for sectors.
// Init other misc stuff // Init other misc stuff

View file

@ -60,53 +60,52 @@ 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
344 = 0, Unsupported() // "Portal_TwowayCeiling" 344 = 0, Unsupported() // "Portal_TwowayCeiling"
@ -115,18 +114,16 @@ 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)
358 = 0, Unsupported() // "Portal_LinkedCeiling" 358 = 0, Unsupported() // "Portal_LinkedCeiling"
@ -135,22 +132,20 @@ define Unsupported (0)
361 = 0, Unsupported() // "Portal_LinkedAnchorLineFloor" 361 = 0, Unsupported() // "Portal_LinkedAnchorLineFloor"
// 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 +181,21 @@ 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)
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)