"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