Eternity Engine EDF Reference v1.6 -- 04/02/06

Return to the Eternity Engine Page
Introduction to EDF

EDF, which stands for Eternity Definition Files, is a new data specification language for the Eternity Engine that allows dynamic definition of sprites, thing types, frames, and other previously internal data. The EDF parser is based on the libConfuse configuration file parser library by Martin Hedenfalk, which is also used by GFS and ExtraData.

EDF supercedes DeHackEd, and should become the preferred method for "exe" editing in the future. However, EDF retains features that allow DeHackEd compatibility, and DeHackEd patches may be loaded over EDF, and even have access to "new" things and frames that are defined by it.

Each section in this document deals with one of the EDF constructs, as well as showing their locations in the default EDF files. However, user-made EDF files can, with a few caveats, contain these structures in any arrangement of files and in any order. User EDF files do not need to use the same names or arrangements as the defaults, and they should NEVER be intended to overwrite the Eternity Engine's default files, unless they are being provided with a customized distribution of the engine itself.

Plans are in place to steadily introduce more features and functionality to EDF in future versions of the Eternity Engine, including most notably, weapon definitions. This documentation will be regularly updated to reflect all changes and additions.

Return to Table of Contents


Changes in EDF 1.6

Return to Table of Contents


General Syntax

Return to Table of Contents


Reserved Identifiers

This section is new to EDF 1.6 and 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. 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.

Return to Table of Contents


Files


Specifying the Root EDF File

Eternity supports several methods for locating the root EDF file, which is the only EDF file loaded directly for parsing. Excepting special lump chains documented below, all other EDF files must be included through the root EDF. Return to Table of Contents


Loading EDF From a WAD Lump

Starting with EDF 1.4, it is possible to load a WAD lump as the root EDF file. The name of the root EDF lump must be "EDFROOT", and the newest lump of that name is the one that will be loaded and parsed. See the section below on including files for information on how this affects EDF processing.

As of EDF 1.5, selective sets of EDF definitions may also be loaded additively from separate chains of optional lumps. These lumps are documented under their own sections below.

Return to Table of Contents


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.

Return to Table of Contents


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.

Return to Table of Contents


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.

Return to Table of Contents


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.

Return to Table of Contents


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.

Return to Table of Contents


Including BEX Files

As of Eternity Engine v3.31 public beta 5, EDF now 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.

Return to Table of Contents


Default EDF Files

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


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: 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.

Return to Table of Contents


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.

Return to Table of Contents


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 Available Options 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.

Return to Table of Contents


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 Gametype Values 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()
Return to Table of Contents


Strings

New to EDF 1.4, strings allow custom messages to be defined which may be used directly by various game engine subsystems and can be used by other facilities such as the ShowMessage codepointer.

Each string must be given a unique mnemonic in its definition's header, and this is the name used to identify the string elsewhere. Each field in the string definition is optional. If a field is not provided, it takes on the default value indicated below the syntax information. Fields may also be provided in any order.

As of EDF 1.5, string definitions may also be provided within special lumps named ESTRINGS. The ESTRINGS lump is parsed separately after the root EDF has been processed, and thus all string definitions found within the ESTRINGS lump are additive over those defined through the root EDF. If string definitions within the ESTRINGS lump have the same mnemonic as one already defined, they will overwrite the original definitions (note this also includes the numeric id field).

Syntax:
string <mnemonic>
{
   num = <unique number>
   val = <string>
}
Explanation of Fields: Restrictions and Caveats: Replacing Existing Strings:

To replace the values of an existing EDF string definition, simply define a new string with the exact same mnemonic value (as stated above, all strings need a unique mnemonic, so duplicate mnemonics serve to indicate that an existing string should be replaced).

Full Example:
# Define a string for use by the ShowMessage codepointer

string CyberMsg
{
   num = 0;
   val = "Moooo!";
}

# Define a string for use by the intermission
# See below for notes on reserved mnemonics and how the game engine uses them.

string _IN_NAME_MAP01 { val = "The Slough of Despond" }
Engine-Defined String Mnemonics

The following string mnemonics, if defined and properly enabled, will be used by game engine subsystems directly for the indicated purposes. All reserved mnemonics start with underscores. Using mnemonics that begin with underscores for your own strings is done at your own risk, since this may break compatibility of your patch with future versions of the Eternity Engine.

Mnemonic Name or Class           Purpose                         Use Enabled By
-------------------------------------------------------------------------------
_IN_NAME_*                       Intermission map names          MapInfo
-------------------------------------------------------------------------------
Return to Table of Contents


Sprite Names

Sprite names are defined as a list of string values which must be exactly four characters long, and should contain only capital letters and numbers.

Syntax:
spritenames = { <string>, ... }
If this syntax is used more than once, the definition which occurs last during parsing will take precedence as the original definition of the sprite name list. Values may either be added by copying the entire list in a new EDF file and adding the new values anywhere in the list, or by using the following syntax:
spritenames += { <string>, ... }
This syntax allows the addition of new sprite names to the list without requiring the original list to be changed or copied.

The names defined in this list are the names by which a sprite must be referred to in all other EDF structures. Sprites are the first item to be parsed, regardless of their location, so like all EDF structures, the list and any additions to it can be placed anywhere.

Note: Sprite names may be duplicated in the list. When this occurs, objects will use the corresponding index of the last definition of that sprite name. Avoid this whenever possible, as it is wasteful and may lead to inconsistencies if DeHackEd patches are subsequently applied. Previous versions of the EDF documentation inappropriately stated that all sprite names must be unique. This has never been true, and cannot be made true for purposes of forward compatibility (otherwise addition of new sprites to the default sprites.edf could break older EDFs).

