                "Hacking the DOOM.EXE file"

            by Matt Fell (matt.burnett@acebbs.com)
                       June 13, 1994
===========================================================================

  Many of the characteristics of the DOOM environment are determined by the
data in the DOOM.WAD file: the maps data, the picture data, the sounds, etc.
Almost all of this has been explained in the Unofficial DOOM Specs. But 
there is also a host of variables and possibilities in the DOOM.EXE file, 
and in this article I will explain all I know about it. I'll probably 
include a new chapter in the 1.4 specs, to contain this info. This is kind 
of a trial run...
  Many simple variables can be changed in the manner that the classic
"HOCKEY" wad does it - by using the HACK.EXE program to patch doom.exe
in the specified places. I once thought I would write a program that would
enable easy editing of the "thing table" described below, for such cool
effects as invisble Barons and floating imps. But I never did finish it.
I get distracted easily :-), also I just love letting others do all the
real work :-).
  I freely mix hex and decimal numbers below. Hopefully you can tell from
the context :-). All of this refers to the registered version 1.2 DOOM.EXE 
file. When 1.4 comes out, I'll need to change the numbers, obviously. Some 
of the data could be located by using search patterns, since much of it 
doesn't change from version to version. But using the actual numbers is 
probably better, although less flexible.
  By far, the most possibilities are in the thing table, but I included
just about the entireity of my notes, for completeness' sake. I'm compiling
a list of ideas of what can be done by patching the exe, please contribute
your thoughts! Example: reduce the damage done by the missles, for longer
deathmatch battles. Another example: the entries in the thing table for 
demons and spectres are IDENTICAL except for the bit that makes spectres 
"inviso". Suppose one replaces the numbers for the "grey tree" with the 
numbers from the "Baron"'s entry, and change the invisible bit. Then one 
would have ADDED another monster, an invisible Baron, without having "taken 
away" the original non-inviso Baron. Of course, one would no longer have 
grey trees :-). I would really like to be able to expand the size of the 
thing table, the frame table, and the sprite name list, but I have looked 
for the appropriate pointers in vain. If someone could figure this out...
  Also, please report any interesting results gained by experimenting,
any errors, etc. Thanks.

  The data begins at $6f414 (455700) and continues to the end of the file,
$8db27 (580391). Here's an overview of the sections:

start length what

6f414  3d30  TEXT STRINGS
73412  1a34  various unknowns, probably to do with I/O, sound, mouse, etc.
74bf8 10000  looks like hard-coded math tables, for speed?
84bf8   148  misc.
84d40    82  gamma correction messages
84dc2   280  "are you sure you want to quit" messages
85042   3a2  MENUS (new game, load game, etc.)
853e4   140  ?
85524   36c  configuration options and defaults, like in DEFAULT.CFG
85890   174  ?
85a04    60  ?
85a64    54  ?
85ab8    c4  ?
85b7c    20  max ammo at start, and ammo per thing
85b9c    c0  ammo type and frame #s for the weapons
85c5c   188  ANIMATED WALLS and FLOORS
85de4   258  SWITCH-WALLS
8603c    c0  ?
860fc    d4  ?
861d0   500  5 colormaps for use with the gamma correction setting 0-4
866e4    fc  ?
867e0    40  pointers to chatmacros, "Green:", etc.
86820    88  pointers to level names, used on Automap
868a8    d8  splat mark coordinates for end-level screen
86980   5a8  wimap patch animations for end-level screen
86f28   224  SONG NAMES list of pointers
8714c   8b8  SOUND TABLE
87a04   1a4  SPRITE NAMES list of pointers
87ba8  3800  FRAME TABLE
8b3a8    20  ?
8b3c8  2368  THING TABLE
8d730   3fd  ?

  For readable lists of the TEXT STRINGS, THING TABLE, FRAME TABLE,
SPRITE NAMES, and SOUND TABLE, see the accompanying (or appended below)
Qbasic programs DEHACK. Instead of distributing a few hundred k of text
files, I decided to use simple programs that you can run to get the same
lists and tables that I use. Why Qbasic? Because everyone who has dos has
it, and if you don't, you're smart enough to write little programs yourself.
  This is one of the things I need feedback on - should I include these
mini-programs in the chapter in the 1.4 specs? Or should I just have the
descriptions and offset numbers, as below?
  Unless noted differently, "integer" means a 4-byte integer.

