Hexen/Modding Tips

From ModdingWiki
Jump to navigation Jump to search

Map Design

Notes here are supplemental/errata to the Official Hexen Specs; consult that for additional information.

Sector Specials

Light sequences

Automatic light sequences flow towards the sector tagged with special 2, passing through alternating sectors of type 3 and 4. Beware that attempting to implement forked paths with the automatic specials won’t work in vanilla Hexen, and if the pattern assignment breaks then the game will crash when a player touches one of the unassigned sectors. If you need a light sequence that branches or is otherwise more complex, you’ll have to use the Light_Phased special or an ACS script instead.


Polyobjects can take some time to fully understand. You may want to start out with a close study of how the Hexen IWAD levels set them up.

A polyobject is formed by creating solid walls (one-sided linedefs) inside a dummy sector which I’ll refer to as the polyobject cage. The properties of this sector don’t matter, only the properties of the linedefs that are to become your polyobject.

While it’s reasonable to allow for some space to grow the map, try to keep the polyobject cage somewhat close to the actual map sectors. The game might experience strange problems if it’s stuck too far out into the void.

Each polyobject is associated with an anchor and a start spot. These are numbered by a special case use of the thing angle property, rather than by the TID system.

The anchor points are placed in the polyobject cage area, often within the polyobject’s void space. The polyobject’s anchor point determines the point that will be placed on the polyobject start spot, and the point that the polyobject will rotate around when rotation specials are used.

The start spots are placed in the actual map space and determine where the polyobject will appear during play. To minimize the possibility of errors, every polyobject start location should be contained in its own rectangular sector, separate from others and encompassing the entirety of the space that the polyobject in question must move within. This is particularly important for pairs of doors. Polyobjects cannot share a subsector, and the map will not load in game if it finds that they do.

Polyobjects don’t have to be convex shapes, though it’s simpler if they are since you can then use Polyobj_StartLine (trigger type 1) and expect it to work without incident. The Polyobj_ExplicitLine (trigger type 5) special exists for the purpose of making non-convex polyobject constructions render correctly; you may have to use a little trial-and-error on the line ordering if you’re making a complex shape, but a general rule of thumb is that the lines on the inside of a concave shape should generally have a higher order number than the lines on the outside.

Polyobject movement

Rotation specials make a polyobject rotate around its anchor point. Rotate right means rotate clockwise, and rotate left means rotate counter-clockwise. Since map special arguments have a maximum value of 255, "byte angles" are used for the angle values. A byte angle of 0 will make the polyobject do a full 360-degree revolution. 64 will result in a 90-degree quarter-turn, 128 results in a half-turn. Finer values also work as expected based on this.

The door swing special is somewhat similar, but it rotates the polyobject counter-clockwise, pauses for the specified delay, then rotates the polyobject clockwise back to its starting position. The maximum valid angle for a swinging door is 128, to do a 180-degree turn. The door swing speed is treated as a signed value, so if you use a value higher than 127 it will actually go clockwise instead of moving any faster. This is a little tricky to arrange since you have to subtract your intended speed value from 256 and use the result for clockwise rotations. If your doors are paired, it’s easier to just move the one you want moving counter-clockwise normally, and let the other one mirror the movement. To do this, set the clockwise-moving door as a mirror of the counter-clockwise-moving door, and have all trigger lines that operate the doors set to activate the counter-clockwise-moving door.

For swinging doors, the polyobject’s anchors should be placed inside the polyobject approximately where hinges would be, near the side of the door adjacent to the wall. A centrally placed anchor will result in a door that rotates like a revolving door instead. When an anchor is placed outside the polyobject itself, the rotation specials will cause it to "orbit" its start spot.

Special Boss Setup

Some of the bosses require special settings to function properly.


There is just one gotcha when setting up a Heresiarch. Instead of the normal action special with arguments, special actions to be performed upon his death should instead be invoked by putting a script number where you would normally put the number of the action special, and leaving the arguments at zero. This script will be run when the Heresiarch is killed.

The technical reason for this exception to normal thing specials is because the Heresiarch’s internal AI code highjacks the argument slots for its own use.

Death Wyvern

The death wyvern is the most finicky boss to set up. If you do it improperly, you can end up with the wyvern being stuck in place and emitting a continuous, annoying scream, or even worse, the game could hang.

