Eternity Engine EDF Reference v1.3 -- 08/08/04

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

Return to Table of Contents


General Syntax

Return to Table of Contents


Files


Why Not in Wads?

Eternity cannot currently load EDF from wad lumps, although actions have been taken to enable this in the near future.

In the meanwhile, Eternity offers several ways to make loading of EDF from files a gentler process. These are addressed in the "Specifying the Root EDF File" section below.

Return to Table of Contents


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

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.

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.

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.

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.31 public beta 4. 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.

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" file in its current working directory.

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 gamemode's 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


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" }
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, 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 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 frames not needing access via DeHackEd can be given a DeHackEd number of -1. This causes them to be inaccessible to DeHackEd.

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 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 characters, and field values may NOT contain pipe characters, unless, starting with EDF v1.3, the entire field value is enclosed in escaped quotation marks. Beginning with EDF v1.3, extraneous whitespace IS allowed between field delimiters and their values. Only whitespace which is enclosed within escaped quotation marks will be interpreted as part of a field's value, so if BEX flags strings are to use pipes or spaces to separate flags, they must be enclosed with escaped quotations (the \" sequence).

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 '|' 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 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 escaped quotation marks so that they can contain 
# normally ignored or reserved characters.
# This allows BEX flags strings to contain pipes and/or spaces:

frame NOWGOOD2 { cmp = "AAAA | * | * | 6 | Look | @next | * | \"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 NOWGOOD3 
{ 
   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 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 can be given a DeHackEd number of -1. This causes them to be inaccessible to DeHackEd and to parameterized codepointers.

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>
   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             = <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 of 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>
   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


Delta Structures

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

Each delta structure for a thing type, frame, or sound 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>
}
The name field is required, and must be set to a valid 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, and Sounds 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
}
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