6f414   
  START OF DATA. Several times I'll refer to pointers. All these pointers
are integers. Add the values of these pointers to $6f414 and you'll get the 
location of what's being pointed to.
  Note: there's also at least one other kind of pointer in here, with larger
values, that seem to point to a location in the code, NOT the data. I call
these "code-pointers" for now. I know it's a lame term.

6f414   
  TEXT STRINGS. They all start on 4-byte boundaries, i.e. at xxxx0/4/8/c. 
$00 ends the string. Then the next one starts at the next boundary, so a 4 
byte string is followed by $00, then 3 bytes of random junk, then the next 
string. The first string is 01 01 01, then "ULTRADIR", and so on. See 
DEHACK1.BAS for a program to extract a list of all the text strings, 
DEHACK1.TXT will be about 72k.

73140   
  I think this is the last string, "TZ"

73144   
  Misc. stuff I haven't investigated. Some of it has to do with sound card 
stuff and mice and joysticks, because at 7384c is "DMXGUS.INI" and at 74ba8 
are pointers which point to the strings "None", "PC_Speaker", "Adlib", etc.

74bf8
  64k of precisely ordered numbers, which leads me to believe they are
pre-calculated math tables, to speed up some floating point operations
used in the screen draw routine. Any other guesses?

84bfc
  3 pointers to the episode 1/2/3 end texts, "Once you beat...", "You've
done it...", and "The loathsome Spiderdemon is dead..."

84c24
  pointer to the string "doom.wad"

84c74
  pointer to the string "default.cfg"

84c78
  8 integers: 1, 25, 50, 24, 40, 640, 1280, 320

84c98
  2 code-pointers

84ccc
  29 integers, with values like 90 and 135 and 180. Angles?

84d40
  "Gamma correction OFF", 00s, "Gamma correction level 1", ... 4. Each
occupies $1a bytes.

84dc2
  8 text messages used to confirm quitting, each uses $50 bytes

85042
  MENUS. I know this controls to some extent which menu pictures are used
for which menu, but I haven't figured it all out yet.

853e4
  14 ints: 42, 22, 23, 24, 28, 29, 31, 40, zeros

8541c
  256 bytes, values from 00-ff, no two the same, "random" order.

85524
  The configuration options. Each is 5 integers: a pointer to a string,
like "mouse_sensitivity", a code-pointer, the default value for that
option, a 0 or 1 (1 for all the "key_" options), and a 0. It would be
pretty dense to do anything with this, I think.

85890
  About 117 integers, with a definite structure, but I can't figure it
out, and changing/experimenting seems to do nothing.

85a64
  21 sets of 4 bytes: 0, 0, 1, 0, 320, 168, "33", 0, 1, $(b2 26 26 2e),
$(ff 63 fd ff), a pointer that points to the $(b2...), 0, 1, "ema", 0, 0,
1, 0, 1, "xma". All these are unchanged from version 0.99 through 1.2,
except the pointer obviously.

85ab8
  Ints: 0, -1, -1, 0, 0, 0, 0, 4, 7, 10, 12, 14, 15, 15, 0, 0, 112, 96, 64,
176, then 16 that are members of this set {-65536, -47000, 0, 47000, 65536},
then 4, 5, 6, 7, 0, 1, 2, 3, 8, 3, 1, 5, 7

85b7c
  AMMO AMOUNTS. 8 integers: 200, 50, 300, 50, 10, 4, 20, 1. The first four
are the maximum initial capacity for ammo, shells, cells, and rockets. The
backpack doubles these amounts. The second four are how many ammo in a
clip, shells, rockets/rocket, and cells/cell item. Boxes have 5x as much.

859bc
  AMMO TABLE. 8 sets of 6 integers:

Punch     5  4  3  2  5  0      
Pistol    0 12 11 10 13 17
Shotgun   1 20 19 18 21 30
Chaingun  0 34 33 32 35 38
Laucher   3 42 41 40 43 46
Plasma    2 59 58 57 60 62
BFG       2 66 65 64 67 71
Chainsaw  5 53 52 50 54  0

  The first number of each set is the ammo type. Type 5 never runs out. The
