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)