Restrictions and Caveats: Full example:
# defining an original spritenames array (this would replace the default list)
# notice that sprite names never NEED to be quoted, but can be if so desired.
spritenames =
{
   FOO1, FOO2, FOO3, TNT1, PLAY
}

# add a few values in later (maybe near a thing or frames that use them)...
spritenames += { "BLAH", "WOOT" }
Return to Table of Contents


Sprite-Related Variables

There are two sprite-related variables which may be specified in user EDF files: playersprite sets the sprite to be used by the default "Marine" player skin. This must be one of the four-character sprite mnemonics defined in the spritenames array. If not provided in any EDF file, this variable defaults to the value "PLAY" (and if PLAY is not defined in that case, an error will occur).

blanksprite sets the sprite to be used when objects or guns attempt to use a sprite which has no graphics loaded. This must be one of the four-character sprite mnemonics defined in the spritenames array. If not provided in any EDF file, this variable defaults to the value "TNT1" (and if TNT1 is not defined in that case, an error will occur).

These values are parsed immediately after the sprite name list is loaded, and can be placed anywhere. If defined more than once, the last definition encountered takes precedence. These values must be defined at the topmost level of an EDF file.

Syntax:
playersprite = <sprite mnemonic>

blanksprite = <sprite mnemonic>
Full example:
# set the player skin sprite to BLAH
playersprite = BLAH

# set the blank sprite to FOO1
blanksprite = FOO1
Return to Table of Contents


Sprite-Based Pickup Items

Sprite-based pickup item definitions allow one of a set of predefined pickup effects to be associated with a sprite, so that collectable objects (with the SPECIAL flag set) using it will have that effect on the collecting player.

It is currently only possible to associate one effect with a given sprite, but effects can be assigned to as many sprites as is desired. If a sprite is assigned more than one pickup effect, the one occuring last takes precedence. There are plans to extend this feature in the future to include customizable pickup items, but for now only the predefined effects are available.

Syntax:
pickupitem <sprite mnemonic> { effect = <effect name> }
sprite mnemonic must be a valid sprite mnemonic defined in the spritenames list.
effect name may be any one of the following:
   ** Note: all ammo amounts double in "I'm Too Young To Die" and "Nightmare!"
   ** Note: weapons give 5 clips of ammo when "Weapons Stay" DM flag is on
   ** Note: dropped weapons give half normal ammo
   
   Effect Name         Item is...               Special effects
  ----------------------------------------------------------------------------
   PFX_NONE            No-op collectable        None
   PFX_GREENARMOR      Green armor jacket       +100% armor
   PFX_BLUEARMOR       Blue armor jacket        +200% armor
   PFX_POTION          DOOM health potion       +1% health
   PFX_ARMORBONUS      Armor bonus              +1% armor
   PFX_SOULSPHERE      Soulsphere               +100% health
   PFX_MEGASPHERE      Megasphere               200% health/armor
   PFX_BLUEKEY         DOOM Blue key card
   PFX_YELLOWKEY       DOOM Yellow key card
   PFX_REDKEY          DOOM Red key card
   PFX_BLUESKULL       DOOM Blue skull key
   PFX_YELLOWSKULL     DOOM Yellow skull key
   PFX_REDSKULL        DOOM Red skull key
   PFX_STIMPACK        Stimpack                 +10% health
   PFX_MEDIKIT         Medikit                  +25% health
   PFX_INVULNSPHERE    Invulnerability Sphere   Temporary god mode
   PFX_BERZERKBOX      Berzerk Box              Super strength
   PFX_INVISISPHERE    Invisibility Sphere      Temporary partial invis.
   PFX_RADSUIT         Radiation Suit           No nukage damage
   PFX_ALLMAP          Computer Map             All of automap revealed
   PFX_LIGHTAMP        Light Amp Visor          All lights at full level
   PFX_CLIP            Clip                     +10 Bullets
   PFX_CLIPBOX         Clip box                 +50 Bullets
   PFX_ROCKET          Rocket                   +1 Rocket
   PFX_ROCKETBOX       Box of Rockets           +10 Rockets
   PFX_CELL            Cells                    +20 Cells
   PFX_CELLPACK        Cell pack                +100 Cells
   PFX_SHELL           Shells                   +4 Shells
   PFX_SHELLBOX        Box of Shells            +20 Shells
   PFX_BACKPACK        Backpack                 Max ammo *= 2, +1 clip all ammo
   PFX_BFG             BFG                      BFG weapon, +2 clips cells
   PFX_CHAINGUN        Chaingun                 Chaingun weapon, +2 clips bull.
   PFX_CHAINSAW        Chainsaw                 Chainsaw weapon
   PFX_LAUNCHER        Rocket launcher          Rocket launcher weapon, +2 rock.
   PFX_PLASMA          Plasma Gun               Plasma gun weapon, +2 clips cells
   PFX_SHOTGUN         Shotgun                  Shotgun weapon, +2 clips shells
   PFX_SSG             Super Shotgun            SSG weapon, +2 clips shells
   PFX_HGREENKEY       Heretic Green key        ** Gives both DOOM red keys
   PFX_HBLUEKEY        Heretic Blue key         ** Gives both DOOM blue keys
   PFX_HYELLOWKEY      Heretic Yellow key       ** Gives both DOOM yellow keys
   PFX_HPOTION         Heretic Potion           +10% health
   PFX_SILVERSHIELD    Silver Shield            +100% Heretic armor (stronger)
   PFX_ENCHANTEDSHIELD Enchanted Shield         +200% Heretic armor (stronger)
   PFX_BAGOFHOLDING    Bag of Holding           No effect yet
   PFX_HMAP            Map Scroll               All of automap revealed
   PFX_TOTALINVIS      Total InvisiSphere       Temporary total invisibility
  -----------------------------------------------------------------------------