next three numbers are 3 frame #s (see the FRAME TABLE below) for the pics
displayed when moving while holding that weapon. You know, the "bobbing
weapon" effect? Fifth is the first frame of the "shoot" sequence for that
weapon, and last is the first frame of the "firing" sequence. The "firing"
pics are the ones that are lit up, fire coming out, etc.

85c5c
  ANIMATED WALLS and FLOORS. Each is 26 bytes: an integer, a 8-byte string,
$00, a 8-byte string, $00, and a final int.

0 NUKAGE3  NUKAGE1  8
0 FWATER4  FWATER1  8
0 SWATER4  SWATER1  8
0 LAVA4    LAVA1    8
0 BLOOD4   BLOOD1   8
1 BLODGR4  BLODGR1  8
1 SLADRIP4 SLADRIP1 8
1 BLODRIP4 BLODRIP1 8
1 FIREWALL FIREWALA 8
1 GSTFONT3 GSTFONT1 8
1 FIRELAVA FIRELAV3 8
1 FIREBLU2 FIREBLU1 8
1 ROCKRED3 ROCKRED1 8

  Obviously the 0/1 means floor or wall. The first string is the name of
the animation cycle's LAST listed texture, the second string is the FIRST
listed texture. The cycle includes them and all entries between them in
whichever wad file is in effect (It doesn't have to be DOOM.WAD, a pwad
with new TEXTURE1 and 2 resources works quite nicely. I'm doing it myself,
for my levels). The final 08 doesn't seem to mean much.

85dc8
  A -1 then a bunch of zeros, maybe space for another animation cycle?

85de4
  SWITCH WALL NAMES. Each is 20 bytes: an 8-byte string, 00, another string,
00, and a 2-byte integer. There are 28 switches here, from (SW1BRCOM 
SW2BRCOM 1) to (SW1WOOD SW2WOOD 2). When a switch is pulled, the game
checks to see if the wall texture is on this list. If it is, it changes
the wall texture to the corresponding alternate texture. The 2-byte integer
1 or 2 tells it to look in either TEXTURE1 or TEXTURE2.

86028
  20 zeros, again, room for one more?

8603c
  48 integers: 3 0 2 1 3 0 2 0 3 1 2 0 0 0 0 0
               2 0 2 1 0 0 0 0 3 1 3 0 0 0 0 0
               2 0 3 1 2 1 3 1 2 1 3 0 0 0 0 0

860fc
  50 integers, all are either 50 or -50.

861d0
  5 sets of 256 bytes, each is a COLORMAP, for the gamma correction
settings OFF, 1, 2, 3, 4.

866d0
  5 integers: 1, 0, -1, 0, 0

866e4
  13 sets of 5 - 10 bytes, each set terminated by a $FF

8675e
  $74 $20

86760
  13 pointers to the stuff at 866e4. An integer '0' between each pointer.

867c8
  6 integers: -1, -1, 0, -1, 0, 1

867e0
  10 pointers to the 10 default chatmacros, then 4 pointers, to "Green:",
"Indigo:", "Brown:", "Red:"

86820
  AUTOMAP LEVEL NAMES. 27 pointers to the level names used on the automap.

8689c
  The ascii letters "gibr" - the keys for sending messages in multiplayer.

868a8
  SPLAT MARK COORDINATES. At what screen coordinates to place the WISPLAT
picture on the end-level screen, for th 27 levels. 54 integers, 27 pairs.
e1m1 x, e1m1 y, ..., e3m9 y.

86980, 86bb0, 86da8
  END-LEVEL MAP ANIMATIONS. Each is 14 integers. The first one is (0, 11,  
3, 224, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0). The first number is 0 for all the
ones on maps 0 and 2 (episodes 1 and 3), and it's 2 for map 1. The 11 is
always 11 except the last one of map 2 is 8. The 3 means 3 pictures are
involved in the animation, e.g WIA00100, WIA00101, and WIA00102. 224 and 104
are the x and y coordinates. The sixth number is not 0 for map 1 - it's
from 1 to 8. This controls the way the Tower of Mystery "appears". All the
other numbers are always 0.

86ef8
  Three integers, how many animations for WIMAP0, 1, 2 respectively.

86f04 
  Three pointers, to the starts of the animations for WIMAP0, 1, 2
respectively.

8714c
  SOUND TABLE. 61 and 1/2 sounds are listed here. Each is 9 integers: a
