EDF basics: Difference between revisions

From Eternity Wiki
Jump to navigationJump to search
No edit summary
Line 145: Line 145:


Unless the intention is to redefine the entire game structure, the overriding root EDF file must contain a command at the top to include the ''base\root.edf'' file, by using this function: ''stdinclude("root.edf")''. Note that it is possible to load several wads containing EDFROOT; they will be processed additively.
Unless the intention is to redefine the entire game structure, the overriding root EDF file must contain a command at the top to include the ''base\root.edf'' file, by using this function: ''stdinclude("root.edf")''. Note that it is possible to load several wads containing EDFROOT; they will be processed additively.
NOTE: EDF data is always loaded before any [[Dehacked]] lumps.


===Including files===
===Including files===

Revision as of 01:44, 30 March 2020

Back to EDF
  • This section incorporates text from the HTML Eternity documentation.

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++. Also, the equal sign (as a standalone operator) used to connect keywords with values is no longer required. 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. To reduce cluttering, examples and definitions throughout this wiki will be written without the equal operator.

Mnemonics

Blocks in EDF are titled by identifiers (mnemonics).

Value types

Fields in EDF can take character string, heredoc, numeric values or lists of values.

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
  • \x80 : Changes text color to "brick" range where supported.
  • \x81 : Changes text color to "tan" range where supported.
  • \x82 : Changes text color to "gray" range where supported.
  • \x83 : Changes text color to "green" range where supported.
  • \x84 : Changes text color to "brown" range where supported.
  • \x85 : Changes text color to "gold" range where supported.
  • \x86 : Changes text color to "red" range where supported.
  • \x87 : Changes text color to "blue" range where supported.
  • \x88 : Changes text color to "orange" range where supported.
  • \x89 : Changes text color to "yellow" range where supported.
  • \x8a : Changes text color to CUSTOM COLOR 1.
  • \x8b : Changes text color to CUSTOM COLOR 2.
  • \x8c : Changes text color to CUSTOM COLOR 3.
  • \x8d : Changes text color to CUSTOM COLOR 4.
  • \xfa : Changes text color to "translucent" where supported.
  • \xfb : Changes text color to gamemode "normal" range where supported.
  • \xfc : Changes text color to gamemode "hilite" range where supported.
  • \xfd : Changes text color to gamemode "error" range where supported.
  • \xfe : Toggles text shadowing where supported.
  • \xff : 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.

NOTE: Simply adding "\" will not result in a newline character even if the continued string appears multiline in the EDF file. For text that is supposed to be multiline, use heredocs instead.

Heredocs

EDF supports heredocs, which are multi-line strings. A heredoc is delimited by @" and "@, and can be placed interchangeably with a string, especially where more lines are needed. Heredocs are commonly used where non-EDF code is implemented, such as in DECORATE-style state definition or sound sequencing. Note: in heredocs, any character is taken into account, such as whitespaces at the beginning of a line. It is up to the interpreter reading the contents of the heredoc to remove extraneous whitespaces, and such characters will appear where literal text is to be written.

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.

Value lists

Fields can take multiple values, enclosed in curly braces and separates by commas. The spritenames block includes such an example, or other situations such as non-heredoc sound sequences.

Note: commas are not interchangeable with semicolons, and are used only to separate values inside lists, whereas semicolons are simple substitutes to white space in general parts of the code.

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
       
    */

Implementation

Loading EDF

By default, Eternity loads the EDF file from the relative path: base\root.edf. The root file can be substituted as follows, either from an external file or a WAD lump:

  • To load an EDF root from 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
  • A 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.

Unless the intention is to redefine the entire game structure, the overriding root EDF file must contain a command at the top to include the base\root.edf file, by using this function: stdinclude("root.edf"). Note that it is possible to load several wads containing EDFROOT; they will be processed additively.

NOTE: EDF data is always loaded before any Dehacked lumps.

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.

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, include the standard, default EDF files into your own. To include the files from Eternity's base directory, use the stdinclude function:

stdinclude("root.edf")

Note: to ensure backward and forward compatibility, do not include other EDF files from the base directory than root.edf.

Include statements may only be located at the topmost level of an EDF file, and not inside any section.

The userinclude function allows the optional inclusion of a file from Eternity's base 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

This lumpinclude 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")

Note: including a lump or file several times will not cause duplicate loading of data.

Including BEX files(deprecated)

It is possible to include BEX files by using:

bexinclude("file.bex")

but it is recommended to use the DEHACKED lump or GFS files rather than EDF.

Base EDF files

This section explains the contents of each of the standard default EDF modules. Note that some are game-dependent and are in consequence included in their respective folders, as well as the base folder for the common features.

  • cast.edf -- contains castinfo (Doom 2 cast call) definitions
  • fonts.edf -- contains font definitions -- game dependent
  • frames.edf -- contains frame definitions -- game dependent
  • misc.edf -- contains boss_spawner_types and some Heretic-specific string blocks
  • player.edf -- contains skin and playerclass definitions
  • root.edf -- includes all other modules
  • sounds.edf -- contains sound and soundsequence definitions -- game dependent
  • sprites.edf -- contains spritenames and pickupitem definitions
  • terrain.edf -- contains splash, terrain, floor definitions
  • things.edf -- contains thingtype and damagetype definitions -- game dependent
  • user.edf -- optional user-defined EDF file which may contain any definitions

Default fallbacks

As of 3.39.20, default fallback no longer exists.

Lumps besides EDFROOT that are automatically loaded