Death wyvern essentials:

  • The death wyvern itself. It requires a TID and can be given any action special you want.
  • A thing with an identical TID to the wyvern, requiring arguments containing the TID(s) at least one waypoint. It need not be a map spot (Hypostyle uses an ettin).
  • Map spots that serve as waypoints. Each should have a unique TID and arguments containing the TID(s) of at least one other waypoint.

A very basic setup would be:

  • Death Wyvern: TID = 1, Special/Arguments can be any reasonable action to execute upon wyvern’s death
  • Map Spot: TID = 1, Special = 0, Arg1 = 2, Arg2 = 3
  • Map Spot: TID = 2, Special = 0, Arg1 = 3
  • Map Spot: TID = 3, Special = 0, Arg1 = 2

With this setup, the wyvern will behave as follows: upon waking, fly to the map spot with TID 1 (since that one matches the Wyvern’s own). According to the args on this map spot, randomly choose between the map spot with TID 2 or the one with TID 3 and fly there. The wyvern will then continuously patrol back and forth between map spot 2 and map spot 3 until slain.

The wyvern swoops around in arcs when changing direction but will try to head for the exact position of its target map spot, taking into account its Z height setting as well, you can control its general altitude along the path. Another interesting thing to note: you can make a waypoint map spot reference its own TID as one of the arguments. When following this destination, the wyvern will circle around and back to that spot (may only work for spots that reference solely themselves, not 100% sure).

In addition to thing setup, the death wyvern requires some careful testing and preparation of its area to ensure that it will not get stuck, as it has no awareness of walls in its navigation. Make sure that the path between any two linked waypoints is clear with enough space to spare to account for the swooping movements.

NB: The official specs, and by extension map editing utilities based on them, may erroneously lead you to believe that the map spot destination numbers should be placed in the arguments of the wyvern itself. That is a mistake which will at best result in the arguments being ignored (if you gave the wyvern a TID and a first destination with matching TID) and at worst leave you with a stuck wyvern.


Korax expects there to be a few special scripts and map settings as well, but unlike the death wyvern he doesn’t necessarily break down totally without them. However, it is theoretically possible for missing Korax scripts to cause a crash under certain circumstances and Chocolate Hexen currently treats missing Korax scripts as a fatal error, although vanilla generally continues running despite this. Lack of the scripts will at best cause error messages to appear at the top of the screen and make things look sloppy to the player, so it behooves you to provide them (plus, it offers many opportunities to give the battle more "oomph", though if you really don’t want them you can always provide dummy scripts in those slots just to prevent the undesirable consequences of missing scripts).

The script numbers used are:

  • 249: Run when Korax is injured to below 50% HP.
  • 250: Randomly invoked battle script.
  • 251: Randomly invoked battle script.
  • 252: Randomly invoked battle script.
  • 253: Randomly invoked battle script.
  • 254: Randomly invoked battle script used only after Korax is below half health.
  • 255: Run when Korax is slain.

As with ACS in general, the battle scripts can be used for a variety of effects; the Dark Crucible is set up for such things as setting off traps, calling minions, and altering the battle field. When Korax performs the "attack" where he raises his fist and sends a lightning bolt to the ceiling, a battle script will be invoked. Unfortunately, a well-equipped and skilled player allowed to get near to Korax can often kill him before he gets a chance to do much with these scripts.

Korax is also capable of teleporting himself. There are no adverse effects to not setting this up, but again, it can help add challenge and interest to the fight. Korax will only teleport once his health is below 50%. Once at this point, he can randomly choose from any map spots given a TID of 249 and teleport to one of them.

ACS Scripts

Be aware that vanilla Hexen is not compatible with ZDoom ACS. If you intend to make your mod work with non-ZDoom ports, make sure you compile your scripts to the original ACS format. This can be achieved by using the original ACC released by Raven, or using the separate "compile to Hexen bytecode" button if you’re compiling your scripts from SLADE.

Inserting dummy scripts

Vanilla Hexen maps cannot run without a proper BEHAVIOR lump (a 0-length entry named BEHAVIOR is not enough). If you really do not want to include scripts in your map, you need to run tests on it before scripts have been added, or you want to override a special script requirement (e.g. Korax scripts), a dummy script which performs no action but satisfies the requirement that a script exist may be written like this:

script 1 (void)

Displaying Strings

Strings to be displayed by Print or PrintBold in vanilla Hexen should be given in ALL CAPS (the Hexen font uses lowercase letters only, so the in-game message will appear in lowercase.) Strings that contain lowercase letters may be displayed as gibberish.


The following objects can be spawned by script and by the destruction of certain items. DEFS.ACS (included via COMMON.ACS) gives names to them for when you are spawning via script, but for appearing out of breakable objects you can only refer to them by number. The names are generally meant to be easy mnemonics for the object spawned, but some of them are a bit obscure.

Spawned objects in vanilla Hexen cannot be assigned TIDs. This is particularly significant for the "thrust spike" objects which can be spawned, but not subsequently activated/deactivated.

In scripts, these things can be created using the Thing_Spawn, Thing_SpawnNoFog, Thing_Projectile and Thing_ProjectileGravity functions. The number of a particular type of thing currently on the map can also be retrieved using the thingcount function.

You may also place any of these spawnable objects inside some types of breakable scenery. To have an item spawn out of a breakable object (pots, decorative armor), you should leave the breakable object's special at 0 but set its first argument to the spawn number of the item you want it to contain. Certain objects do not behave logically when spawned this way; for instance, projectiles (such as those listed here in the "trap" category), will hang inertly in place and cannot cause damage. Objects that have a significant angle property (e.g. monsters) will spawn facing east.

The pairs 66/97 and 67/99 (permanent small flames and permanent large flames) are redundant spawn numbers. 66 and 97 both spawn the same permanent small flame, while 67 and 99 both spawn the same permanent large flame. Use whichever one you prefer, but ideally pick one or the other and be consistent about it.

The pair of sapphire planets, and the pair of emerald planets, are not interchangeable despite looking identical, and there are actually separate sprite entries for each of them. Puzzle slots will demand a particular sapphire or emerald and won't accept the other one.

The phantom "mash" monsters are special versions of certain normal monsters that are translucent and do not leave corpses when killed. In the core levels, they appear only while fighting Korax, and are spawned by one of his battle scripts.

Using out-of-bounds spawn numbers is not recommended. It might spawn something, but is unlikely to be consistent across varying ports (even vanilla vs. chocolate). The defined numbers range from 0 to 108. Things that do not appear in this table cannot be spawned without port extensions; notably, the Firestorm and Arc of Death weapons and the Brown Chaos Serpent enemy do not have spawn numbers, and many monster projectiles cannot be fired from scripted traps.

Table of spawnable things