Full example:
# define a couple of sprite-based pickups
pickupitem FOO2 { effect = PFX_TOTALINVIS }
pickupitem FOO3 { effect = PFX_LAUNCHER }

# redefine an existing pickup effect (don't forget free-form syntax...)
pickupitem FOO3 
{ 
   effect = PFX_ENCHANTEDSHIELD;
}
Return to Table of Contents


Frames

Frames, also known as states, define the animation and logic sequences for thing types and player weapons.

Each frame must be given a unique mnemonic in its definition's header, and this is the name used to identify the frame elsewhere. Each field in the frame definition is optional. If a field is not provided, it takes on the default value indicated below the syntax information. Fields may also be provided in any order.

If a frame's mnemonic is not unique, the latest definition of a frame with that mnemonic replaces any earlier ones. As of EDF 1.1 (Eternity Engine v3.31 public beta 4), frame mnemonics are completely case-insensitive. This means that a frame defined with a mnemonic that differs from an existing one only by case of letters will overwrite the original frame.

Note that the order of frame definitions in EDF is not important. For purposes of DeHackEd and parameterized codepointers, the number used to access a frame is now defined in the frame itself. For the original frames, these happen to be the same as their order.

User frames that need to be accessible from DeHackEd or from parameterized codepointers can define a unique DeHackEd number, which for purposes of forward compatibility, should be greater than or equal to 10000, and less than 32768. Beginning with EDF 1.6, DeHackEd numbers will be automatically allocated to frames which are used in misc or args fields using the "frame:" prefix if they have a DeHackEd number of -1. The previous behavior in this case was to post a warning message and replace the frame with frame 0. This change makes it unnecessary in many cases to assign and keep track of DeHackEd numbers yourself.

Syntax:
# Remember that all fields are optional and can be in any order.

frame <unique mnemonic>
{
   sprite         = <sprite mnemonic>
   spriteframe    = <number> OR <character>
   fullbright     = <boolean>
   tics           = <number>
   action         = <bex codeptr name>
   nextframe      = <frame mnemonic> OR <nextframe specifier>
   misc1          = <special field>
   misc2          = <special field>
   particle_event = <event name>
   args           = { <special field>, ... }
   dehackednum    = <unique number>
   cmp            = <compressed frame definition>
}
Explanation of fields: Special Fields:

The special fields misc1 and misc2, as well as all five usable values of the args list, can take special values of the following type by using prefix:value syntax as shown: Restrictions and Caveats: Replacing Existing Frames:

To replace the values of an existing frame, simply define a new frame with the exact same mnemonic value (as stated above, all frames need a unique mnemonic, so duplicate mnemonics serve to indicate that an existing frame should be replaced). EDF 1.1 also adds delta structures, which allow fields of existing frames to be edited without replacing all values in those frames. Delta structures also cascade, and are thus useful for layering of different modifications. See the section Delta Structures for full information.

Full Example:
# define some new frames
frame BLAH1
{
   sprite = FOO1
   fullbright = true
   tics = 12
   nextframe = BLAH2
}

frame BLAH2
{
   sprite = FOO1
   tics = 12
   nextframe = BLAH1
}

# Overwrite an existing frame (since BLAH1 is already defined above...)
# Also remember that mnemonics are case-insensitive!
frame blah1
{
   sprite = FOO1
   fullbright = true
   tics = 12
   action = HticExplode
   args = { 1 }
   nextframe = S_NULL
}
Return to Table of Contents


Compressed Frame Definitions

Compressed frame definitions are a new feature in EDF 1.1 that allows a shorthand syntax for specifying the fields of a frame block.

A compressed frame definition resides inside a normal EDF frame definition, using the cmp keyword outlined in the syntax of the frame block. It accepts a single string value with an extended syntax, and the value of all other fields in the frame block except for the dehackednum can be set via this string. When the cmp field is present in a frame block, all other fields except misc1, misc2, args, and dehackednum are ignored.

Note that the cmp field is NOT accepted inside framedelta blocks.

As of Eternity Engine v3.31 Delta, the format of cmp fields has been relaxed to allow arbitrary whitespace, quoted values, and line continuation. Line continuation was discussed in the General Syntax section, but the new changes to the cmp field are discussed below. Note that all existing cmp strings are still accepted as valid; the new features simply allow for greater flexibility.

Syntax:
frame
{
   cmp = <compressed frame definition>
}
The compressed frame definition string has the following syntax:
"sprite|spriteframe|fullbright|tics|action|nextframe|particle_event|misc1|misc2|args1-5"
Fields MUST be provided in the order given, but any number of fields can be left off at the end of the definition, and those fields will receive their normal default values. To let an internal field default, you must use the special reserved value "*" for that field.

Each field is delimited by pipe or, as of EDF v1.4, comma characters, and field values may NOT contain pipe or comma characters, unless, starting with EDF v1.3, the entire field value is enclosed in single or escaped double quotation marks. Beginning with EDF v1.3, extraneous whitespace IS allowed between field delimiters and their values. Only whitespace which is enclosed within quotation marks will be interpreted as part of a field's value, so if BEX flags strings are to use pipes, commas, or spaces to separate flags, they must be enclosed with quotations. When using quoted values, the beginning and end quotation mark type must match (ie, if it starts with ', it must end with ', and if it starts with \", it must end with \").

The fullbright field has a special caveat within compressed frame definitions. Any value beginning with the letter T (small or capital) will be interpreted to mean "true", and any other value, including the default, will be interpreted to mean "false".

Otherwise, all fields can accept exactly the same types and ranges of values that they normally accept when specified separately within a frame block. This includes letters and numbers for the spriteframe field, special keywords for the nextframe field, and prefix:value syntax for misc1, misc2, and the five args fields.