Eternity can load other EDF lumps, besides EDFROOT. Previously, they were dedicated to specific blocks, but now can have any purpose. Do not explicitly include them from EDFROOT.

  • ESTRINGS
  • ETERRAIN
  • EMENUS
  • ESNDSEQ
  • ESNDINFO
  • EFONTS

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. This has the positive side effect of improving the ability of your EDF patches to combine with those of others.

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.

The number of EDF warnings that happen will be reported unconditionally. To see the actual warning messages on the system console (as well as in the verbose log where they will always appear unconditionally), use the -edf-show-warnings parameter.

Enable Functions

Starting with EDF 1.2, special functions are provided which allow the user to enable or disable options within the EDF parser. The primary use for these functions is to instruct the parser to skip definitions for game modes other than the one currently being played. Although all the thing, frame, sound, and sprite definitions will not conflict and can be loaded with each other, most of the time this is unnecessary and requires a significant amount of memory which will never be used. Allowing such definitions to be discarded during parsing speeds up processing and reduces memory usage. Note that all of these functions are only valid at the topmost level of an EDF file, and not within definitions.

Enable Functions

enable(<option>)

This function enables the provided option from the point of its call onward. If the option is already enabled, no change takes place. If an invalid option name is provided, an error will occur.

disable(<option>)

This function disables the provided option from the point of its call onward. If the option is already disabled, no change takes place. If an invalid option name is provided, an error will occur.

ifenabled(<option>, ...)

This function tests if the the provided option is enabled. If so, nothing will change. Otherwise, the EDF parser will be instructed to skip forward until it finds an endif function (see below). The endif function will then be invoked. If the option provided is invalid, an error will occur. Note that ifenabled/endif pairs cannot be nested.

As of EDF 1.5, it is possible to provide any number of valid enable options to this function. In the case that more than one enable option is provided, *all* specified options must be enabled or the section will be skipped.

ifenabledany(<option>, ...)

New to EDF 1.5, this function tests if *any* of the provided options are enabled. If any are, nothing will change. Otherwise, parsing will skip to the next endif function.

ifdisabled(<option>, ...)

New to EDF 1.5, this function tests if *all* of the provided options are disabled. If all options are disabled, nothing will change. Otherwise, parsing will skip to the next endif function.

ifdisabledany(<option>, ...)

New to EDF 1.5, this function tests if *any* of the provided options are disabled. If any of the options are disabled, nothing will change. Otherwise, parsing will skip to the next endif function.

endif()

This function marks the end of a section of the file started by an ifenabled, ifenabledany, ifdisabled, ifdisabledany, ifgametype, or ifngametype call.

When any of the aforementioned functions tests an option or value that is not enabled or is set to a different value, the parser will look for this function and then call it. This function will cause the parser to start recognizing definitions again from its line onward. If this function does not appear after one of the mentioned functions and before the end of the current file, a "missing conditional function" error will occur.

Available Options

DOOM

When this option is enabled, DOOM thing, frame, state, and sound definitions will be available. This variable is enabled by default for all user EDFs, but is disabled if the game is loaded in Heretic mode and the default root.edf file in Eternity's directory is loaded.

HERETIC

When this option is enabled, Heretic thing, frame, state, and sound definitions will be available. This variable is enabled by default for all user EDFs, but is disabled if the game is loaded in DOOM or DOOM II mode and the default root.edf in Eternity's directory is loaded.

Notes on Game Mode Options:

As mentioned in their descriptions, the DOOM and HERETIC options will be enabled by default when user EDF files are loaded. However, user EDF files can explicitly call the disable function to turn off one or both options before including any of Eternity's defaults. It is best to do this when you know you will not be using any of one of the game modes' definitions.

Example:

// this thing type is only available if HERETIC is enabled

ifenabled(HERETIC)

thingtype foo { spawnstate = S_FOO1 }

endif()

Note on command-line option "-edfenables": The -edfenables command-line option allows the user to override the default behavior explicitly and enable all gamemodes' definitions without adding an EDF file. This does not interfere with explicit usage of enable functions in user EDFs, but it does allow older DeHackEd patches and WADs which might assume Heretic definitions are available in DOOM or vice versa to work.

Gametype Functions

Starting with EDF 1.5, special functions are provided which allow the EDF parser to evaluate definitions conditionally depending on the actual type of game being played. This enables definitions which should only exist in one game type or another to be placed within a single EDF module without conflict or unnecessary waste of memory and processing time. Note that all of these functions are only valid at the topmost level of an EDF file, and not within definitions.

Gametype Functions

ifgametype(<gametype>, ...)

This function tests the active gametype against every gametype listed as a parameter. If the gametype matches any of the listed types, nothing will change. Otherwise, processing will skip to the next endif function.

ifngametype(<option>, ...)

This function tests the active gametype against every gametype listed as a parameter. If the gametype matches none of the listed types, nothing will change. Otherwise, processing will skip to the next endif function.

Gametype Values

DOOM

This gametype is used for DOOM, Ultimate DOOM, DOOM II, and Final DOOM.

HERETIC

This gametype is used for Heretic and Heretic: Shadow of the Serpent Riders.

Notes on Gametype Values:

Gametype values, like the rest of EDF, are case-insensitive. Only values listed above should be used with the gametype detection functions.

Example:

// this TerrainTypes floor is only available when Heretic is being played

ifgametype(HERETIC)

floor { flat = FLATHUH1; terrain = Lava }

endif()