Thing DEFS name Number Category
Nothing T_NONE 0 Nothing
Centaur T_CENTAUR 1 Enemy
Slaughtaur T_CENTAURLEADER 2 Enemy
Green Chaos Serpent T_DEMON 3 Enemy
Ettin T_ETTIN 4 Enemy
Stalker T_WATERLURKER 6 Enemy
Reiver T_WRAITH 8 Enemy
Reiver (buried) T_WRAITHBURIED 9 Enemy
Lava ball projectile T_FIREBALL1 10 Trap
Blue mana T_MANA1 11 Item
Green mana T_MANA2 12 Item
Boots of Speed T_ITEMBOOTS 13 Item
Porkalator T_ITEMEGG 14 Item
Wings of Wrath T_ITEMFLIGHT 15 Item
Dark Servant T_ITEMSUMMON 16 Item
Banishment Device T_ITEMTPORTOTHER 17 Item
Chaos Device T_ITEMTELEPORT 18 Item
Dark Bishop T_BISHOP 19 Enemy
Wendigo T_ICEGOLEM 20 Enemy
Magic Bridge T_BRIDGE 21 Platform
Dragonskin Bracers T_DRAGONSKINBRACERS 22 Item
Quartz Flask T_ITEMHEALTHFLASK 24 Item
Krater of Might T_ITEMBOOSTMANA 26 Item
Timon's Axe T_FIGHTERAXE 27 Item
Hammer of Retribution T_FIGHTERHAMMER 28 Item
Segment of Quietus (1) T_FIGHTERSWORD1 29 Item
Segment of Quietus (2) T_FIGHTERSWORD2 30 Item
Segment of Quietus (3) T_FIGHTERSWORD3 31 Item
Serpent Staff T_CLERICSTAFF 32 Item
Segment of Wraithverge (1) T_CLERICHOLY1 33 Item
Segment of Wraithverge (2) T_CLERICHOLY2 34 Item
Segment of Wraithverge (3) T_CLERICHOLY3 35 Item
Frost Shards T_MAGESHARDS 36 Item
Segment of Bloodscourge (1) T_MAGESTAFF1 37 Item
Segment of Bloodscourge (2) T_MAGESTAFF2 38 Item
Segment of Bloodscourge (3) T_MAGESTAFF3 39 Item
Porkalator trap projectile T_MORPHBLAST 40 Trap
Grey rubble (larger) T_ROCK1 41 Effects
Grey rubble (medium) T_ROCK2 42 Effects
Grey rubble (smaller) T_ROCK3 43 Effects
Brown clod with green specks (1) T_DIRT1 44 Effects
Brown clod with green specks (2) T_DIRT2 45 Effects
Brown clod with green specks (3) T_DIRT3 46 Effects
Small grey pebble T_DIRT4 47 Effects
Green particle T_DIRT5 48 Effects
Brown particle T_DIRT6 49 Effects
Arrow trap projectile T_ARROW 50 Trap
Dart trap projectile T_DART 51 Trap
Dart trap projectile (poisoned) T_POISONDART 52 Trap
Spiked ball projectile T_RIPPERBALL 53 Trap
Blue glass shard T_STAINEDGLASS1 54 Effects
Yellow glass shard T_STAINEDGLASS2 55 Effects
Purple glass shard T_STAINEDGLASS3 56 Effects
Green glass shard T_STAINEDGLASS4 57 Effects
Gold glass shard T_STAINEDGLASS5 58 Effects
Small blue glass shard T_STAINEDGLASS6 59 Effects
Small yellow glass shard (1) T_STAINEDGLASS7 60 Effects
Small yellow glass shard (2) T_STAINEDGLASS8 61 Effects
Small purple glass shard T_STAINEDGLASS9 62 Effects
Small green glass shard T_STAINEDGLASS0 63 Effects
Serrated blade projectile T_BLADE 64 Trap
Frost shard projectile T_ICESHARD 65 Trap
Small flame on ground T_FLAME_SMALL 66 Effects
Large flame on ground T_FLAME_LARGE 67 Effects
Mesh Armor T_MESHARMOR 68 Item
Falcon Shield T_FALCONSHIELD 69 Item
Platinum Helm T_PLATINUMHELM 70 Item
Amulet of Warding T_AMULETOFWARDING 71 Item
Flechette T_ITEMFLECHETTE 72 Item
Torch (item) T_ITEMTORCH 73 Item
Disc of Repulsion T_ITEMREPULSION 74 Item
Combined Mana T_MANA3 75 Item
Yorick's Skull T_PUZZSKULL 76 Puzzle item
Heart of D'sparil T_PUZZGEMBIG 77 Puzzle item
Ruby Planet T_PUZZGEMRED 78 Puzzle item
Emerald Planet (1) T_PUZZGEMGREEN1 79 Puzzle item
Emerald Planet (2) T_PUZZGEMGREEN2 80 Puzzle item
Sapphire Planet (1) T_PUZZGEMBLUE1 81 Puzzle item
Sapphire Planet (2) T_PUZZGEMBLUE2 82 Puzzle item
Daemon Codex ("O" book) T_PUZZBOOK1 83 Puzzle item
Liber Oscura ("A" book) T_PUZZBOOK2 84 Puzzle item
Steel Key T_METALKEY 85 Key item
Cave Key T_SMALLMETALKEY 86 Key item
Axe Key T_AXEKEY 87 Key item
Fire Key T_FIREKEY 88 Key item
Emerald Key T_GREENKEY 89 Key item
Dungeon Key T_MACEKEY 90 Key item
Silver Key T_SILVERKEY 91 Key item
Rusted Key T_RUSTYKEY 92 Key item
Horn Key T_HORNKEY 93 Key item
Swamp Key T_SERPENTKEY 94 Key item
Drop of water T_WATERDRIP 95 Effects
Temporary small flame T_TEMPSMALLFLAME 96 Effects
Permanent small flame T_PERMSMALLFLAME 97 Effects
Temporary large flame T_TEMPLARGEFLAME 98 Effects
Permanent large flame T_PERMLARGEFLAME 99 Effects
Phantom Green Chaos Serpent T_DEMON_MASH 100 Enemy
Phantom Brown Chaos Serpent T_DEMON2_MASH 101 Enemy
Phantom Ettin T_ETTIN_MASH 102 Enemy
Phantom Centaur T_CENTAUR_MASH 103 Enemy
Giant spike (up) T_THRUSTSPIKEUP 104 Scenery
Giant spike (buried) T_THRUSTSPIKEDOWN 105 Scenery
Reiver skin drip T_FLESH_DRIP1 106 Effects
Reiver chainmail drip T_FLESH_DRIP2 107 Effects
Reiver spark drip T_SPARK_DRIP 108 Effects