Examples:
# this is a compressed frame definition which specifies ALL the values

frame FOOBAR1 { cmp = "AAAA|A|F|6|Look|@next|pevt_none|0|0|0|0|0|0|0" }

# this is an equivalent frame definition, using default specifiers and
# leaving off defaulting fields at the end of the definition. This frame
# and the above mean the EXACT same thing.

frame FOOBAR1 { cmp = "AAAA|*|*|6|Look|@next" }

# here is a complicated example using a parameterized codepointer

#                                                          Args start here
#                                                          |
#                                                          V
frame FOOBAR2 { cmp = "TROO|6|*|6|MissileAttack|@next|*|*|*|thing:DoomImpShot|*|*|20" }
Bad Frame Examples:

Some illegal compressed frame definitions would include the following. Don't make these mistakes:
# This is wrong, field values may NOT be empty -- use "*" to indicate a default.

frame BAD1 { cmp = "AAAA|||6|Look|@next" }

# This is wrong because BEX flag fields CANNOT use '|' or ',' inside compressed frames, unless
# they are surrounded by escaped quotation marks.

frame BAD3 { cmp = "AAAA|B|T|23|SomePointer|*|*|*|flags:SOLID|SHOOTABLE|COUNTKILL" }

# This is wrong because you cannot leave off fields at the beginning.

frame BAD4 { cmp = "Look|@next" }

# This is wrong because fields must be in the correct order.

frame BAD5 { cmp = "6|TROO|*|6|thing:DoomImp|@next|MissileAttack|*|20" }
Examples Using EDF 1.3 and Later Extended Syntax:

The following frames would have been invalid prior to EDF v1.3, but are now accepted due to the new relaxation of the cmp field format:
# Arbitrary whitespace is now allowed, and is ignored outside of quoted values:

frame NOWGOOD1 { cmp = "AAAA | * | * | 6 | Look | @next" }

# Values may now be quoted using single or escaped double quotation marks so 
# that they can contain normally ignored or reserved characters.
# This allows BEX flags strings to contain pipes, commas, and/or spaces:

frame NOWGOOD2 { cmp = "AAAA | * | * | 6 | Look | @next | * | 'flags:SHOOTABLE | SOLID | COUNTKILL'" }
frame NOWGOOD3 { cmp = "AAAA | * | * | 6 | Look | @prev | * | \"flags:SHOOTABLE | SOLID | COUNTKILL\"" }

# EDF line continuation may be used inside any quoted string, including cmp field values.
# This frame is completely equivalent to the first example above:

frame NOWGOOD4 
{ 
   cmp = "AAAA | *    | *    | \
          6    | Look | @next" 
}

# As of EDF v1.4, you can use commas instead of pipes as delimiters. This was added
# by user request because it makes some definitions more readable. When using commas, the
# entire cmp field must be quoted without exception, since commas cannot be used in 
# unquoted strings.

frame NOWGOOD5 { cmp = "AAAA, *, *, 6, Look, @next" }

Return to Table of Contents


Thing Types

Thing types define monsters, lamps, control points, items, etc -- anything that moves, occupies space, can display a sprite, or is useful for singling out locations.

Each thing type must be given a unique mnemonic in its definition's header, and this is the name used to identify the thing type elsewhere. Each field in the thing type definition is optional. If a field is not provided, it takes on the default value indicated below the syntax information. Fields may also be provided in any order.

If a thing type's mnemonic is not unique, the latest definition of a thing type with that mnemonic replaces any earlier ones. See the information below for more on this. As of EDF 1.1 (Eternity Engine v3.31 public beta 4), thing type mnemonics are completely case-insensitive. This means that a thing type defined with a mnemonic that differs from an existing one only by case of letters will overwrite the original type.

Note that the order of thing type definitions in EDF is not important. For purposes of DeHackEd, the number used to access a thing type is now defined in the type itself. For the original thing types, these happen to be the same as their order.

User thing types that need to be accessible from DeHackEd or by parameterized codepointers can define a unique DeHackEd number, which for purposes of forward compatibility, should be greater than or equal to 10000 and less than 32768. User types not needing access via DeHackEd or by parameterized codepointers can be given a DeHackEd number of -1. Beginning with EDF 1.6, if a thingtype with a DeHackEd number of -1 is used by name in a misc or args field using the "thing:" prefix, it will be automatically assigned a unique DeHackEd number by the game engine. The previous behavior was to post a warning message and replace the thing with the "Unknown" type. This largely removes the need for users to assign and keep track of DeHackEd numbers.

Syntax:
# Remember that all fields are optional and can be in any order.

thingtype <unique mnemonic>
{
   inherits        = <thing type mnemonic>
   doomednum       = <number>
   spawnstate      = <frame mnemonic>
   spawnhealth     = <number>
   seestate        = <frame mnemonic>
   seesound        = <sound mnemonic>
   reactiontime    = <number>
   attacksound     = <sound mnemonic>
   painstate       = <frame mnemonic>
   painchance      = <number>
   painsound       = <sound mnemonic>
   meleestate      = <frame mnemonic>
   missilestate    = <frame mnemonic>
   crashstate      = <frame mnemonic>
   deathstate      = <frame mnemonic>
   xdeathstate     = <frame mnemonic>
   deathsound      = <sound mnemonic>
   speed           = <number> OR <floating-point number>
   radius          = <floating-point number>
   height          = <floating-point number>
   correct_height  = <floating-point number>
   mass            = <number>
   damage          = <number>
   activesound     = <sound mnemonic>
   flags           = <flag list>
   flags2          = <flag list>
   flags3          = <flag list>
   cflags          = <flag list>
   addflags        = <flag list>
   remflags        = <flag list>
   raisestate      = <frame mnemonic>
   translucency    = <number> OR <percentage>
   bloodcolor      = <number>
   fastspeed       = <number> OR <floating-point number>
   nukespecial     = <BEX codepointer mnemonic>
   particlefx      = <particle effect flag list>
   droptype        = <thing type mnemonic>
   mod             = <MOD name> OR <number>
   obituary_normal = <string>
   obituary_melee  = <string>
   translation     = <number> OR <translation table lump name>
   dmgspecial      = <dmgspecial name>
   skinsprite      = <sprite mnemonic>
   dehackednum     = <unique number>
}
Explanation of fields: Restrictions and Caveats: Replacing Existing Thing Types:

To replace the values of an existing thing type, simply define a new thing type with the exact same mnemonic value (as stated above, all thing types need a unique mnemonic, so duplicate mnemonics serve to indicate that an existing thing type should be replaced).

EDF 1.1 also adds delta structures, which allow fields of existing things to be edited without replacing all values in those things. Delta structures also cascade, and are thus useful for layering of different modifications. See the section Delta Structures for full information.

Full Example:
# define a new thing type
thingtype ScarletPimpernel
{
  doomednum = 15000
  spawnstate = S_SCARPIMP1
  flags = SPECIAL|NOTDMATCH
  dehackednum = 10000
}

# overwrite an existing thing type (assume BaronOfHell is already defined normally...)
# everything is the same as the original except the fields I changed...
thingtype BaronOfHell
{
  doomednum = 3003
  spawnstate = S_BOSS_STND
  seestate = S_BOSS_RUN1
  seesound = brssit
  painstate = S_BOSS_PAIN
  painchance = 10                  # changed from 50 to 10
  painsound = dmpain
  meleestate = S_BOSS_ATK1
  missilestate = S_BOSS_ATK1
  deathstate = S_BOSS_DIE1
  deathsound = brsdth
  speed = 12                       # changed to from 8 to 12
  radius = 24.0000
  height = 64.0000
  mass = 1000
  activesound = dmact
  flags = SOLID|SHOOTABLE|COUNTKILL
  flags2 = E1M8BOSS|FOOTCLIP
  raisestate = S_BOSS_RAISE1
  obituary_normal = "was burned by a baron"
  obituary_melee  = "was ripped open by a baron"
  dehackednum = 16
}
Return to Table of Contents


Thing Type Inheritance

New to EDF 1.2, thing type inheritance allows you to derive new thing types from existing ones, so that there is no need to duplicate all the fields in the original type. To activate inheritance for a thing type, use the following syntax:
thingtype <unique mnemonic>
{
   inherits = <thing type mnemonic>
   <any other thingtype fields>
}
When the inherits field is set in a thing type, its parent type will be processed first if it has not already been processed. Then, all the fields from the parent type, except for dehackednum and doomednum, will be copied from the parent type to this type. Once the parent is copied, any other fields in this type will be treated as a thingdelta section, such that only fields explicitly provided will overwrite values from the parent thing type. Defaults will not be applied for unlisted fields, again with the exceptions of dehackednum and doomednum.

Thing delta sections are applied to thing types after initial processing is finished, and thus do not affect the inheritance process. If a thing delta section is applied to a parent type, it will not affect the child type. Thing deltas applied to child types apply after both inheritance and any values overridden in the child type.

Restrictions and Caveats: Inheritance Example:
/*
   As you can see here, thing type inheritance allows inheriting type 
   definitions to be minimized to only those fields which must differ. 
   In this example, the dehackednum of the new thing type will be -1, 
   since it is unspecified. The doomednum will be 20001, since it is 
   not inherited, but is specified in the child type. Remember that the 
   dehackednum and doomednum fields are NOT copied between thing types.
*/

thingtype MyNewBaron
{
   inherits     = BaronOfHell   # Inherit from the BaronOfHell
   doomednum    = 20001         # Set the doomednum to something meaningful
   translucency = 50%           # Make it 50% translucent
}
Return to Table of Contents


DOOM II Cast Call

The cast call structure allows you to edit and extend the DOOM II cast call used after beating the game in DOOM II. Editing existing thing types via EDF or DeHackEd can otherwise cause this part of the game to malfunction, and it has never before been possible to add your own monsters into the fray. Now this can be done.

Unlike most other EDF sections, castinfo sections will be kept in the order they are specified, unless the castorder array is defined. The castorder array feature allows you to explicitly specify a complete ordering for the castinfo sections which overrides the order of their definitions. See below for more information on castorder.

Beginning with EDF 1.1, all castinfo sections are required to have a unique mnemonic. Sections with duplicate mnemonics will overwrite, with the last one occuring during parsing taking precedence as the definition.

Syntax:
castinfo <mnemonic>
{
   type       = <thing type mnemonic>
   name       = <string>
   stopattack = <boolean>
   
   # see notes about this; there can be from zero to four sound blocks
   sound
   { 
      frame = <frame mnemonic>
      sfx   = <sound mnemonic>
   }
}
Explanation of Fields: Restrictions and Caveats: Full Example:
# My New Cast Call -- Only The Ultimate FooBar and the Player are worthy!
castinfo foobar
{
   type = FooBar
   name = "The Ultimate FooBar"
   
   sound { frame = S_FOOBAR_ATK1; sfx = firsht }
   sound { frame = S_FOOBAR_ATK3; sfx = firsht }
   sound { frame = S_FOOBAR_ATK5; sfx = firsht }
}

# Notice since DoomPlayer is now #2 and not #17, I still need to set his
# name, otherwise it would call him a former sergeant o_O
castinfo player
{
   type = DoomPlayer
   name = "Our Hero"
   stopattack = true
}
Using the castorder Array