pointer to the string which is the sound's "name", then a 0 or 1, then
a value ranging from 32 to 128, then 0, -1, -1, 0, 0, 0. The names are
"pistol", "shotgn", ... "hoof", "metal", "chgun". Prefix DS or DP and you
get the entries in DOOM.WAD for the sound data. The "chgun" is the 1/2 -
there's no "DSCHGUN" in doom.wad, and the entry in this table is incomplete
anyway, lacking the all-important 0, -1, -1, 0, 0, 0 ending :-). There seem
to be a few glitches in the way the sounds were fit into the whole scheme,
this is just one of them. See DEHACK5.BAS for how to extract the whole
table and list of sound names

879ec
  pointer to start of SOUND TABLE.

879f0
  Integer = 150. 150 whats?

87a04
  SPRITE NAME LIST. 105 pointers to the strings "TROO", "SHTG", ...,
"SMRT". See DEHACK4.BAS to extract the whole list.

87ba8
  FRAME TABLE. 512 entries, each is 28 bytes:

longint     sprite number 0-104, lookup in sprite name list pointers
longint     sprite subnumber, 0 = "A", 1 = "B", in for example, SMRTA0.
longint     duration, how many timeslices until it looks for the next
            frame in the sequence. -1 means forever.
2-byte int  ?
2-byte int  ?
longint     next frame in sequence. 0 means no next frame, sequence done.
longint     always 0, has no effect
longint     always 0

  See DEHACK3.BAS to extract the whole table

8b3a8
  Two integers: 1, 0, then 6 code-pointers.

8b3c8
  THING TABLE. 103 entries, each is 88 bytes, or 21 integers. See
DEHACK2.BAS to extract the table. Here's a list of what the 21 ints do:
  
  1. Thing number. 3001 is an imp, 5 is a blue key, etc. Some of them are
     -1, e.g. the very first entry (players), the fireballs, ... 
  2. First frame number of the thing's frame sequence, for 'regular' items.
     For monsters, it's the first frame of the standing-in-place sequence.
  3. Toughness/hit points.
  4. 'moving' first frame #, monsters/player only
  5. 'see player' sound # for monsters, or 'first' sound for projectiles.
     Note the sounds are 1-61, not 0-60. 0 indicates no sound.
  6. Always 8, except for player. What does it do?
  7. 'attack' sound #, monsters only.
  8. 'injury' first frame #, monsters/player only.
  9. ???. monsters/player only.
  10. 'pain' sound #, monsters/player only.
  11. 'close attack' frame #, monsters/player.
  12. 'distance attack' frame #, monsters/player.
  13. 'death' frame # for monsters, 'explode' frame # for projectiles.
  14. 'explosive death' frame #, only PLAY, POSS, SPOS, TROO are this weak.
  15. 'death' sound # for monsters, 'explode' sound # for projectiles. 
  16. Speed of movement. Projectiles' speeds are * 65536 (or split this
      into two 2-byte integers.
  17. Horizontal size * 65536
  18. Height * 65536
  19. Point value? Not implemented.
  20. Missle damage. Also, SKUL has a 3 here, I presume it turns into a
      projectile when attacking.
  21. 'act' sound #, monsters.
  22. Attributes, controlled by bits. Bit set = condition true. bit0 =
      1/0, bit8 = 256/0, bit16 = 65536/0, ...

   bit0     a gettable thing
   bit1     an obstacle to players and monsters (but not projectiles)
   bit2     can be hurt (note barrels have this set)
   bit3     ? teleport destination is only one with it set
   bit4     'automatics' like PUFF, TFOG, BLUD, projectiles
   bit5-7   unused?
   bit8     hung from ceiling
   bit9     floating monsters and not-on-ground things
   bit10    projectiles and player
   bit11    ? player only
   bit12-13 unused?
   bit14    floating monsters
   bit15    unused?
   bit16    projectiles
   bit17    unused?
   bit18    'Inviso' like Spectres!
   bit19    ? barrel only
   bit20-21 unused?
   bit22    Monster: counts towards KILL % at end-of-level screen
   bit23    Artifact: counts towards ITEM %
   bit24    unused?
   bit25    the 6 keys and the player
   bit26-31 unused?

8d730
  Misc junk I can't figure out.

8db27
  End of doom.exe