There are two ways that Hexen can play background music: from MUS tracks in a WAD or from the Hexen CD. The majority of people (especially nowadays) probaby use the MUS soundtrack, but there are a few things that should be noted regarding the CD. Particularly, only about half of the MUS tracks have CD equivalents, and several of the CD tracks were taken by the storyline/intermission tracks (which are also used in a few levels when playing CD audio).

There are two different methods for assigning the two different types of music. CD tracks are assigned in the MAPINFO lump with a cdtrack # key for each map where # is the CD track number. MUS tracks are assigned in the SNDINFO lump with a $MAP # track key, where # is the map number and track is the name of the MUS lump to play.

For example, to play the Winnowing Hall music on MAP01 in the IWAD, MAPINFO includes:

   cdtrack 13

and SNDINFO includes:

   $MAP 1 Winnowr

If you wish to include a custom MUS track in a PWAD for vanilla Hexen, bear in mind that it must really be in MUS format; autoconversion of MIDI lumps was a feature added to the Doom engine after the Heretic/Hexen codebase was forked from it.

CD Tracks

Here are the CD tracks and their equivalent MUS name. Track 1 is the data track and should not be played as audio. There is an oddity in Deathkings, in that tracks are sometimes substituted even if the MUS track is available on the CD.

Table of Hexen CD track MUS equivalents

Track Number MUS name Deathkings Substitution
2 Jachr Matches
3 Blechr Matches
4 Hexen
5 Orb
6 Hall
7 Chess
8 Cryptr Matches
9 Falconr 18 (Chap_4r), 10 (Octor)
10 Octor 5 (Orb)
11 Rithmr 19 (Fantar)
12 Sixater 21 (Levelr)
13 Winnowr Matches
14 Swampr 16 (Bonesr)
15 Wutzitr 20 (Foojar)
16 Bonesr 8 (Cryptr)
17 Chap_1r 14 (Swampr)
18 Chap_4r
19 Fantar
20 Foojar 17 (Chap_1r)
21 Levelr
22 Simonr 6 (Hall)

CD Substitutions

The omitted tracks on the CD leave fifteen MUS tracks that do not have a CD track equivalent, so you may have to select a next-best track out of the ones available on the CD. Both the original campaign and Deathkings substitute CD tracks for these missing pieces in their MAPINFO, but Deathkings substitutes them differently from the main game. "Chartr" exists in the Hexen IWAD but goes unused in both campaigns.

Table of Hexen CD missing track substitutions

MUS name Beyond Heretic substitution Deathkings substitution
Borkr 17 (Chap_1r)
Chap_2r 6 (Hall)
Chap_3r 10 (Octor) 15 (Wutzitr)
Chippyr 22 (Simonr)
Crucibr 2 (Jachr) 15 (Wutzitr)
Deepr 20 (Foojar) 15 (Wutzitr)
Fortr 16 (Bonesr) 13 (Winnowr)
Fubasr 6 (Hall) 9 (Falconr)
Grover 5 (Orb) 7 (Chess)
Percr 21 (Levelr) 9 (Falconr)
Secretr 14 (Swampr)
Stalkr 9 (Falconr) 16 (Bonesr)
Voidr 19 (Fantar) 22 (Simonr)
Wobabyr 15 (Wutzitr) 9 (Falconr)