When editing the cast call, it will probably be advantageous to specify the castorder array. Doing so will allow you to avoid the EDF 1.0 problem of being forced to redefine the entire cast call simply to add a new cast member in the middle. It also allows you to move around existing castinfo definitions without editing them, and to omit or repeat definitions.

Syntax:
castorder = { <mnemonic>, ... }
All mnemonics specified in the castorder list must be valid. If any do not exist, an error will occur.

As with other EDF lists, if the list is defined more than once, the latest definition encountered is the one used. Also, you may use addition lists to add entries to the end of the castorder list.

Full Example:
# I decided to switch the cast call order around
castorder = { player, foobar }

...

# Later on, perhaps in another file, I add a new castinfo. I can do this:
castinfo weirdo
{
   type = WeirdoGuy
   name = "The Weirdo Guy"
}

# This will add weirdo to the end of the existing castorder list.
# I could also just redefine the entire list, but there's no point in this case.
castorder += { weirdo }
Return to Table of Contents


DOOM II Boss Brain Types

The Boss Brain thing types list allows editing of the types of monsters which can be spawned by the DOOM II Boss Brain cube spitter object. This structure is a simple list of thing type mnemonics, which are kept in the order they are provided. You can redefine the list at will, just as with the spritenames list.

Starting with EDF 1.1, there is no longer an 11-type limitation on the boss spawner list. However, if you provide more than 11 thing types in this list, you must also define the new boss_spawner_probs list, which must be a list of numbers which when added together equal 256. These numbers serve as the probability values out of 256 for the corresponding thing types. If exactly 11 types are defined and the boss_spawner_probs list is not defined, the normal defaults will be used. If boss_spawner_probs is defined, it MUST be the exact same length as the boss_spawner_types list.

Starting with EDF 1.2, if a thing type in the boss_spawner_types list is invalid, the "Unknown" thing type will be substituted for it. The previous behavior was to cause an error.

Syntax:
# A list of thing types

boss_spawner_types =
{
   <thing type mnemonic>, ...
}

# A list of probabilities for the above thing types. If provided, this list
# must be the same length as the above, and if not provided, the above list
# must contain exactly 11 types. The numbers in this list must add up to 256.

boss_spawner_probs =
{
   <number>, ...  
}
Full Example:
# Changed DoomImp to FooBar, and Archvile to the ScarletPimpernel
# (so it can give you a powerup, but not very often, since Archvile is the
#  rarest type ;)
# In a TC you might want to change ALL the monster types...
# These will use the default probabilities listed below, unless a
# boss_spawner_probs list is also defined somewhere.

boss_spawner_types =
{
   FooBar, Demon, Spectre, PainElemental, Cacodemon, ScarletPimpernel,
   Revenant, Arachnotron, Mancubus, HellKnight, BaronOfHell
}
Example with More than 11 Thing Types:
boss_spawner_types =
{
   DoomImp, Demon, Spectre, PainElemental, Cacodemon, Archvile, Revenant,
   Arachnotron, Mancubus, HellKnight, BaronOfHell, FooBar, ScarletPimpernel
}

boss_spawner_probs =
{
   40, 40, 30, 10, 30, 2, 10, 20, 30, 22, 10, 10, 2
}
Normal Default Probabilities Used When 11 Types are Defined:
boss_spawner_probs =
{
# prob. / thing type normally in this position in the list
   50,  # DoomImp
   40,  # Demon
   30,  # Spectre
   10,  # PainElemental
   30,  # Cacodemon
    2,  # Archvile
   10,  # Revenant
   20,  # Arachnotron
   30,  # Mancubus
   24,  # HellKnight
   10   # BaronOfHell
}
Return to Table of Contents


Sounds

New to EDF 1.1, sound definitions allow editing of existing sounds, as well as the addition of new sounds which can be referred to by things and frames. Although Eternity already supports the implicit addition of new sounds whose lumps start with the DS prefix, those sounds are only available to MapInfo and scripting. Since EDF allows the assignment of DeHackEd numbers, it allows much greater flexibility for new sounds.

EDF also provides access to some sound structure fields which are not currently supported in DeHackEd.

Each sound must be given a unique mnemonic in its definition's header, and this is the name used to identify the sound elsewhere. Each field in the sound definition is optional. If a field is not provided, it takes on the default value indicated below the syntax information. Fields may also be provided in any order.

Syntax:
sound <mnemonic>
{
   lump          = <string>
   prefix        = <boolean>
   singularity   = <singularity class>
   priority      = <number>
   link          = <sound mnemonic>
   linkvol       = <number>
   linkpitch     = <number>
   skinindex     = <skin index type>
   clipping_dist = <number>
   close_dist    = <number>
   dehackednum   = <number>
}
Explanation of Fields: Restrictions and Caveats: Replacing Existing Sounds:

To replace the values of an existing EDF sound definition, simply define a new sound with the exact same mnemonic value (as stated above, all sounds need a unique mnemonic, so duplicate mnemonics serve to indicate that an existing sound should be replaced).

EDF 1.1 adds delta structures, which allow fields of existing sounds to be edited without replacing all values in those sounds. Delta structures also cascade, and are thus useful for layering of different modifications. See the section Delta Structures for full information.

Full Example:
# Define some new sounds
# This one is only accessible via scripting because it doesn't have a DeHackEd number.
sound MySound
{
   lump = foo  # this will play DSFOO, since prefix defaults to true
}

# This entry uses its mnemonic to double as the sound lump name.
sound dsblah
{
   prefix = false  # Without this, it would try to play DSDSBLAH, which is wrong
   dehackednum = 10000
}

