Have you ever wanted to create some kind of insane mod for Vanilla Doom (and other classic Dooms) but wished that there was a better programmatic way to write weapon, ammo, sound, string, par time, and thing definitions with a DECORATE-like language? Introducing DECOHack, the thing that does exactly that!
DECOHack takes a file (or series of files) written in a DECORATE-ish language and turns it into a DEH/BEX file that can be loaded into your favorite source port, or patched into your favorite executable via DeHackEd! Supports all patch schemes up to ID24.
decohack code.dh --output dehacked.deh
Hate backpacks? Turn them into BFGs!
#include <doom19> #include <friendly> // copy BFG pickup into backpack thing MTF_BACKPACK : thing MTF_BFG { //keep ednum, though ednum 8 }
Make an Imp with a worse attack!
#include <doom19> #include <friendly> thing MTF_IMP free states thing MTF_IMP "Worse Imp" { health 200 speed 12 clear states States { Spawn: TROO AB 10 A_Look Loop See: TROO AABBCCDD 3 A_Chase Loop Melee: Missile: TROO EF 8 A_FaceTarget TROO G 6 A_BruisAttack Goto See Pain: TROO H 2 TROO H 2 A_Pain Goto See Death: TROO I 8 TROO J 8 A_Scream TROO K 6 TROO L 6 A_Fall TROO M -1 Stop XDeath: TROO N 5 TROO O 5 A_XScream TROO P 5 TROO Q 5 A_Fall TROO RST 5 TROO U -1 Stop Raise: TROO ML 8 TROO KJI 6 Goto See } }
The sky's the limit (within reason, as it is still limited to Doom engine quirks and limitations)!
If you're worried about how many states you have left (in total or action-pointer allocated), you can run DECOHack with the `--budget` switch. Full help available via the `--help-full` switch. You can do a lot! It's all documented, even the worst of Doom's hardcodings!
DECOHack v0.42.1 by Matt Tropiano (using DoomStruct v2.19.5)
Addtional feature support by Xaser Acheron.
With special thanks to Simon "fraggle" Howard (DEH9000)
and Dennis "exl" Meuwissen (WhackEd).
Usage: decohack [--help | -h | --version]
--dump-constants
--dump-resource [path]
[filename] [switches]
--help Prints help and exits.
-h
--help-full Prints full help (not just usage) and exits.
--version Prints version, and exits.
--changelog Prints the changelog, and exits.
--gui Starts the GUI version of this program.
--dump-constants Dumps the list of available defined constants
to STDOUT.
--dump-resource [path] Dumps an internal resource (starting with
"decohack/" ) to STDOUT.
--dump-pointers Dumps the list of Action Pointers and their
parameter types to STDOUT.
--dump-pointers-html Dumps the list of Action Pointers and their
parameter types to STDOUT in HTML form.
[filenames]:
<filename> ... The input filenames. One or more can be added,
parsed in the order specified.
-- Source input is from Standard In, not a file.
[switches]:
--output [file] Outputs the resultant patch to [file].
-o [file] If [file] is a WAD file, the output patch is added
or replaced in the WAD file as "DEHACKED".
--charset [name] Sets the input charset to [name]. The default
-c [name] charset is UTF-8 (system default).
--source-output [file] Outputs the combined source to a single file.
-s [file] If [file] is a WAD file, the source is added
or replaced in the WAD file as "DECOHACK".
--output-charset [name] Sets the output charset to [name]. The default
-oc [name] charset is ASCII, and there are not many reasons
to change.
--budget Prints the state budget after compilation.
-b
--dry-run Does no output - only attempts to compile and
return errors and/or warnings. Overrides all
output switches.
==============================================================================
============ DECOHack ============
==============================================================================
DECOHack is a utility that reads a DECORATE-like syntax and outputs a DEH or
BEX patch. You should probably read up on the ZDoom DECORATE format before
you proceed, as some pieces are similar, and some are not.
/!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
IMPORTANT: It is important to note that DECOHack is CASCADING.
A definition of any kind will alter or replace the original
definition, and anything unspecified in a definition will
remain UNCHANGED.
/!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
==============================================================================
===== Some Language Specs
==============================================================================
<BOOLEAN> : true
false
<IDENTIFIER> : Alphanumeric-plus-underscores token (starting with a letter).
<STRING> : Any single- or double-quoted set of characters, or a raw string
bounded in backticks.
<INTEGER> : Any positive integer, or hex integer (e.g. 0x01234abcd).
<NUMBER> : <INTEGER>
- <INTEGER>
<FIXED> : Any number with a decimal point in it (converted to a
fixed-point number).
<NUMERIC> : <FIXED>
<INTEGER>
- <FIXED>
- <NUMBER>
==============================================================================
===== Comments
==============================================================================
You can put unparsed comments throughout your code using "//" for single-line
comments, or "/* */" for multi-line comments, like so:
// This is a comment.
/*
This is a comment
on multiple lines.
*/
/* Multi-line comments are
pretty
free form */
You'll see them in a bunch of places in this documentation.
==============================================================================
===== Format (MUST BE SET FIRST!)
==============================================================================
To set the output format (and available features):
using ( doom19 | udoom19 | doomunity | boom |
mbf | extended | mbf21 | dsdhacked | id24 )
Examples:
using doom19
using boom
==============================================================================
===== Strings
==============================================================================
Reassigns a set of strings. Any strings replaced here can carry through to
sprite names and sound names!
Doom 1.9:
strings
{
<INTEGER> <STRING>
...
}
Boom and higher:
strings
{
<IDENTIFIER> <STRING>
...
}
The Identifier in the Boom definition is the string mnemonic from the Boom
DeHackEd specs.
==============================================================================
===== Ammo
==============================================================================
Changes an ammo entry. `ammo` plus an index, and an optional string for the
new name.
ammo <INTEGER> <STRING>
{
max <INTEGER>
pickup <INTEGER>
// ID24 Properties (ID24 feature set and later)
initialAmmo <INTEGER>
maxUpgradedAmmo <INTEGER>
boxAmmo <INTEGER>
backpackAmmo <INTEGER>
weaponAmmo <INTEGER>
droppedAmmo <INTEGER>
droppedBoxAmmo <INTEGER>
droppedBackpackAmmo <INTEGER>
droppedWeaponAmmo <INTEGER>
deathmatchWeaponAmmo <INTEGER>
skill1Multiplier <FIXED>
skill2Multiplier <FIXED>
skill3Multiplier <FIXED>
skill4Multiplier <FIXED>
skill5Multiplier <FIXED>
}
Examples:
ammo 0 "Splinters"
{
max 300
pickup 20
}
ammo 2
{
max 5000
pickup 100
}
------------------------------------------------------------------------------
Ammo Aliases
------------------------------------------------------------------------------
You can specify identifier aliases for ammo slots by using the following:
alias ammo Bullets 0
...so the next time you refer to it, you can write:
ammo Bullets
{
// ... code
}
The alias works in every place you can use an ammo reference:
weapon 4 : weapon Shotgun "Shotgun Copy"
{
ammotype Bullets
}
Ammo alias identifiers are case-insensitive. There are a few internal
"#includes" that will add these names by default.
------------------------------------------------------------------------------
Auto-Ammo
------------------------------------------------------------------------------
Ammo types can be freed and filled automatically like states. To free a single
ammo slot:
ammo free <INTEGER>
To free an explicit range (inclusive):
ammo free <INTEGER> to <INTEGER>
Examples:
ammo free 6
ammo free 6 to 10
In order to fill the next free Ammo, you need to define ammo types using the
"auto" keyword:
auto ammo <IDENTIFIER> [ <STRING> ]
{
// ... same ammo body like always ...
}
Note that you'll need to use an unused identifier (or alias) to represent the
new Ammo when you need to refer to its index later. The identifiers are
case-insensitive.
Examples:
auto ammo RifleRounds "Rifle Rounds"
{
// ... code ...
}
Any place that would ordinarily use an Ammo index can use an auto-ammo
identifier in place of the index.
Ammo types that are edited directly or auto-filled this way are not "free"
anymore, similar to how "free" states work (more on that later).
You can modify auto-filled ammo types later (remember, definitions cascade!) by
writing a normal Ammo definition body:
ammo RifleRounds
{
// ... code ...
}
/!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
IMPORTANT: DECOHack will not warn you about Ammo slots with a
special purpose being filled this way! Most of the time, auto-
ammo types are useful for ID24 and higher patch types. Be
VERY careful if you use this feature in Vanilla or Boom!
/!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
You can also influence the next "auto ammo" index/slot to be used via a
special clause:
set next auto ammo index <INTEGER>
...where <INTEGER> is a positive integer for setting the next seek index for
"auto" ammo types. This may not write to the exact slot for the next ammo
type, however - it will still seek to the next "free" slot from that provided
index!
==============================================================================
===== Sound
==============================================================================
Changes a sound entry. `sound` plus the sound name. The sound name must
match a sound string in the string table (should not start with DS or DP).
sound <STRING>
{
priority <INTEGER>
singular <BOOLEAN>
}
Examples:
sound "barexp"
{
priority 120
singular false
}
This pays attention to the string table's current state - the sound name must
be changed (if you want to change it) before it is referred to by name, here.
Note that you can't change sound names in Boom or higher.
==============================================================================
===== States
==============================================================================
Individual states can be manipulated and/or changed, but be careful -
individual state manipulation should only be reserved for very few kinds of
changes.
state <INTEGER>
{
[ <SpriteName> <Frame> <NUMBER> [Bright] <StateFlags> [<Offset>] [<ActionPointer>] ]
(
goto <INTEGER>
| goto <IDENTIFIER>
| goto weapon <INTEGER> <WeaponStateLabel>
| goto thing <INTEGER> <ThingStateLabel>
| wait
| stop
)
}
In this case, "stop" is an alias for "goto 0", and "wait" is an alias for
"goto <last defined state>". <SpriteName> must match a sprite name in the
string table at the time this is declared. <Frame> must be a single valid
character in a sprite frame. <NUMBER> is the duration in tics. [Bright] is an
optional keyword indicating that the state graphic is always painted
fullbright.
<StateFlags>, available in MBF21 or later, are additional flags placed on
individual states. State flags are only completely overwritten if at least one
is specified in the state declaration. The only state flags available in this
patch type are:
Fast This frame's duration is halved in Nightmare.
NotFast This frame's duration is NOT halved in Nightmare. This is
only useful for states that already had it, but just want
to clear flags by specifying at least one flag.
Action pointer mnemonics must start with "A_". Some action pointers,
especially in MBF and later formats, can be optionally parameterized up to two
parameters (or greater, if MBF21):
A_Die
A_Die()
A_Turn(90)
A_RandomJump(344, 128)
Parameter values can also resolve to values via thing or weapon label names,
sound indices, and references to thing or weapon state labels (like how goto
is used).
A_RandomJump(missile2, 255) // Available state label on same actor
A_RandomJump(thing 23 pain, 128) // Thing state label
A_RandomJump(weapon 5 fire2, 128) // Weapon state label
A_PlaySound("FRE001", 0) // Sound name
A_PlaySound(pistol, 0) // Sound name
Some parameter values can be set with fixed-point numbers, but not every
function requires them or understands them:
A_Mushroom(-45.0, 16.0)
Depending on the expected parameter type, DECOHack will automatically convert
those parameters to fixed-point. The following is equivalent to the above:
A_Mushroom(-45, 16)
Parameter values can also be a series of flags that get or'ed together. This
is useful for some functions that manipulate flags. A set of supported flags
can be combined via the PIPE operator (or pluses):
A_AddFlags(SOLID | DROPPED, 0)
A_AddFlags(SOLID + DROPPED, 0)
DECOHack calculates a single value from these expressions. The only checking
done is if those flags are valid for the patch level (i.e. MBF, EXTENDED, or
MBF21).
NOTE: Some flags may share names with valid labels. To force DECOHack to
interpret a parameter as a label, wrap it in quotes (it may be a good idea to
do this anyway, for readability).
A_RandomJump("missile", 64)
Also, similarly, to force DECOHack to interpret an expression as a flag
expression, prefix it with the "flags" keyword:
A_AddFlags(flags SOLID | DROPPED, 0)
Weapon states have a special characteristic that went unused for the most part
in Doom, but is still modifiable in DECOHack. You can set the offset of the
weapon graphic on the frame (but note that it will only apply it if the first
argument is nonzero).
Offset(1, 32)
ID24 patches add an additional field to states called "tranmap" that allows
you to add a translucency mapping (usually "TRANMAP") to TRANSLUCENT things:
Tranmap("TADDMAP")
Action pointers understand what is expected in each parameter - you can just
refer to thing aliases, labels, and sounds or what-have-you as-is and it
will attempt to figure it out:
A_Spawn(Demon, 0.0) // Thing alias
A_Scratch(10, punch) // Sound name
A_RandomJump(pain2, 128) // State label
A_HealChase(heal, slop) // State label, sound name
A_WeaponSound(shotg3, 1) // Sound name
A_WeaponProjectile(CacodemonBall, 0, 0, 0, 0) // Thing alias
/!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
IMPORTANT: Some MBF pointers use the miscellaneous offset fields
as function parameters, so attempting to use Offset on those
weapon states that use them will cause an error! You can still
use Offset with Doom/Ultimate Doom 1.9 and MBF21 pointers - those
do not use those fields at all.
/!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
You can also use a shorthand for doing multiple actions on "one" state by
putting a set of multiple code pointers in braces:
// a very mean mancubus
MANC H 10 Bright {
A_FatAttack1
A_FatAttack2
A_FatAttack3
}
Note that what is generated is NOT one state - states cannot have more than
one action pointer. Rather, the result is a bunch of states:
MANC H 0 Bright A_FatAttack1
MANC H 0 Bright A_FatAttack2
MANC H 10 Bright A_FatAttack3
The duration on every state is 0 except for the last one, which simulates
several actions on "one" state. This works for action pointers that also
have parameters. The following:
TNT1 A 0 A_SpawnObject(DoomImpBall, 0.0, 0.0, 0.0, 16.0, 4.0, 0.0, 0.0)
TNT1 A 0 A_SpawnObject(DoomImpBall, 0.0, 0.0, 0.0, 16.0, -4.0, 0.0, 0.0)
TNT1 A 0 A_SpawnObject(DoomImpBall, 0.0, 0.0, 0.0, 16.0, 0.0, 4.0, 0.0)
TNT1 A 4 A_SpawnObject(DoomImpBall, 0.0, 0.0, 0.0, 16.0, 0.0, -4.0, 0.0)
...could be collapsed to:
TNT1 A 4 {
A_SpawnObject(DoomImpBall, 0.0, 0.0, 0.0, 16.0, 4.0, 0.0, 0.0)
A_SpawnObject(DoomImpBall, 0.0, 0.0, 0.0, 16.0, -4.0, 0.0, 0.0)
A_SpawnObject(DoomImpBall, 0.0, 0.0, 0.0, 16.0, 0.0, 4.0, 0.0)
A_SpawnObject(DoomImpBall, 0.0, 0.0, 0.0, 16.0, 0.0, -4.0, 0.0)
}
You could even couple this with some #define preprocessor directives if you
end up doing the same thing for multiple things:
#define A_SuperFatAttack { A_FatAttack1 A_FatAttack2 A_FatAttack3 }
MANC H 10 Bright A_SuperFatAttack
...which the preprocessor will turn into:
MANC H 10 Bright { A_FatAttack1 A_FatAttack2 A_FatAttack3 }
...and compiles down to:
MANC H 0 Bright A_FatAttack1
MANC H 0 Bright A_FatAttack2
MANC H 10 Bright A_FatAttack3
Individual state manipulation can have partial changes to its properties
instead of using a full state definition line:
state <INTEGER>
{
spritename <SpriteName>
frame <Frame>
duration <NUMBER>
[Bright]
[NotBright]
[Fast] // MBF21 Only
[NotFast] // MBF21 Only
[<TranmapClause>] // ID24 Only
[<OffsetClause>]
pointer [ <ActionPointer> | null ]
nextstate <StateIndex>
}
More examples:
state 11
{
PISG A 1 A_Lower
wait
}
state 13
{
PISG A 4 Offset(1, 32)
goto 16
}
state 16
{
PISG C 4
goto 17
}
state 16
{
duration 1
}
state 17
{
PISF A 7 Bright A_Light1
goto 1
}
state 173
{
PLAY W -1
stop
}
state 575 // change just next state
{
goto 577
}
state 911
{
CAND A -1 Bright
stop
}
state 911
{
notbright
pointer null
}
For replacing states in bulk, you will have to "free" a bunch of states for
replacement.
state free <INTEGER>
To free an explicit range (inclusive):
state free <INTEGER> to <INTEGER>
To free from a starting state index, following next state indices until a
free or protected state is reached:
state free from <INTEGER>
Examples:
state free 100
state free 100 to 200
state free from 100
/!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
IMPORTANT: "Freeing" a state does NOT ALTER IT, it just flags
that state as "available" for the state-filling functions in
this utility.
/!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
Then, you can fill a sequence of states starting from a specific state, and
free states will be auto-filled by availability, connected together in
sequence. Be careful: it may fail with an error if you run out of available
states (especially action pointer states in Doom 1.9).
state fill <INTEGER>
{
<SpriteName> <Frames> <NUMBER> [Bright] [<ActionPointer>|<Offset>]
...
(
goto <INTEGER>
| goto <IDENTIFIER>
| goto weapon <INTEGER> <WeaponStateLabel>
| goto thing <INTEGER> <ThingStateLabel>
| wait
| stop
| loop
)
}
<Frames> in this situation can be many valid characters in a sprite frame.
Examples:
state fill 714
{
PAIN H 8 Bright
PAIN I 8 Bright A_Scream
PAIN JK 8 Bright
PAIN L 8 Bright A_PainDie
PAIN M 8 Bright
stop
}
Each state altered directly (via "state X") or filled in this manner are no
longer "free."
IMPORTANT: It is possible to re-free a state that was freed before and
subsequently filled in, so be careful! You can enable "state safety" in your
patches in order to detect this, though - just add the following clause to
your code:
set state free safety on
...and from that line on, every freed state will incur a check to see if it
has been freed before, and if so, it will throw an error the moment it
happens. To turn this behavior off from a particular point, add:
set state free safety off
For best results, you should add "set state safety on" to the beginning of
your code.
You can protect a state from being freed (or an inclusive range of them) by
writing the following:
state protect <INTEGER>
state protect <INTEGER> to <INTEGER>
You can also use a state clause in place of an integer for the first clause:
state protect thing 11 spawn
Be careful though - it will protect the state at that resolved index, not
anything regarding the label specifically.
It will not be flagged as "free" if in a range of free states, it won't be
treated as "free" in state filling functions, and attempting to alter the
state directly will throw an error. By default, state 0 and 1 are flagged as
protected. You can turn off the protection on states by doing the following:
state unprotect <INTEGER>
state unprotect <INTEGER> to <INTEGER>
/!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
IMPORTANT: DECOHack is intentionally not very smart about
figuring out user intent, especially around states with hardcoded
purpose, in order to keep patch crafting as flexible as possible.
For example, one such state, State 266 (S_VILE_HEAL1), is the
state that the action pointer "A_VileChase" can make an actor
jump to when it resurrects a dead monster, despite the fact
that it is not referenced ANYWHERE on a thing definition's
state pointers!
Please view "DeHackEd Hardcodings.txt" in the docs folder for
more info!
/!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
------------------------------------------------------------------------------
Auto-States (Global States)
------------------------------------------------------------------------------
Since states are "just another structure" in Doom, they can be declared in
batches and you can refer to them later via a global state label, separated
from both Things and Weapons:
auto state <IDENTIFIER> {
// ... state info goes here ...
}
For example:
auto state ImpDeath {
TROO I 8
TROO J 8 A_Scream
TROO K 6
TROO L 6 A_Fall
TROO M -1
Stop
}
You can then refer to this state chain anywhere that you use state labels,
such as in Things and Weapons, and even other global states.
auto state ImpDeath2 {
TROO K 6
TROO L 6 A_Fall
TROO M -1
Stop
}
auto state ImpDeath {
TROO I 8
TROO J 8 A_Scream
Goto ImpDeath2
}
Each state declared or filled in this manner are also no longer "free," if
states were freed to accommodate these new states.
You can also influence the next "auto state" index/slot to be used via a
special clause:
set next auto state index <INTEGER>
...where <INTEGER> is a positive integer for setting the next seek index for
"auto" states. This may not write to the exact slot for the next state,
however - it will still seek to the next "free" slot from that provided index!
==============================================================================
===== Weapon
==============================================================================
Weapons are a combination of state filling and attribute declaration. All
definitions are cumulative on the weapon slot (separate definitions can alter
the same slot in different ways).
Ready, Select, Deselect, Fire, and Flash state labels set the weapon state
indices. Other labels are used for arbitrary jump points. "LightDone" is a
built-in alias for state 1.
Unlike ZDoom DECORATE, the "Spawn" state is not used, as that is used by an
associated Thing for pickups.
weapon <INTEGER> [ : weapon <INTEGER> ] [ <STRING> ]
{
ammotype ( 0 | 1 | 2 | 3 | 5 )
//MBF21 fields
ammopershot <INTEGER>
flags mbf21 <INTEGER-EXPRESSION>
clear properties // If present, clear all properties.
clear flags // If present, clear all flags (both sets, if available)
// MBF21 Flags (MBF21 feature set only)
+ mbf21 <INTEGER> // set flag(s)
- mbf21 <INTEGER> // unset flag(s)
+ <MBF21WeaponFlagName> // set flag
- <MBF21WeaponFlagName> // unset flag
// ID24 Properties (ID24 feature set only)
slot <INTEGER>
slotPriority <INTEGER>
switchPriority <INTEGER>
initialOwned <BOOLEAN>
initialRaised <BOOLEAN>
carouselIcon <STRING>
allowSwitchWithOwnedWeapon <INTEGER or WeaponAlias>
noSwitchWithOwnedWeapon <INTEGER or WeaponAlias>
allowSwitchWithOwnedItem <INTEGER>
noSwitchWithOwnedItem <INTEGER>
// specific state assignment.
state <WeaponStateName> <INTEGER>
// specific state assignment using another thing's states.
state <WeaponStateName> thing <INTEGER or ThingAlias> <ThingStateLabel>
// specific state assignment using another weapon's states.
state <WeaponStateName> weapon <INTEGER or WeaponAlias> <WeaponStateLabel>
// if present, clear all state indices (not freed!).
clear states
// clears a specific label (not freed!).
clear state <WeaponStateLabel>
states
{
ready:
<StateInfo>
...
deselect:
<StateInfo>
...
select:
<StateInfo>
...
fire:
<StateInfo>
...
flash:
<StateInfo>
...
}
}
Example:
weapon 2 "Shotgun"
{
ammotype 1
clear states
states
{
ready:
SHTG A 1 A_WeaponReady
loop
deselect:
SHTG A 1 A_Lower
loop
select:
SHTG A 1 A_Raise
loop
fire:
SHTG A 3
SHTG A 7 A_FireShotgun
SHTG BC 5
SHTG D 4
SHTG CB 5
SHTG A 3
SHTG A 7 A_ReFire
goto ready
flash:
SHTF A 4 Bright A_Light1
SHTF B 3 Bright A_Light2
goto lightdone
}
}
/!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
IMPORTANT: Using "goto" or other "jump" actions to jump to
labels/state pointers that you have not set or re-declared
within a "states" block will jump to whatever state is already
declared for that label!
/!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
To flag all states as "free" that are connected to a weapon, type the
following:
weapon <INTEGER> free states
weapon <INTEGER> free <WeaponStateName>
And the same result will happen if you freed from each defined weapon frame
individually. Best used before redefining a weapon. NOTE: "Freeing" is NOT
the same as clearing the state definitions!
You can copy from another weapon slot by adding the [ : weapon <INTEGER> ]
clause:
weapon 3 : weapon 4 "New Weapon Name"
{
...
}
/!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
IMPORTANT: DECOHack does NOT have any concept of "inheritance"
as DECORATE does. The copy via the ":" is a straight-up
definition copy, and does not have a concept of "super" or
"parent" objects of any kind!
/!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
All weapon characteristics and state labels get copied.
You can also swap two weapon slots:
weapon 3 swap with 4
Multiple weapons can be edited as though each weapon were changed
individually via an "each" clause like so:
each weapon from <INTEGER> to <INTEGER>
{
// ... weapon properties ...
}
each weapon in ( <INTEGER or WeaponAlias> , ... )
{
// ... weapon properties ...
}
For example, you can make all of the weapons have infinite ammo:
each weapon from 0 to 8
{
ammotype 5
}
Or maybe just the pistol and chaingun:
each weapon in (1, 3)
{
ammotype 5
}
If states are filled across the set of weapons, any special frame indices
will set to the EXACT same value across all of the specified weapons (i.e.,
the same Select state, the same Fire state, etc.).
------------------------------------------------------------------------------
Weapon Aliases
------------------------------------------------------------------------------
You can specify identifier aliases for weapon slots by using the following:
alias weapon Shotgun 2
...so the next time you refer to it, you can write:
weapon Shotgun
{
// ... code
}
The alias works in every place you can use a weapon reference:
weapon Shotgun free states
weapon 4 : weapon Shotgun "Shotgun Copy"
{
// ... weapon body
}
Weapon alias identifiers are case-insensitive. There are a few internal
"#includes" that will add these common ZDoom weapon names by default.
------------------------------------------------------------------------------
Auto-Weapons
------------------------------------------------------------------------------
Weapons can be freed and filled automatically like states. To free a single
weapon slot:
weapon free <INTEGER>
To free an explicit range (inclusive):
weapon free <INTEGER> to <INTEGER>
Examples:
weapon free 8
weapon free 9 to 20
In order to fill the next free Weapon, you need to define Weapons using the
"auto" keyword:
auto weapon <IDENTIFIER> [ : weapon ( <INTEGER> | <IDENTIFIER> ) ] [ <STRING> ]
{
// ... same weapon body like always ...
}
Note that you'll need to use an unused identifier (or alias) to represent the
new Weapon when you need to refer to its index later. The identifiers are
case-insensitive.
Examples:
auto weapon NewShotgun "New Shotgun"
{
// ... code ...
}
auto weapon BetterShotgun : weapon NewShotgun "Better Shotgun"
{
// ... code ...
}
Any place that would ordinarily use a Weapon index can use an auto-weapon
identifier in place of the index.
Weapons that are edited directly or auto-filled this way are not "free"
anymore, similar to how "free" states work.
You can modify auto-filled Weapons later (remember, definitions cascade!) by
writing a normal Weapon definition body:
weapon BetterShotgun
{
// ... code ...
}
/!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
IMPORTANT: DECOHack will not warn you about Weapon slots with a
special purpose being filled this way! Most of the time, auto-
weapoons are useful for ID24 and higher patch types. Be
VERY careful if you use this feature in Vanilla or Boom!
/!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
You can also influence the next "auto weapon" index/slot to be used via a
special clause:
set next auto weapon index <INTEGER>
...where <INTEGER> is a positive integer for setting the next seek index for
"auto" weapons. This may not write to the exact slot for the next weapon,
however - it will still seek to the next "free" slot from that provided index!
==============================================================================
===== Thing
==============================================================================
Things are a combination of state filling and attribute declaration. All
definitions are cumulative on the thing slot (separate definitions can alter
the same slot in different ways).
Spawn, See, Melee, Missile, Pain, Death, XDeath, and Raise state labels set
the thing state indices. Other labels are used for arbitrary jump points.
thing <INTEGER> [ : thing <INTEGER> ] [ <STRING> ]
{
clear properties // If present, clear all properties.
ednum <NUMBER>
health <NUMBER>
speed <NUMBER>
radius <INTEGER>
height <INTEGER>
damage <NUMBER>
reactiontime <INTEGER>
painchance <INTEGER>
mass <INTEGER>
flags <INTEGER-EXPRESSION>
flags mbf21 <INTEGER-EXPRESSION> // MBF21 Only
flags id24 <INTEGER-EXPRESSION> // ID24 Only
clear flags // If present, clear all flags (both sets, if available)
+ <INTEGER> // set flag(s)
- <INTEGER> // unset flag(s)
+ <ThingFlagName> // set flag
- <ThingFlagName> // unset flag
// MBF21 Flags (MBF21 feature set only)
+ mbf21 <INTEGER> // set flag(s)
- mbf21 <INTEGER> // unset flag(s)
+ <MBF21ThingFlagName> // set MBF21 flag
- <MBF21ThingFlagName> // unset MBF21 flag
// ID24 Flags (ID24 feature set only)
+ id24 <INTEGER> // set flag(s)
- id24 <INTEGER> // unset flag(s)
+ <ID24ThingFlagName> // set MBF21 flag
- <ID24ThingFlagName> // unset MBF21 flag
clear sounds // if present, clear all sounds.
seesound <STRING>
attacksound <STRING>
painsound <STRING>
deathsound <STRING>
activesound <STRING>
// Extended Properties (Extended/DEHEXTRA feature set and later)
dropitem <INTEGER or ThingAlias>
// MBF21 Properties (MBF21 feature set and later)
fastspeed <INTEGER>
meleerange <INTEGER>
infightinggroup <INTEGER>
projectilegroup <INTEGER>
splashgroup <INTEGER>
ripsound <STRING>
// ID24 Properties (ID24 feature set and later)
minRespawnTics <INTEGER>
respawnDice <INTEGER>
pickupAmmoType <INTEGER>
pickupAmmoCategory <INTEGER>
pickupWeaponType <INTEGER or WeaponAlias>
pickupItemType <INTEGER>
pickupBonusCount <INTEGER>
pickupMessage <STRING>
translation <STRING>
pickupSound <STRING>
// specific state assignment.
state <ThingStateName> <INTEGER>
// specific state assignment using another thing's states.
state <ThingStateName> thing <INTEGER or ThingAlias> <ThingStateLabel>
// specific state assignment using another weapon's states.
state <ThingStateName> weapon <INTEGER or WeaponAlias> <WeaponStateLabel>
// if present, clear all state indices (not freed!).
clear states
// clears a specific label (not freed!).
clear state <ThingStateLabel>
states
{
spawn:
<StateInfo>
...
see:
<StateInfo>
...
missile:
<StateInfo>
...
pain:
<StateInfo>
...
death:
<StateInfo>
...
xdeath:
<StateInfo>
...
raise:
<StateInfo>
...
}
}
Example:
thing 11 "Chaingun Sargeant"
{
EdNum 65
Health 70
Speed 8
Radius 20
Height 56
Damage 0
ReactionTime 8
PainChance 170
Mass 100
clear flags
+SOLID
+SHOOTABLE
+COUNTKILL
SeeSound "posit2"
AttackSound ""
PainSound "popain"
DeathSound "podth2"
ActiveSound "posact"
states
{
Spawn:
CPOS AB 10 A_Look
Loop
See:
CPOS AABBCCDD 3 A_Chase
Loop
Missile:
CPOS E 10 A_FaceTarget
ReFire:
CPOS FE 4 Bright A_CPosAttack
CPOS F 1 A_CPosRefire
Goto ReFire
Pain:
CPOS G 3
CPOS G 3 A_Pain
Goto See
Death:
CPOS H 5
CPOS I 5 A_Scream
CPOS J 5 A_Fall
CPOS KLM 5
CPOS N -1
Stop
XDeath:
CPOS O 5
CPOS P 5 A_XScream
CPOS Q 5 A_Fall
CPOS RS 5
CPOS T -1
Stop
Raise:
CPOS N 5
CPOS MLKJIH 5
Goto See
}
}
/!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
IMPORTANT: Using "goto" or other "jump" actions to jump to
labels/state pointers that you have not set or re-declared
within a "states" block will jump to whatever state is already
declared for that label!
/!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
To flag all states as "free" that are connected to a thing, type the
following:
thing <INTEGER> free states
thing <INTEGER> free <ThingStateName>
And the same result will happen if you freed from each defined thing frame
individually. Based on the current thing definition. Best used before
redefining a thing. NOTE: "Freeing" is NOT the same as clearing the state
definitions!
The following editor numbers cannot be used: 1, 2, 3, 4, or 11, as they have
a special purpose: Player Starts, plus Deathmatch.
You can copy from another thing slot by adding the [ : thing <INTEGER> ]
clause:
thing 3 : thing 4 "New Name"
{
...
}
All thing characteristics and state labels get copied.
/!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
IMPORTANT: DECOHack does NOT have any concept of "inheritance"
as DECORATE does. The copy via the ":" is a straight-up
definition copy, and does not have a concept of "super" or
"parent" objects of any kind!
/!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
You can also swap two thing slots:
thing 3 swap with 4
Multiple things can be edited as though each thing were changed individually
via an "each" clause like so:
each thing from <INTEGER> to <INTEGER>
{
// ... thing properties ...
}
each thing in ( <INTEGER or ThingAlias> , ... )
{
// ... thing properties ...
}
For example, you can make all of the hanging bodies non-solid:
each thing from 129 to 134
{
-SOLID
}
Or maybe make some slower projectiles really fast and damaging!
each thing in (7, 17, 32, 33, 37)
{
speed 25
damage 10
}
If states are filled across the set of things, any special frame indices
will set to the EXACT same value across all of the specified things (i.e.,
the same Spawn state, the same Missile state, etc.).
------------------------------------------------------------------------------
Thing Aliases
------------------------------------------------------------------------------
You can specify identifier aliases for thing slots by using the following:
alias thing DoomImp 12
...so the next time you refer to it, you can write:
thing DoomImp
{
// ... code
}
The alias works in every place you can use a thing reference or slot:
thing DoomImp free states
A_Jump(thing DoomImp death)
thing 200 : thing DoomImp "Imp Copy"
{
// ... thing body
}
Thing alias identifiers are case-insensitive. There are a few internal
"#includes" that will add these common ZDoom thing names by default.
------------------------------------------------------------------------------
Auto-Things
------------------------------------------------------------------------------
Things can be freed and filled automatically like states. To free a single
thing slot:
thing free <INTEGER>
To free an explicit range (inclusive):
thing free <INTEGER> to <INTEGER>
Examples:
thing free 151
thing free 151 to 250
In order to fill the next free Thing, you need to define Things using the
"auto" keyword:
auto thing <IDENTIFIER> [ : thing ( <INTEGER> | <IDENTIFIER> ) ] [ <STRING> ]
{
// ... same thing body like always ...
}
Note that you'll need to use an unused identifier (or alias) to represent the
new Thing when you need to refer to its index later. The identifiers are
case-insensitive.
Examples:
auto thing NewImp "New Imp"
{
// ... code ...
}
auto thing BetterImp : thing NewImp "Better Imp"
{
// ... code ...
}
...then in action pointer functions (and other places that use thing
references), you can refer to them later since they are now aliased:
A_SpawnThing(NewImp)
A_RandomJump(thing NewImp death, 128) // Label in a specific thing
Any place that would ordinarily use a Thing index can use an auto-thing
identifier in place of the index.
Things that are edited directly or auto-filled this way are not "free"
anymore, similar to how "free" states work.
You can modify auto-filled Things later (remember, definitions cascade!) by
writing a normal Thing definition body:
thing BetterImp
{
// ... code ...
}
/!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
IMPORTANT: DECOHack will not warn you about Thing slots with a
special purpose being filled this way! Most of the time, auto-
things are useful for EXTENDED and higher patch types. Be
VERY careful if you use this feature in Vanilla or Boom!
/!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
You can also influence the next "auto thing" index/slot to be used via a
special clause:
set next auto thing index <INTEGER>
...where <INTEGER> is a positive integer for setting the next seek index for
"auto" things. This may not write to the exact slot for the next thing,
however - it will still seek to the next "free" slot from that provided index!
------------------------------------------------------------------------------
Thing Editor Keys
------------------------------------------------------------------------------
https://zdoom.org/wiki/Editor_keys
DECOHack Things also support the Editor Keys that are read by map editors
like Ultimate Doom Builder or SLADE, except the supported keys are passed
along to the resultant DEHACKED file. The following keys are detected:
//$Angled
//$NotAngled
//$Category <String>
//$Group <String>
//$Color <Integer>
//$Colour <Integer>
//$Sprite <String>
//$EditorSprite <String>
------------------------------------------------------------------------------
Flag Mnemonics
------------------------------------------------------------------------------
Instead of integers, you can use the following mnemonics for object flags:
List of valid mnemonics and their values:
Things (Doom+):
SPECIAL = 0x00000001
SOLID = 0x00000002
SHOOTABLE = 0x00000004
NOSECTOR = 0x00000008
NOBLOCKMAP = 0x00000010
AMBUSH = 0x00000020
JUSTHIT = 0x00000040
JUSTATTACKED = 0x00000080
SPAWNCEILING = 0x00000100
NOGRAVITY = 0x00000200
DROPOFF = 0x00000400
PICKUP = 0x00000800
NOCLIP = 0x00001000
SLIDE = 0x00002000
FLOAT = 0x00004000
TELEPORT = 0x00008000
MISSILE = 0x00010000
DROPPED = 0x00020000
SHADOW = 0x00040000
NOBLOOD = 0x00080000
CORPSE = 0x00100000
INFLOAT = 0x00200000
COUNTKILL = 0x00400000
COUNTITEM = 0x00800000
SKULLFLY = 0x01000000
NOTDMATCH = 0x02000000
NOTDEATHMATCH = 0x02000000
TRANSLATION = 0x04000000
TRANSLATION1 = 0x04000000
UNUSED1 = 0x08000000
TRANSLATION2 = 0x08000000
TOUCHY = 0x10000000
UNUSED2 = 0x10000000
BOUNCES = 0x20000000
UNUSED3 = 0x20000000
FRIEND = 0x40000000
FRIENDLY = 0x40000000
UNUSED4 = 0x40000000
TRANSLUCENT = 0x80000000
Things (MBF21+):
LOGRAV = 0x00000001
SHORTMRANGE = 0x00000002
DMGIGNORED = 0x00000004
NORADIUSDMG = 0x00000008
FORCERADIUSDMG = 0x00000010
HIGHERMPROB = 0x00000020
RANGEHALF = 0x00000040
NOTHRESHOLD = 0x00000080
LONGMELEE = 0x00000100
BOSS = 0x00000200
MAP07BOSS1 = 0x00000400
MAP07BOSS2 = 0x00000800
E1M8BOSS = 0x00001000
E2M8BOSS = 0x00002000
E3M8BOSS = 0x00004000
E4M6BOSS = 0x00008000
E4M8BOSS = 0x00010000
RIP = 0x00020000
FULLVOLSOUNDS = 0x00040000
Things (ID24+):
NORESPAWN = 0x00000001
SPECIALSTAYSSINGLE = 0x00000002
SPECIALSTAYSCOOP = 0x00000004
SPECIALSTAYSDM = 0x00000008
Weapons (MBF21+):
NOTHRUST = 0x00000001
SILENT = 0x00000002
NOAUTOFIRE = 0x00000004
FLEEMELEE = 0x00000008
AUTOSWITCHFROM = 0x00000010
NOAUTOSWITCHTO = 0x00000020
Monsters tend to have 0x00400006 set (SOLID, SHOOTABLE, COUNTKILL).
Projectiles tend to have 0x00010610 set (MISSILE, NOGRAVITY, DROPOFF,
NOBLOCKMAP).
Example:
+SOLID
-NOGRAVITY
+RANGEHALF
==============================================================================
===== Custom Action Pointers
==============================================================================
There may be some patches that accept bespoke actions or action functions that
are not known to DECOHack, or actions that port authors include that may not
be "standard". For those, you can specify custom pointers for use on Thing
or Weapon states:
custom thing pointer <PatchType> A_PointerName ( <ParameterType> [ , <ParameterType> ...] )
custom weapon pointer <PatchType> A_PointerName ( <ParameterType> [ , <ParameterType> ...] )
Where <PatchType> is:
boom // no parameters, allow Offset
mbf // two parameters max, store in Misc fields, disallow Offset if at least one parameter
mbf21 // ten parameters max, store in Args fields, allow Offset
...which describes how many parameters the function can take and how it's
stored in the patch (misc fields, or args).
<ParameterType> is:
bool // 0 or 1
byte // -127 to 127
ubyte // 0 to 255
short // -32767 to 32767
ushort // 0 to 65535
int // -2147483648 to 2147483647
uint // 0 to 2147483647
angleint // -359 to 359
angleuint // 0 to 359
anglefixed // -359.99998 to 359.99998
fixed // -32768.99998 to 32767.99998
state // 0 to 2147483647, verify valid state index, reference, or label.
thing // 0 to 2147483647, verify valid thing index.
thingmissile // 0 to 2147483647, verify valid thing index, and thing is a MISSILE.
weapon // 0 to 2147483647, verify valid weapon index.
sound // valid sound name.
flags // -2147483648 to 2147483647, flag expression
For example, a popular non-standard pointer, MonsterRail:
custom thing pointer boom A_MonsterRail()
...and its counterpart, FireRailgun:
custom weapon pointer boom A_FireRailgun()
...the Mushroom pointer from MBF:
custom thing pointer mbf A_Mushroom(anglefixed, fixed)
...the WeaponMeleeAttack pointer from MBF21:
custom weapon pointer mbf21 A_WeaponMeleeAttack(ushort, uint, fixed, sound, fixed)
/!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
IMPORTANT: This is only supported for Boom and higher, since those
patch formats refer to action pointers by mnemonic - defining a
custom pointer as "A_PointerName" will write "PointerName" to the
correct place in the [CODEPTR] section of the patch. Name your
experimental pointers accordingly!
/!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
==============================================================================
===== Custom Properties
==============================================================================
There are some ports out there that accept additional DeHackEd properties. In
order to use those, you have to declare them ahead of time, like custom action
pointers.
custom <Object> property <Name> <DEHLabel> <ValueType>
...where <Object> is one of:
thing, weapon, misc, state, sound, ammo
...and <Name> is the property name.
...and <DEHLabel> is the DeHackEd entry name when the DEH patch gets written.
...and <ValueType> is one of:
bool // 0 or 1
byte // -127 to 127
ubyte // 0 to 255
short // -32767 to 32767
ushort // 0 to 65535
int // -2147483648 to 2147483647
uint // 0 to 2147483647
angleint // -359 to 359
angleuint // 0 to 359
anglefixed // -359.99998 to 359.99998
fixed // -32768.99998 to 32767.99998
state // 0 to 2147483647, verify valid state index, reference, or label.
thing // 0 to 2147483647, verify valid thing index.
thingmissile // 0 to 2147483647, verify valid thing index, and thing is a MISSILE.
weapon // 0 to 2147483647, verify valid weapon index.
sound // valid sound name.
flags // -2147483648 to 2147483647, flag expression
string // any string expression, written as-is.
For example, Doom Retro's "gib health" property for Things can be defined as:
custom thing property gibhealth "Gib health" int
==============================================================================
===== Par Times
==============================================================================
Only for certain patch formats (Boom-compatible), Par Times are declared this
way:
pars
{
<MapName> <INTEGER> // seconds
<MapName> <INTEGER>:<INTEGER> // minutes:seconds
}
Where <MapName> is a map lump (map or episode-map is derived from it), and
<INTEGER> is the par time in SECONDS (or <INTEGER>:<INTEGER> is
minutes:seconds).
Examples:
pars
{
e1m1 30
map20 150
map20 2:30
map45 200
}
Note that DECOHack is not prudent enough to check for "valid" minutes and
seconds. The formula, no matter what is entered, is always:
(minutes * 60) + seconds
...which means that a value of 81:75 is considered perfectly valid:
(81 * 60) + 75 = 4935 sec.
==============================================================================
===== Miscellany
==============================================================================
Miscellaneous data is in the miscellaneous block:
misc
{
monstersFightOwnSpecies <BOOLEAN>
initialBullets <INTEGER>
initialHealth <INTEGER>
greenArmorClass <INTEGER>
blueArmorClass <INTEGER>
soulsphereHealth <INTEGER>
maxSoulsphereHealth <INTEGER>
megasphereHealth <INTEGER>
godModeHealth <INTEGER>
idfaArmor <INTEGER>
idfaArmorClass <INTEGER>
idkfaArmor <INTEGER>
idkfaArmorClass <INTEGER>
bfgCellsPerShot <INTEGER>
maxHealth <INTEGER>
maxArmor <INTEGER>
}
==============================================================================
===== Forced Output
==============================================================================
So, there may be some ports out there that have bad defaults or other fields
on objects that do not get set properly. In order to output ALL of the fields
on an object (instead of just changes from the original, which is the default
behavior), you can add the following clause to an object body:
force output
...and then, the whole object definition will be output into the resulting
patch file. Only use this if you have no alternative recourse, since this will
bloat your output patch potentially.
This will work on ammo, misc, sound, thing, state, and weapon objects.
==============================================================================
===== SPECIAL: DSDHACKED Patch Behavior
==============================================================================
DSDHACKED patches introduce a way to extend sprite names and sounds. DECOHack
will extend these automatically whenever a new sprite is referred to in state
definitions or a new sound is referred to in parameters or in sound
definitions as though they already exist.
If any sprite name uses characters that are not available (or legal) in an
identifier, you need to wrap the name in quotes:
"TR-X" ABCD 5 A_Chase
"00BF" G 10 Bright
NOTE: These features are only enabled for patches that employ a DSDHACKED
(or better) feature set!
You can also affect what the next available sprite or sound index is with the
following clauses:
set next sound index <INTEGER>
set next sprite index <INTEGER>
...where <INTEGER> is a positive integer GREATER THAN OR EQUAL TO the current
sprite or sound index (for safety reasons). For example:
set next sound index 1000
set next sprite index 350
==============================================================================
===== Preprocessor
==============================================================================
DECOHack has a C-like preprocessor. The following directives influence how
a DECOHack file is parsed.
------------------
#include
------------------
The #include directive includes the contents of the specified file. The
filename is provided as a string parameter, and can either be a relative file
path from the file that contains the directive or an absolute path. Files can
be included more than once - use this with caution!
#include "scenery.dh"
#include "maps/mapnames.dh"
You can include some internal resource files by prefixing the file path with
"classpath:" and it will attempt to read that file from the Java classpath.
#include "classpath:decohack/constants/doom19.dh"
There are a few #include paths that are aliased in DECOHack for convenience:
<doom19> "classpath:decohack/doom19.dh"
<udoom19> "classpath:decohack/udoom19.dh"
<doomunity> "classpath:decohack/doomunity.dh"
<boom> "classpath:decohack/boom.dh"
<mbf> "classpath:decohack/mbf.dh"
<extended> "classpath:decohack/extended.dh"
<mbf21> "classpath:decohack/mbf21.dh"
<dsdhacked> "classpath:decohack/dsdhacked.dh"
<id24> "classpath:decohack/id24.dh"
<friendly> "classpath:decohack/constants/friendly_things.dh"
For example:
#include <mbf21>
...is exactly the same as:
#include "classpath:decohack/mbf21.dh"
------------------
#define
------------------
The #define directive defines a single-token macro that expands to a series of
other tokens. This is also useful for creating defines and testing if they
were defined later. They may also expand to zero tokens. All macro tokens are
CASE SENSITIVE!
NOTE: Unlike the C-language preprocessor, this does not create macro
functions.
#define GREETING_TEXT "Hello."
#define FILE_WAS_INCLUDED
#define lines can be multi-line, if each line is ended with a backslash:
#define CLEARED_THING { \
clear flags \
clear sounds \
clear states \
state spawn thing MTF_CANDLE spawn \
}
------------------
#undefine
------------------
The #undefine directive removes a previously defined macro. All subsequent
uses of that macro are treated as though they were never defined.
#define GREETING_TEXT "Hello."
#undefine GREETING_TEXT
------------------
#ifdef
------------------
The #ifdef directive includes the next series of lines if the following macro
was defined, until it reaches an #endif directive.
#define DOOM_STRINGS
#ifdef DOOM_STRINGS
#include "strings/doom.dh"
#endif
------------------
#ifndef
------------------
The #ifdef directive includes the next series of lines if the following macro
was NOT defined, until it reaches an #endif directive.
#define NO_PAR_TIMES
#ifndef NO_PAR_TIMES
pars
{
e1m1 0:40
}
#endif
------------------
#else
------------------
The #else directive ends the most recently started "if" directive block and
provides an alternate section if the first "if" is not processed.
#define TOUGH_PAR_TIMES
#ifdef TOUGH_PAR_TIMES
#include "maps/tough-partimes.dh"
#else
#include "maps/normal-partimes.dh"
#endif
------------------
#endif
------------------
The #endif directive ends the most recently started "if" or "else" directive
block.
==============================================================================
===== Built-in Resources
==============================================================================
#include <doom19>
#include "classpath:decohack/doom19.dh"
Adds ammo, state, weapon slot, thing slot, and string mnemonics for
Doom 1.9 EXEs, plus the "using doom19" line. Also adds ZDoom thing and
weapon aliases.
#include <udoom19>
#include "classpath:decohack/udoom19.dh"
Adds ammo, state, weapon slot, thing slot, and string mnemonics for
Ultimate Doom 1.9 EXEs, plus the "using udoom19" line. Also adds ZDoom
thing and weapon aliases.
#include <doomunity>
#include "classpath:decohack/doomunity.dh"
Adds ammo, state, weapon slot, thing slot, and string mnemonics for
Ultimate Doom 1.9 EXEs, plus the "using doomunity" line. Also adds ZDoom
thing and weapon aliases, and does not limit string lengths.
#include <boom>
#include "classpath:decohack/boom.dh"
Adds ammo, state, weapon slot, thing slot, and string mnemonics for
Boom-compatible ports, plus the "using boom" line. Also adds ZDoom
thing and weapon aliases.
#include <mbf>
#include "classpath:decohack/mbf.dh"
Adds ammo, state, weapon slot, thing slot, and string mnemonics for
MBF-compatible ports, plus the "using mbf" line. Also adds ZDoom thing
and weapon aliases.
#include <extended>
#include "classpath:decohack/extended.dh"
Adds ammo, state, weapon slot, thing slot, and string mnemonics for
Extended-DEH-compatible ports, plus the "using extended" line, AND
freeing up the extra extended states immediately for use, AND freeing
the things from 151 to 250 (the extended things) for auto-thing fill.
Also adds ZDoom thing and weapon aliases.
#include <mbf21>
#include "classpath:decohack/mbf21.dh"
Adds ammo, state, weapon slot, thing slot, and string mnemonics for
MBF21-compliant ports (which includes Extended-DEH), plus the
"using mbf21" line, AND freeing up the extra extended states
immediately for use, AND freeing the things from 151 to 250 (the
extended things) for auto-thing fill. Also adds ZDoom thing and
weapon aliases.
#include <dsdhacked>
#include "classpath:decohack/dsdhacked.dh"
Adds ammo, state, weapon slot, thing slot, and string mnemonics for
DSDHACKED-compliant ports (which includes MBF21), plus the
"using dsdhacked" line, AND freeing up the states from 1100 to the
state max, freeing the things from 151 to the thing max for
auto-thing fill, and allows new sound and sprite definitions
automatically. Also adds ZDoom thing and weapon aliases.
#include <id24>
#include "classpath:decohack/id24.dh"
Adds ammo, state, weapon slot, thing slot, and string mnemonics for
ID24-compliant ports (which includes DSDHACKED), plus the
"using id24" line, AND freeing up the states from 1100 to the
state max, freeing the things from 151 to the thing max for
auto-thing fill, freeing all weapons at index 9 and higher,
freeing all ammo types from index 6 and higher, and allows new sound and
sprite definitions automatically. Also adds ZDoom thing and weapon
aliases.
..............................................................................
#include <friendly>
#include "classpath:decohack/constants/friendly_things.dh"
"Friendly" names for Doom things, all the way up through ID24.
..............................................................................
#include "classpath:decohack/constants/doom19.dh"
All ammo, state, weapon slot, thing slot, and string mnemonics for Doom
1.9 EXEs.
#include "classpath:decohack/constants/doom19/ammo.dh"
All ammo slot mnemonics for Doom 1.9 EXEs.
#include "classpath:decohack/constants/doom19/states.dh"
All state mnemonics for Doom 1.9 EXEs.
#include "classpath:decohack/constants/doom19/things.dh"
All thing slot mnemonics for Doom 1.9 EXEs.
#include "classpath:decohack/constants/doom19/things_aliases.dh"
All thing aliases for Doom 1.9 EXEs.
#include "classpath:decohack/constants/doom19/weapons.dh"
All weapon slot mnemonics for Doom 1.9 EXEs.
#include "classpath:decohack/constants/doom19/weapons_aliases.dh"
All weapon aliases for Doom 1.9 EXEs.
#include "classpath:decohack/constants/doom19/strings.dh"
All string mnemonics for Doom 1.9 EXEs.
#include "classpath:decohack/constants/udoom19.dh"
All ammo, state, weapon slot, thing slot, and string mnemonics for
Ultimate Doom 1.9 EXEs (Doom 1.9 ammo, thing, weapon, and states are
reused).
#include "classpath:decohack/constants/udoom19/strings.dh"
All string mnemonics for Ultimate Doom 1.9 EXEs.
#include "classpath:decohack/constants/boom.dh"
All ammo, state, weapon slot, thing slot, and string mnemonics for
Boom-compatible ports.
#include "classpath:decohack/constants/boom/states.dh"
All state mnemonics for Boom-compatible EXEs.
#include "classpath:decohack/constants/boom/strings.dh"
All string mnemonics for Boom-compatible EXEs (meant to be a common
define for both Doom indices and Boom string keys).
#include "classpath:decohack/constants/boom/things.dh"
All thing mnemonics for Boom-compatible EXEs.
#include "classpath:decohack/constants/boom/things_aliases.dh"
All thing aliases for Boom-compatible EXEs.
#include "classpath:decohack/constants/mbf.dh"
All ammo, state, weapon slot, thing slot, and string mnemonics for
MBF-compatible ports.
#include "classpath:decohack/constants/mbf/states.dh"
All state mnemonics for MBF-compatible EXEs.
#include "classpath:decohack/constants/mbf/things.dh"
All thing mnemonics for MBF-compatible EXEs.
#include "classpath:decohack/constants/mbf/things_aliases.dh"
All thing aliases for MBF-compatible EXEs.
#include "classpath:decohack/constants/extended.dh"
All ammo, state, weapon slot, thing slot, and string mnemonics for
Extended-DEH-compatible ports.
#include "classpath:decohack/constants/extended/states.dh"
All state mnemonics for Extended-DEH-compatible EXEs.
#include "classpath:decohack/constants/extended/things.dh"
All thing mnemonics for Extended-DEH-compatible EXEs.
### Changed for 0.42.1 * `Fixed` New ID24 Weapons did not use `-1` as the default ammo type enumerant. * `Fixed` Weapons defined using `auto weapon` (or regular define) did not un-free the Weapon on define. * `Fixed` Ammo defined using `auto ammo` (or regular define) did not un-free the Ammo object on define. * `Added` Some sanity checks to Doom19 patch exports to ensure action pointers are added to the correct states. ### Changed for 0.42.0 * `Fixed` ID24 Weapons aliases were pointing to the wrong include. (Issue #141) ### Changed for 0.41.1 * `Fixed` Local, "future-defined" labels were not taking precedence over global labels in `states` blocks. (Issue #140) ### Changed for 0.41.0 * `Added` A "force output" clause on objects in order to force writing them to a patch, even if its fields are unchanged. ### Changed for 0.40.2 * `Fixed` A typo in the state protector/unprotector kept single states from being unprotected. (Issue #139) ### Changed for 0.40.1 * `Fixed` Copying an object didn't copy over its custom property values. * `Changed` Some better internal handling of properties for states. ### Changed for 0.40.0 * `Fixed` A potential warning was not output to `stderr`. * `Fixed` `AmmoPerShot` was not singled out as an MBF21 property on Weapons. * `Fixed` [GUI] Auto-complete does not pop-up automatically in strings. * `Added` "Auto-states," or Global State Labels (Enh. #34). * `Changed` Some better internal handling of object properties. ### Changed for 0.39.1 * `Fixed` The `--dump-constants` switch pointed to the wrong resource (Issue #131). ### Changed for 0.39.0 * `Added` Support for ID24 patches. * `Changed` DECOHack writes sprites and sound index sections in index order instead of name order. (Issue #130). ### Changed for 0.38.1 * `Fixed` DECOHack wrote to the wrong WAD file if output was an existing WAD file (Issue #126). ### Changed for 0.38.0 * `Changed` DECOHack now accepts any valid mnemonic for string entries in Boom patches or higher (alphanumeric plus underscore). ### Changed for 0.37.0 * `Fixed` Updated Preprocessor - some directives were not ignored on false code blocks when they should have been. * `Added` [GUI] Some keywords to the syntax highlighter. ### Changed for 0.36.0 * `Added` State re-use safety for freed states in patches, but only if opted-in by the `set state free safety on` clause. * `Added` `NOTDMATCH` as a Thing flag mnemonic. It was in the docs, but originally added as `NOTDEATHMATCH`. Oops. * `Changed` Things, Ammo, and Weapons with changed names will be included in the output DeHackEd patch. * `Changed` Things with editor keys only will be included in the output DeHackEd patch. ### Changed for 0.35.2 * `Added` Attempting to use `using` a second time will give the user a better error message. ### Changed for 0.35.1 * `Fixed` Setting a Thing's Pain state explicitly (not via States block) would set Pain Chance instead. (Issue #121). ### Changed for 0.35.0 * `Fixed` Soulsphere health misc value did not check the correct property range. * `Changed` Some Thing bit documentation for Doom19. * `Changed` Speed on MISSILE Things can now take an explicit fixed-point value (instead of a coerced one). * `Changed` Thing Health property can go up to a max integer value. * `Changed` Thing Damage property can go up to an integer value. * `Changed` Ammo max and pickup properties can go up to a max integer value. * `Changed` State duration property can go up to an integer value. ### Changed for 0.34.0 * `Fixed` Any clause that sets intervals (freeing things, protecting states) may create a condition that causes an endless loop. (Issue. #119) * `Fixed` Sound entries were off by 1 due to a misunderstanding of what index sound entries started at. (Issue #120) ### Changed for 0.33.0 * `Added` `set next` clauses for manipulating the next sprite or sound index used in DSDHACKED patches. (Enh. #116) * `Added` `set next` clause for manipulating the next thing index used in `auto thing`. ### Changed for 0.32.2 * `Fixed` CLEAR STATES in an Each Thing clause did not clear states. (Issue #115) * `Fixed` CLEAR STATES in an Each Weapon clause did not clear states. ### Changed for 0.32.1 * `Fixed` Mass on Things can be negative, for real this time. (Issue #114) ### Changed for 0.32.0 * `Fixed` [GUI] Some autocomplete docs fixes/changes. * `Added` Added more valid string mnemonics to Boom patches (notably, Woof/ZDoom obituaries). ### Changed for 0.31.2 * `Added` `TRANSLATION1` as a valid bit flag for Things. ### Changed for 0.31.1 * `Fixed` The Soulsphere, Megasphere, Blur Sphere, and Invulnerability didn't have their `TRANSLUCENT` flag set. (Issue #112) ### Changed for 0.31.0 * `Fixed` [GUI] Editor would error out on workspace load with no files open. * `Added` A warning for when a user makes a Thing that is `SHOOTABLE` with 0 mass. (Enhancement #103) * `Changed` Slightly improved some error messages. ### Changed for 0.30.4 * `Fixed` `Fast` and other MBF21 flags were not being respected in state bodies. (Issue #95) ### Changed for 0.30.3 * `Fixed` If DroppedItem was the only change to a Thing, it would not be saved in the patch. (Issue #91) ### Changed for 0.30.2 * `Fixed` Mass on Things can be negative. (Issue #90) ### Changed for 0.30.1 * `Fixed` Macros for `STR_PD_YELLOWK` and `STR_PD_REDK` were swapped (in doom19 and udoom19), plus `MTF_SHOTGUNGUY_DEAD` was added. (Issue #85) ### Changed for 0.30.0 * `Fixed` MBF21 pointer `A_ConsumeAmmo` had an incorrect signature/documentation, despite it compiling properly. (Issue #84) ### Changed for 0.29.0 * `Added` `monstersFightOwnSpecies` miscellany field. (Enhancement #82) ### Changed for 0.28.0 * `Added` Documentation for all pointers in is HTML when dumped with `--dump-pointers-html`. ### Changed for 0.27.0 * `Added` The `state protect` and `state unprotect` clauses now accept state index clauses, not just numbers. (Enhancement #12) * `Added` Custom properties. (Enhancement #55, #54) ### Changed for 0.26.0 * `Fixed` Added some bit flags that were missing from the docs: UNUSEDX bits, FRIENDLY. * `Added` A directory tree for the GUI. * `Added` A warning on wrong int/fixed type use (Enhancement #78). * `Added` A warning on wrong Thing type use (MISSILE vs. not) (Enhancement #77). ### Changed for 0.25.0 * `Fixed` Changed the z-position parameter type for MBF's A_Spawn pointer to "fixed". * `Fixed` Changed the range parameter type for MBF21's A_MonsterMeleeAttack pointer to "fixed". * `Fixed` Some inconsistent error messages around flag setting/removal. * `Fixed` Thing `dropitem` didn't allow 0 as a viable value. * `Added` The DECOHack GUI, plus a switch to start it (`--gui`). * `Added` Documentation for all pointers when dumped with `--dump-pointers`. * `Added` A `--charset` switch for specifying the encoding of the input source files (if not system default). * `Added` The ability to write the patch and the source directly into a WAD. * `Changed` MBF's A_FireOldBFG pointer should have been a weapon pointer instead of a thing pointer. * `Changed` Added a better error message for bad action pointers. * `Changed` Added an error message if the user does "flag mixing" on the same expression (see Issue #76). ### Changed for 0.24.1 * `Fixed` MBF Action Pointers were not recognized. This has been fixed. * `Fixed` An error is now thrown if you are attempting to define a custom action pointer that already exists. ### Changed for 0.24.0 * `Added` The ability to read a DECOHack patch from STDIN. * `Added` The ability to add custom action pointers. (Enhancement #72) ### Changed for 0.23.0 * `Added` A patch format for the Unity port, `doomunity`, which is `udoom19` but with no string limits (thanks, Xaser!). (PR #65). * `Added` A way to dump all known action pointers to DECOHack to STDOUT via the `--dump-pointers` runtime switch. * `Fixed` MBF21's `A_SeekTracer` parameters needed to check for FIXED angles, not UINT. * `Fixed` Some Action Pointer parameter interpretation - if a field needs a fixed expression, integer values are coerced to fixed, and vice-versa. * `Changed` Stricter (but safer) checking for types in parameters, such as Fixed values, and auto-detecting sounds, things, and states. * `Changed` Better string length error messages (Issue/Enhancement #64). ### Changed for 0.22.0 * `Fixed` **MAJOR FIX** DECOHack was completely broken and would NPE out on any parse. Whoops. Fixed! ### Changed for 0.21.0 * `Added` STR_ `#defines` for BOOM's extended locked door strings were missing (thanks, Xaser!). (PR #61) * `Changed` A_RandomJump and A_WeaponJump should take a UINT, not BYTE for probability (thanks, Altazimuth!). (Issue #62) ### Changed for 0.20.1 * `Fixed` Extended sounds were off by 1. (Issue #60) ### Changed for 0.20.0 * `Added` Multiple input files can be added, parsed in the order provided. (Enhancement #57) * `Fixed` Bad tokens in action pointer blocks no longer hang the parser. (Issue #59) ### Changed for 0.19.2 * `Fixed` Changed maximum string lengths for Vanilla patches (doom19, udoom19). (Issue #56) ### Changed for 0.19.1 * `Fixed` Thing indices were not being parsed properly in action pointer parameters. ### Changed for 0.19.0 * `Fixed` `A_JumpIfHealthBelow` did not accept negative values for the health reference value. (Issue #53) * `Fixed` Actor label values were not backfilled properly if the action that used them needed applying to many frames on one line. * `Added` Auto-things and free-able things (all patches). (Enhancement #50) * `Added` Aliases for things and weapons via `alias thing` and `alias weapon` statements. * `Added` DSDHACKED patch support. (Enhancement #42) ### Changed for 0.18.1 * `Fixed` Editor keys were not being saved if a Thing body didn't have parse-able content right after body start. * `Changed` Copying a definition from the exact same one will not perform a copy, as there is nothing to do. ### Changed for 0.18.0 * `Added` Support for editor keys on Things like DECORATE. (Enhancement #47) ### Changed for 0.17.0 * `Added` Labels can now be used pre-declared in actor (thing/weapon) definitions. (Enhancement #35) * `Added` Some keywords/delimiters to force interpretation of some action pointer parameters. * `Added` The output source switch for outputting the combined source into one file. * `Fixed` Some "next state" clauses did not throw errors properly in state blocks. * `Changed` The budget output does not output the action pointer budget if the patch in Boom format or higher. ### Changed for 0.16.2 * `Fixed` The "Red Skull" pickup string should be `GOTREDSKULL`, with two Ls. * `Changed` An error is now thrown if a string name is invalid (Boom and higher). ### Changed for 0.16.1 * `Fixed` Things did not have TRANSLUCENT set. (Issue #41) * `Fixed` NPE on actorless state fill. ### Changed for 0.16.0 * `Changed` Label-Goto-Label syntax in state bodies now supported. (Issue #37) ### Changed for 0.15.0 * `Changed` Altering a state directly now removes its "free" status, if set. * `Changed` Thing speed now accepts negative values. ### Changed for 0.14.1 * `Fixed` Lexer bugfix. Fixes inconsistent identifier concatenation. (Issue #32) ### Changed for 0.14.0 * `Added` Each Thing/Weapon Characteristics Filling. (Enhancement #24) * `Added` Individual state property changes. * `Fixed` A_AddFlags, A_RemoveFlags, A_JumpIfFlagSet used the wrong parameter type. ### Changed for 0.13.0 * `Added` Multi-action pointer lines. (Enhancement #16) ### Changed for 0.12.0.1 * `Added` Missing docs for `ammopershot` weapon field. ### Changed for 0.12.0 **Major compiler change. Do not use numbers for your sound definitions and references!** * `Added` Pre-emptive weapon flag checking on non-MBF21 patches. * `Fixed` Weapon MBF21 flags were parsed incorrectly. * `Fixed` Ensure blank files are written when no changes are made. * `Changed` Sounds definitions now REQUIRE a name, not a number. * `Changed` Some internal sound index/position handling to align with Doom internals rather than DeHackEd's mishandling of sound definitions. ### Changed for 0.11.2 * `Fixed` Extended (and higher) sound slots were not accessible via definition. (Issue #29) * `Fixed` NPE if no state clauses between labels. (Issue #28) ### Changed for 0.11.1 * `Fixed` Flag detection priority. * `Fixed` Splashgroup Outputs as Projectilegroup (Issue #27) * `Fixed` Melee range not being written correctly (Issue #25) * `Fixed` State search looped indefinitely if starting index was 0 with no free states. (Issue #26) * `Fixed` Thing speed info being written on no change. * `Changed` An error message for valid states. ### Changed for 0.11.0 * `Added` Missing DEHEXTRA thing fields and MBF21 support. * `Added` Correct action pointer use detection on things and weapons. * `Added` A way to combine flags per function pointer parameter. * `Added` `#include` directive aliases for convenience. * `Fixed` Sound indices for function calls were off by 1. * `Fixed` Megasphere health misc entry was not parsed! Whoops! * `Fixed` Megasphere health not initialized, either! ### Changed for 0.10.1 * `Fixed` The background flat string indices in the constants files were incorrect. ### Changed for 0.10.0 * `Added` An index value clause for sound indices on parameters. ### Changed for 0.9.0 * `Changed` Handling of protected states - protected states are never treated as free, and cannot be altered directly. ### Changed for 0.8.0 * `Fixed` Parsing a single state body with just the next frame clause did nothing. (Issue #10) (thanks, Aurelius!) * `Fixed` Certain non-blank DEH Extended states were not accessible. * `Added` Ability to clear single states or labels on things and weapons. (Issue #11) * `Changed` `S_FREE_START` in `classpath:decohack/constants/extended/states.dh` is now 1100. ### Changed for 0.7.0 * `Fixed` Disallow MBF action pointers in non-MBF patches. * `Added` Support for using the "unused" state parameters as offsets (supported in Doom code). (Issue #9) ### Changed for 0.6.1 * `Fixed` Changed file export for compatibility with Java 8. ### Changed for 0.6.0 * `Added` Better state referencing. ### Changed for 0.5.0 * `Added` Support for DEHExtra sound definitions (thanks @XaserAcheron). * `Fixed` Better support for DEHExtra in general and code refactoring to accommodate. ### Changed for 0.4.1 * `Fixed` Changed "Friendly" things constants (`classpath:decohack/constants/friendly_things.dh`). * `Changed` Updated help. ### Changed for 0.4.0 * `Added` "Friendly" things constants (`classpath:decohack/constants/friendly_things.dh`). * `Added` Parser: Set weapon/thing states using other weapon/thing states. ### Changed for 0.3.0 * Initial Release.