EDF

From Eternity Wiki
Jump to navigationJump to search

EDF, Eternity Definition File, is a language used to define and modify monsters, decorations, sounds, text strings, menus, terrain types, and other data in Eternity Engine.

In addition to the current feature set, plans are in place to steadily introduce more functionality to EDF, including inventory and weapon definitions.

Introduction

Tutorials

Thingtypes Reference

Note from Essel: This article is currently a mess. All this crap needs to get moved outta here and reorganized/rewritten into the separate pages listed above (and really, the pages listed above are just a start. There's plenty more to write about).

Syntax

EDF is Free-form

Whitespace and token positioning are totally free-form in EDF. In addition, semicolons are discarded as whitespace and can therefore be used to terminate field assignments, lists, etc. as in C or C++. As an example, all of the following are strictly equivalent:

    thingtype w00t { mass = 1000 }
    thingtype w00t
    {
       mass = 1000;
    }
    thingtype
                     w00t
                {
       mass     =
            1000     ;;;;;;
                    }

The usage of a clean and consistent format is encouraged, even though it is not required.

Comments

EDF files can use three forms of comments:

  • # Comments: Like in DeHackEd, this comment type extends to the end of the line.
  • // Comments: An alternate form of single-line comment, equivalent to #.
  • /* */ Comments: This type of comment is multiline, and extends from the opening /* to the first */ found. This type of comment CANNOT be nested. Nested multiline comments will cause a syntax error.

Examples:

    # Single line comment
    // Another single line comment
    /*
    
       This is a multiline comment
       
    */

Strings

Many fields in EDF take strings. Strings, if they do not contain whitespace or any character that needs to be escaped, may be unquoted. Unquoted strings additionally cannot contain any of the following characters: " ' = { } ( ) + , # / ; If any of those characters are found, the unquoted string will be terminated at the last valid character.

Example:

    spritenames += { SPR1, SPR2, SPR3 }

The items SPR1, SPR2, and SPR3 are unquoted strings. Note how the commas serve to separate the items in a list, and therefore do not become part of the strings.

Many fields more or less require quoted strings. Quoted strings must start and end with either single or double quotes (the beginning and ending quote types must match). Quoted strings may contain any character except a line break, including those not allowed in unquoted strings. In addition, quoted strings also support the following escape codes for non-typable characters:

  • \n : Hard line break
  • \t : Tab
  • \b : Backspace
  • \a : Beep (causes a sound when printed to the console)
  • \\ : Literal \ character.
  • \" : Literal ", necessary to use in double-quoted strings only
  • \' : Literal ', necessary to use in single-quoted strings only
  • \0 : Null character
  • \K : Changes text color to "brick" range where supported.
  • \1 : Changes text color to "tan" range where supported.
  • \2 : Changes text color to "gray" range where supported.
  • \3 : Changes text color to "green" range where supported.
  • \4 : Changes text color to "brown" range where supported.
  • \5 : Changes text color to "gold" range where supported.
  • \6 : Changes text color to "red" range where supported.
  • \7 : Changes text color to "blue" range where supported.
  • \8 : Changes text color to "orange" range where supported.
  • \9 : Changes text color to "yellow" range where supported.
  • \N : Changes text color to gamemode "normal" range where supported.
  • \H : Changes text color to gamemode "hilite" range where supported.
  • \E : Changes text color to gamemode "error" range where supported.
  • \S : Toggles text shadowing where supported.
  • \C : Toggles absolute centering of text where supported.

If \ is followed by any other character, the slash is discarded and the next character is treated normally (ie, \d becomes d). Avoid doing this, however, to maintain forward compatibility.

Examples:

    thingtype w00t
    {
       obituary_normal = "w00ts"
       obituary_melee  = 'says \'w00t\
    }

Line Continuation:

Starting with Eternity Engine v3.31 Delta, line continuation can be used to split quoted strings across multiple lines. The syntax for doing this is demonstrated in the following example:

    frame S_MYFRAME
    {
       cmp = "TROO|A|*|6 \
              TroopAttack|@next"
    }

The "\" character, when followed immediately by a line break, signifies that line continuation should be triggered. Whitespace before the line continuation will be included in the string, but any spaces or tabs at the beginning of the next line will NOT be included (this is the same as line continuation in BEX files). This allows the following continued parts of the string to be arbitrarily indented for purposes of beautification. A string can be split across any number of lines in this fashion.

Numbers

Most non-string fields in EDF are numbers, either integer or floating-point. Starting with EDF 1.1, decimal, octal, and hexadecimal integers will be accepted in all number fields. Octal numbers start with a zero, and hexadecimal numbers start with the sequence 0x -- Examples:

    # this is a normal, decimal number (base 10)
    spriteframe = 16
    ...
    # this is an octal number (base 8)
    spriteframe = 020
    ...
    # this is a hexadecimal number (base 16)
    spriteframe = 0x10

Floating-point numbers must have a decimal point in them, as in "20.0". Floating-point numbers are always base 10.

Reserved Identifiers

This section describes classes of identifiers (such as thing, frame, and sound mnemonics) which are considered reserved by the Eternity Engine. You should avoid using any identifier in the following classes for objects which you define yourself. Failure to do so could result in incompatibility of your project with future versions of the Eternity Engine due to conflicts with newly added game engine features.

  • All identifiers beginning with _ (underscore)
  • All identifiers beginning with EE or ee (this prefix means "Eternity Engine" and is therefore reserved for use by the source port's authors only).
  • All identifiers containing ANY non-alphanumeric character excepting non-leading underscores (ex: $ is reserved).

For maximum safety, it is recommended that you develop a consistent and unique naming scheme for objects you create yourself. A simplistic example would be prefixing the word My to mnemonics, such as "MyNewThingType". Such names are more or less guaranteed to never conflict with anything defined by the game engine itself. The Chex Quest III project uses the prefix "CQ" for this purpose. As a side effect, this also improves the ability of your EDF patches to combine with those of others.

Loading EDF

EDF can be loaded either from an external file or from a WAD lump.

  • To include EDF in a WAD file, the name of the root EDF lump must be "EDFROOT".
  • To include an EDF file from the command line, use the -edf parameter. For example:
   eternity -edf c:\blah\root.edf
  • The new GFS file can specify the root EDF file with the "edffile" keyword. Only one EDF file can be specified in a GFS. If -edf is used when a GFS is loaded, the command-line parameter will take precedence. See the GFS documentation for further information.

ESTRINGS lump

The ESTRINGS lump is an optional EDF lump which can contain any number of string definitions. String definitions found in the ESTRINGS lump which already exist will overwrite string definitions with the same mnemonic. ESTRINGS lumps do not cascade by default, but can be made to do so by using the include_prev funtion documented below.

Note: it is inappropriate to include an ESTRINGS lump from EDFROOT or from any file included by it, because ESTRINGS will be processed separately after the root EDF has been processed. Doing this will cause the definitions to be processed twice.

ETERRAIN lump

The ETERRAIN lump is an optional EDF lump which can contain any number of splash, terrain, and floor definitions. All definitions are additive, and if definitions of the same name already exist, they will overwrite. ETERRAIN lumps do not cascade by default, but can be made to do so by using the include_prev function documented below.

Note: it is inappropriate to include an ETERRAIN lump from EDFROOT or from any file included by it, because ETERRAIN will be processed separately after the root EDF has been processed. Doing this will cause the definitions to be processed twice.

Special note for ETERRAIN: If zero splash, terrain, AND floor objects are defined by both the root EDF and any ETERRAIN lump processed, the default terrain.edf module will be loaded in order to maintain compatibility with older projects. In order to disable this behavior, you will need to define at least one splash, terrain, or floor object. This object can be a dummy which is never used, however.

EMENUS lump

The EMENUS lump is an optional EDF lump which can contain any number of menu definitions and menu-system global variables. All definitions are additive, and if definitions of the same name already exist, they will overwrite. EMENUS lumps do not cascade by default, but can be made to do so by using the include_prev function documented below.

Note: it is inappropriate to include an EMENUS lump from EDFROOT or from any file included by it, because EMENUS will be processed separately after the root EDF has been processed. Doing this will cause the definitions to be processed twice.

Including files

Use of include files is critical for several purposes. First, it's unorganized and difficult to maintain EDF files when everything is put haphazardly into one file. Second, through use of the stdinclude function, user-provided EDF files can include the standard defaults, without need to duplicate the data in them. This helps keep EDF files compatible with future versions of the Eternity Engine, besides making your files much smaller.

To include a file or wad lump normally, with a path relative to the current file doing the inclusion, use the include function, like in these examples:

# include examples
include("myfile.edf")
include("../prevdir.edf");  # remember, semicolons are purely optional

This example would include "myfile.edf" from the same directory that the current file is in, and "prevdir.edf" from the parent directory. It is important to note that this function can only include files when called from within a file, and it can only include WAD lumps when called from within a WAD lump. This restriction is necessary due to how the complete path of the included file must be formed.

In order to remain compatible with future versions of Eternity, and to greatly reduce EDF file sizes, you can include the standard, default EDF files into your own. To include files relative to the Eternity executable's directory, use the stdinclude function, like in this example:

stdinclude("things.edf")

This would include "things.edf" in the Eternity Engine's folder. This function may be called from both files and WAD lumps.

Include statements may only be located at the topmost level of an EDF file, and not inside any section. The following example would not be valid:

spritenames =
{
   include("sprnames.txt")
}

Note that for maximum compatibility, you should limit EDF file names to MS-DOS 8.3 format and use only alphanumeric characters (ie, no spaces). This is not required for Windows or Linux, but the DOS port of Eternity cannot use long file names.

New to EDF 1.6 (Eternity Engine v3.33.33), the userinclude function allows the optional inclusion of a file from Eternity's folder. This function is identical to stdinclude, except that it will test to see if the file exists beforehand, and if it does not, no error will occur. This function is NOT for use by EDF editors in projects. This function is intended for end-user modification of EDF settings, including but not limited to the custom user menu. Example:

userinclude("user.edf")

This example can be found in Eternity's root.edf, where it exists to include the optional user-defined "user.edf" file. You should never attempt to overwrite the user.edf file with one from your own project, as this is outside the scope of its purpose and will be offensive to the end user.

Including lumps

Two special functions are provided for specifically including EDF lumps. The first function is lumpinclude. This function includes a wad lump when called from either a file or a lump. The lump named must exist, or an error will occur. The name must also be no longer than eight characters. Case of the lump name will be ignored as usual. Example:

lumpinclude("MYEDFLMP")

The second function, include_prev, may be called only from within a wad lump. This function is special in that you do not tell it what lump to include. Rather, it includes the previously loaded lump of the same name as the current lump being processed, if and only if such a lump exists. This allows cascading behavior to be enabled for lumps such as ESTRINGS and ETERRAIN, so that several wads adding such lumps will all load their definitions. For full flexibility, this does not happen by default. No error will occur if there is no previous lump -- the function call is simply ignored in that case. Example:

include_prev()

The order of lumps is determined first by the order of lumps in each wad, and then by the order in which wads were loaded. The first lump to be loaded by the game engine will be the last lump of a given name in the last wad that was loaded. include_prev will then continue back through lumps of the same name in the same wad, then in the previously loaded wad, etc.

Including BEX files

EDF supports including DeHackEd/BEX files. Any DeHackEd/BEX files included will be queued in the order they are included, after any other DeHackEd/BEX files to be processed. DeHackEd/BEX processing occurs immediately after EDF processing is complete. This allows better cohesion between the EDF and BEX languages, and also allows the user to specify fewer command line parameters or to avoid the need for a GFS file in some cases.

To include a DeHackEd/BEX file for queueing from EDF, use the bexinclude function, like in this example:

bexinclude("strings.bex")

The DeHackEd/BEX file will be included relative to the path of the including EDF file. There is no stdinclude equivalent for DeHackEd/BEX files, since the engine does not provide any default BEX files. You cannot call this function from within an EDF WAD lump, and an error message will be given if this is attempted.

Default EDF files

This section explains the contents of each of the standard default EDF modules as of Eternity Engine v3.33.33.

  • root.edf -- includes all other modules
  • sprites.edf -- contains the sprite names list and sprite-based pickup item definitions
  • sounds.edf -- contains sound definitions
  • frames.edf -- contains frame data for use by thing types and player guns
  • things.edf -- contains thing type definitions
  • cast.edf -- contains DOOM II cast call definitions
  • misc.edf -- contains the default list of DOOM II Boss Spawner thing types
  • terrain.edf -- contains default TerrainTypes definitions
  • user.edf -- optional user-defined EDF file which may contain any definitions

Default fallbacks

As a failsafe to allow old EDF modifications to continue working, EDF is now capable of loading default modules individually when it determines there are zero definitions of certain sections. The following modules will be loaded as fallbacks when the given conditions are met:

  • sprites.edf -- Loaded when zero sprite names are defined. Note that even if pickup items are defined by the user EDF, they will be overridden by the pickup items defined in sprites.edf.
  • sounds.edf -- Loaded when zero sounds are defined.
  • things.edf -- Loaded when zero thingtypes are defined.
  • frames.edf -- Loaded when zero frames are defined.
  • cast.edf -- Loaded when zero cast members are defined.
  • terrain.edf -- Loaded when zero splash, terrain, and floor objects are defined.

Note that misc.edf cannot currently be used as a fallback. Also, this functionality is NOT meant to allow users to neglect including the minimum required number of sections. This functionality is only intended to preserve maximum backward compatibility with old EDF modifications. Relying on fallback behavior in new EDFs may have unexpected results, including possibly having your new definitions ignored.

As mentioned earlier, to prevent default terrain loading, it will be necessary to define at least one splash, terrain, or floor object in the root EDF or ETERRAIN lump.

If the engine-default EDF files cannot be found or parsed for any reason, EDF processing will cease immediately.

Verbose EDF logging

Eternity includes a verbose logging feature in the EDF processor that allows a view of more detailed information on what is occuring while EDF is being processed. This can help nail down the location of any errors or omissions. To enable verbose EDF logging, use the command-line parameter -edfout. This will cause Eternity to write an "edfout##.txt" log file in its current working directory, where ## is a unique number from 0 to 99.


Okay, somebody else finish this article, figure out what's important enough to include, and figure out what's TMI. Too much work for me. :(

If you're looking for the full EDF documentation, download the EE docs from here: http://eternity.mancubus.net/ee3.33.50-docs.zip

Maybe you will even be inspired enough to finish writing this article!