# This entry also uses the mnemonic as the sound name, but with prefixing.
# Since prefix defaults to true, the sound lump played will be "DSEXPLOD".
sound explod
{
   priority = 128
   dehackednum = 10001
}

# This entry links to another sound.
sound BlahLink
{
   lump = dummy    # this won't even get used in this case
   prefix = false  # dsblah doesn't need a prefix, so we should echo that here
   link = dsblah   # we've linked this entry to the dsblah sound
   linkvol = 150   # use some suitable values for these (must experiment)
   linkpitch = 0
   dehackednum = 10002
}

# This entry overrides a previously defined sound.
sound explod
{
   priority = 96        # Maybe we like 96 better than 128...
   dehackednum = 10001  # We can reuse the same DeHackEd number, since it overwrites
}
Return to Table of Contents


TerrainTypes

As of EDF 1.5, the TerrainTypes system has been completely absorbed into EDF. This means it is now possible to completely customize not only what flats are associated with what terrain effects, but the effects themselves. There are three principle object types associated with the TerrainTypes system -- splashes, terrains, and floors. Each will be discussed in its own subsection below.

Return to Table of Contents


Splash Objects

Splash objects define the thingtypes, sounds, and other properties of a splash caused by an thing hitting a terrain. Not all terrains must have splashes, and each terrain can only refer to one splash object. A splash object itself defines properties for both a low mass and high mass splash, however. All fields in the splash block are optional, and as usual, order is irrelevant.

All splash blocks must have a unique mnemonic. Non-unique mnemonics will overwrite, meaning that the properties of the last splash block encountered with a given name will become the final properties of that splash object.

Syntax:
splash <unique mnemonic>
{
   smallclass = <thingtype mnemonic>
   smallclip  = <number>
   smallsound = <sound mnemonic>
   baseclass  = <thingtype mnemonic>
   chunkclass = <thingtype mnemonic>
   sound      = <sound mnemonic>
   
   chunkxvelshift = <number>
   chunkyvelshift = <number>
   chunkzvelshift = <number>
   chunkbasezvel  = <number>
}
Explanation of Fields: Restrictions and Caveats: Replacing Existing Splashes:

To replace the values of an existing EDF splash definition, simply define a new splash with the exact same mnemonic value (as stated above, all splashes need a unique mnemonic, so duplicate mnemonics serve to indicate that an existing splash should be replaced).

Full Example:
// The Water splash object as defined in terrain.edf demonstrates a 
// fully-defined splash object:

splash Water
{
   smallclass = EETerrainWaterBase
   smallclip  = 12
   smallsound = eedrip
   
   baseclass  = EETerrainWaterBase
   chunkclass = EETerrainWaterSplash
   sound      = gloop   
   
   chunkxvelshift = 8
   chunkyvelshift = 8
   chunkzvelshift = 8
   chunkbasezvel  = 2
}
Return to Table of Contents


Terrain Objects

Terrain objects define the full properties of a TerrainType which can be assigned directly to multiple flats. Terrains may optionally define what splash object they use, as well as values related to inflicting damage, whether or not the terrain is liquid, whether or not hitting the terrain causes enemies to awaken, and other important information. All fields in the splash block are optional, and as usual, order is irrelevant.

All terrain blocks must have a unique mnemonic. Non-unique mnemonics will overwrite, meaning that the properties of the last terrain block encountered with a given name will become the final properties of that terrain object.

Terrain deltas are also supported for editing the properties of existing terrain objects without duplicating all fields within them. See the Delta Structures section for full information.

Syntax:
terrain <unique mnemonic>
{
   splash         = <splash mnemonic>
   damageamount   = <number>
   damagetype     = <MOD name>
   damagetimemask = <number>
   footclip       = <number>
   liquid         = <boolean>
   splashalert    = <boolean>
   useptclcolors  = <boolean>
   ptclcolor1     = <palette index> OR <RGB triplet>
   ptclcolor2     = <palette index> OR <RGB triplet>
   minversion     = <number>
}
Explanation of Fields: Restrictions and Caveats: Replacing Existing Terrains:

To replace the values of an existing EDF terrain definition, simply define a new terrain with the exact same mnemonic value (as stated above, all terrains need a unique mnemonic, so duplicate mnemonics serve to indicate that an existing terrain should be replaced).

Full Example:
// The Water terrain object as defined in terrain.edf demonstrates a 
// typical terrain object:

terrain Water
{
   splash   = Water
   footclip = 10
   liquid   = true
   
   useptclcolors = true
   ptclcolor1    = "127 127 255"
   ptclcolor2    = "0 0 255"
   
   minversion = 329
}

// This terrain defines damage properties only to create an 
// instant-death floor type:

terrain SuperDeadly
{
   damageamount   = 10000  // inflict telefrag damage
   damagetype     = LAVA   // use LAVA MOD
   damagetimemask = 1      // inflict damage more or less constantly
}
Return to Table of Contents


Floor Objects

Floor objects associate a terrain with a flat graphic. All fields in the floor block are optional, and as usual, order is irrelevant. Floor objects are precisely equivalent to entries in the old, obsolete binary TERTYPES lump, and in fact, TERTYPES is still supported for legacy projects, and will be used to generate additional floor objects if it is found. See the TERTYPES Lump Processing section below for more information.

Multiple floor objects may associate the same flat with different terrains. The last such definition encountered will determine what terrain the flat uses.

Syntax:
floor
{
   flat    = <string>
   terrain = <terrain mnemonic>
}
Explanation of Fields: Full Example:
// A couple of the floor objects defined for DOOM in terrain.edf:
floor { flat = FWATER1; terrain = Water }
floor { flat = LAVA1;   terrain = Lava  }
Return to Table of Contents


TERTYPES Lump Processing

The old binary TERTYPES lump is now considered obsolete, and thus its format is not described here, nor is any way to generate one any longer available from Team Eternity. However, to support legacy projects, Eternity will translate the last TERTYPES lump loaded into EDF floor definitions dynamically, using the following assumptions: This results in behavior identical to that under the old static TerrainTypes system, if and only if the default terrain objects or objects with equivalent names and behaviors are available for use. TERTYPES lump processing is done after EDF floor objects are processed, and thus any TERTYPES-derived definitions may override EDF floor objects that affect the same flats.

Return to Table of Contents


Dynamic Menus

New to EDF 1.6, dynamic menus allow the Eternity Engine's menu system to be customized in various ways, including through the definition of the custom user menu and via overriding of specific menus within the native menu heirarchy.

Remember that all fields are optional and may be provided in any order. Note that the order of item sections within a menu is important, however.

Syntax:
menu <unique mnemonic>
{
   # one or more item sections can exist; the items appear on the menu in the
   # order they are defined within their parent menu section
   item
   {
      type  = <menu item type name>
      text  = <string>
      cmd   = <string>
      patch = <string>
      flags = <menu item flags string>
   }
   
   prevpage = <menu mnemonic>
   nextpage = <menu mnemonic>
   x        = <number>
   y        = <number>
   first    = <number>
   flags    = <menu flags string>
}
Explanation of Fields: Restrictions and Caveats: Replacing Existing Menus:

To replace the values of an existing EDF menu definition, simply define a new menu with the exact same mnemonic value (as stated above, all menus need a unique mnemonic, so duplicate mnemonics serve to indicate that an existing menu should be replaced).

Example:
/*

  Define the reserved _MN_Custom menu, which is automatically made available on
  the second page of Eternity's main options menu when it is defined.
  This is a great use for the new optional "user.edf" file. Note that by using
  the new "mn_dynamenu" command, it is possible to create your own inter-menu
  links and form a complete heirarchy of custom menus. See the console reference
  for full information.
  
*/ 
menu _MN_Custom
{
   item { type = title;  text = "my custom menu" }
   item { type = gap }
   item { type = info;   text = "\Hitems here" }
   item { type = runcmd; text = "get outta here!"; cmd = "mn_prevmenu" }
   
   first = 3
   flags = background
}
Overriding Native Menus:

Eternity allows specific native menus to be overridden by menus you define in EDF. Currently the following menus can be overridden: To override a specific menu, you set a global variable in either the root EDF or in an EMENUS lump to the mnemonic of the menu you have provided. A table of variables and the menus they replace follows:
   EDF Variable                   Menu Overridden
  -------------------------------------------------------
   mn_episode                     Episode selection menu
  -------------------------------------------------------
Example:
/*
   This could be placed at global scope anywhere within the root chain of EDF
   files/lumps or within an EMENUS lump along with the menu it names.
*/
mn_episode = MyEpisodeMenu
Return to Table of Contents


Delta Structures

New to EDF 1.1, delta structures are an easier and more flexible way to edit existing thing type, frame, sound, and terrain definitions.

Each delta structure for a thing type, frame, sound, or terrain specifies by mnemonic the section that it edits inside it. This allows for any number of delta structures to be defined. The structures are always applied in the order in which they are encountered during parsing, so that, like style sheets in HTML, delta structures cascade. This means you can load your own set of delta structures on top of an existing set in a modification.

Delta Structure Syntax:
# A delta structure for a frame has this syntax:
framedelta
{
   name = <frame mnemonic>
   <list of frame fields>
}

# A delta structure for a thing type has this syntax:
thingdelta
{
   name = <thingtype mnemonic>
   <list of thingtype fields>
}

# A delta structure for a sound has this syntax:
sounddelta
{
   name = <sound mnemonic>
   <list of sound fields>
}

# A delta structure for a terrain has this syntax:
terraindelta
{
   name = <terrain mnemonic>
   <list of terrain fields>
}
The name field is required, and must be set to a valid terrain, sound, frame, or thingtype mnemonic in order to specify the definition that the delta structure edits. Along with the name, the delta structure can specify any field that is valid in that type of definition (see exceptions below).

See the Frames, Thing Types, Sounds, and Terrain sections for full information on their fields and syntax.

Any field not specified in a delta structure will not be affected, and retains the value that it had before the delta structure was applied. A delta structure must specify values explicitly, even if the new values are the usual defaults for those fields. Note that the frame args list must be completely specified. It is not possible to override only some of the values in that list.

Fields not supported in delta structures: Frame Delta Example:
# Change the Zombieman attack frame to use the shotgun zombie attack
framedelta
{
   name = S_POSS_ATK2
   action = SPosAttack
}
Thing Delta Example:
# Change the Zombieman's drop type to MegaSphere, and his spawnhealth to 400
thingdelta
{
   name = Zombieman
   droptype = MegaSphere
   spawnhealth = 400
}


# Later on, maybe in a different file, we change the spawnhealth again
thingdelta
{
   name = Zombieman
   spawnhealth = 20
}

# At this point, the Zombieman drops MegaSpheres, but his spawnhealth is 20, not 400.
Sound Delta Example:
# This changes the sound explod we defined earlier
sounddelta
{
   name = explod
   priority = 200
   singularity = sg_getpow
}
Terrain Delta Example:
# Terrain deltas used by Heretic in terrain.edf to enable splash alerts:
terraindelta { name = Water;  splashalert = true }
terraindelta { name = Lava;   splashalert = true }
terraindelta { name = Sludge; splashalert = true }
Return to Table of Contents


Miscellaneous Settings

These optional settings allow customization of various game engine behaviors. When not provided, they take on the indicated default values. All of these options can only be specified in the topmost level of an EDF file. The last definition encountered is the one which will be used.

Return to Table of Contents