The unofficial LMP format description
Public Version 1.10 (internal revision 20) - 24.10.1994

Written by:Uwe Girlich (girlich@aix520.informatik.uni-leipzig.de )

>>>> THIS A IS VERY OLD VERSION. <<<<
The specs are now maintained at http://www.planetquake.com/demospecs/lmp/.

1. Introduction

A DOOM lmp file records all player actions. The monster movements, respawn positions etc. are totally deterministic. The messages during a multiplayer game (chat mode) do not appear in the lmp.

A lmp file consists of a header, a data area and a quit byte.

The duration of a gametic is round 1/35s. With time measurements with 4dos:

timer ^ doom -playdemo name ^ timer

of many differnet lmp's and linear curve fitting I found a slightly differnet frequency: 35.003Hz. So it is not wrong to speak of 35Hz but it is not totally correct.

2. HEADER

Many thanks to Steffen Winterfeldt (wfeldt@tph100.physik.uni-leipzig.de) for his reverse engineering work.

The easiest way to check the length of the header is to start DOOM with the record option. Then you have to press 'q' during the startup sequence. In the moment, when the screen switchs from text mode to graphics mode, the game stops and you receive the shortest lmp file. It consists only of the header and the quit game byte.

The lmp header format is a subject of change. Until DOOM 1.2 was the format of the 7 byte header:

Byte  Type Contents
0000h Byte skill   (0-4)
0001h Byte episode (1-3)
0002h Byte map     (1-9)
0003h Byte 0/1     (green player)  \  
0004h Byte 0/1     (indigo player)  \ 0: this player doesnt play 
0005h Byte 0/1     (brown player)   / 1: this player plays
0006h Byte 0/1     (red player)    /
The number of bytes (3-6) unequal to zero is the number of players.

From Version 1.4 on the header consists of 13 bytes:

Byte  Type Contents
0000h Byte version (104d=68h DOOM 1.4, 105d=69h DOOM 1.5, 106d=6Ah DOOM 1.6)
0001h Byte skill   (0-4)
0002h Byte episode (1-3)
0003h Byte map     (1-9)
0004h Byte multiplayer rule (0: Cooperative, 1: DeathMatch, 2: AltDeath)
0005h Byte respawn    0: off, !=0: on \  a value != 0 is the number of
0006h Byte fast       0: off, !=0: on  > this command line parameter
0007h Byte nomonsters 0: off, !=0: on /  (with expanded @paramfile)
0008h Byte the lmp is recorded from this player's view (0-3)
0009h Byte 0/1     (green player)  \  
000Ah Byte 0/1     (indigo player)  \ 0: this player doesnt play 
000Bh Byte 0/1     (brown player)   / 1: this player plays
000Ch Byte 0/1     (red player)    /
The number of bytes (9-C) unequal to zero is the number of players.

Now it is very easy to change a existing lmp from one format to the other. The movement algorithm didn't changed from DOOM 1.2 to DOOM 1.5 beta. This is only true if the map also didn't changed. So you can't recycle lmp's of e1m4. It is very interesting, that 1.5 lmp's, recorded even with the turbo option work with 1.2.

3. DATA

3.1 Number of game tics

This formula for the number of game tics (NGT) follows from the first section:

                filelength-headerlength-1
        NGT =   -------------------------
                  4 * number of players

The NGT stored in a lmp can also be found out with the -timedemo option. At the replay end, doom shows the number of game tics and time tics. This game tic number corresponds with NGT only in newer versions of DOOM (>=1.4). Older versions of DOOM report the wrong number (NGT+1).

With timedemo DOOM plays __all__ scenes in the lmp file back but without any synchronizing. So you can calculate also the frames per second with:

                           NGT
                  fps = --------- * 35
                        time tics

This has nothing to do with your frame rate during the game. This frame rate can be computed with the formula (from the FAQ v5.8 (9-2-1), thanks to Hank Leukart (ap641@cleveland.freenet.edu))

                           70
                  fps = --------
                        dots + 1

The dots are displayed with the -devparm option in the lower left edge of the screen. There are only 35 screens per second (each game tic), so one dot is always displayed. With every additional dot, DOOM shows how many vertical sync impulses (1/70s) were necessary to compute a whole screen. The game is not slower but you don't see each screen: the game becomes jerky.

3.2 Multiplayer lmp

In a 2, 3 or 4 player game the game tics are alternated stored, ie for a 2 player game:

game tic 1 of player 0
game tic 1 of player 1
game tic 2 of player 0
game tic 2 of player 1
game tic 3 of player 0
game tic 3 of player 1
           .
           .
           .

3.3 The -turbo parameter

This parameter speeds up all moves (forward, backward, strafe sideways) but not the turn. Due to the value sets described in section 3.4 all move bytes can be multiplied by 2.55 (or 255%) until they dont fit in a short int. This is exactly what happens. All normal move bytes are multiplied by the turbo value in percent. So you can play with -turbo 200 a normal game but your speed is the same as the shift key is always pressed. If you now press the shift key you are running like hell.

The turbo parameter isn't stored in the lmp but DOOM shows in the message line, if a player plays with turbo (ie "green is turbo"). DOOM conclude this from very large move bytes.

3.4 Data description

One game tic (for one player) corresponds to 4 bytes:

  |    0    |    1    |    2    |    3    |
  |   go    | strafe  |  turn   |   use   |

3.4.1. Byte 00h: Go Forward and Backward

The go byte contains a signed number (-127 (81h).. 127 (7Fh)), where positive numbers describe a forward and negative numbers a backward move. In older DOOM versions (and now with -turbo 100) the values go from -50 (CEh)... 50 (32h).

With a mouse you can achive all these codes. The codes for keyboard/joystick actions are:

-25 (E7h) / +25 (19h) go backward/forward
-50 (CEh) / +50 (32h) go backward/forward with speed on

3.4.2 Byte 01h: Strafe Sideways

The strafe byte contains a signed number (-127 (81h).. 127 (7Fh)), where positive numbers describe a right and negative numbers a left move. In older DOOM versions (and now with -turbo 100) the values go from -50 (CEh)... 50 (32h).

With a mouse you can achive all these codes. The codes for keyboard/joystick actions are:

-24 (E8h) / +24 (18h) strafe left/right
-50 (CEh) / +50 (32h) strafe left/right with speed on

3.4.3 Byte 02h: Turn

The turn byte contains a signed number (-127 (81h).. 127 (7Fh)), where positive numbers describe a left and negative numbers a right turn. The values go from -127 (81h)... 127 (7Fh). In my lmp's the maximal values are Turn Left 76 (4Ch) and Turn Right 78 (B2h). With a mouse you can achive all these codes.

                  360
The turn angle is --- * turn_byte degree.
                  256   

With IDMYPOS you can check your current viewing direction. During recording DOOM uses only a byte out of a long for the viewing angle:

        (40h)
          N

(80h) W   +   E (00h)
       
          S 
        (C0h)

The turn byte is directly the increment of the viewing angle.

The codes for keyboard/joystick actions (in DOOM version <1.4) are:

 -2 (FEh) /  +1 (01h) start turn right/left
 -3 (EDh) /  +2 (02h) turn right/left
 -5 (FBh) /  +5 (05h) turn right/left with speed on

Very strange is the fact, that the keyboard controlled right turn is faster than the keyboard controlled left turn. This must be a bug.

The codes for keyboard/joystick actions (in DOOM version >=1.4) are:

 -1 (FEh) /  +1 (01h) start turn right/left
 -2 (EDh) /  +3 (02h) turn right/left
 -5 (FBh) /  +5 (05h) turn right/left with speed on

Now some people at id corrected the right turn but now is the left turn a bit faster.

3.4.4 Byte 03h: Use

In the use byte are coded the fire weapon, the press button/open door and the change weapon actions:

   --------------------------------------------
   | 7     | 6  | 5  | 4  | 3  | 2  | 1  | 0  |
   | SA=0  | 0  |    Weapon    | WB | UB | FB |
   --------------------------------------------

The Fire Bit (FB) is 1 during a shot. The Use Bit (UB) indicates the use of anything (press a button, open a door etc.). The Weapon Bit (WB) is 1 if the player changes manually his weapon. The weapon number is stored in the following bits.

The weapon numbers are beginning with 0; not with 1 as is the status bar:

       Code := 4 + 8* (Weapon-1)

The codes are:

   4 (04h) Activate Weapon 1 (Fist)
  12 (0Ch) Activate Weapon 2 (Pistol)
  20 (14h) Activate Weapon 3 (Shotgun)
  28 (1Ch) Activate Weapon 4 (Chaingun)
  36 (24h) Activate Weapon 5 (Rocket Launcher)
  44 (2Ch) Activate Weapon 6 (Plasma Rifle)
  52 (34h) Activate Weapon 7 (BFG 9000)
  60 (3Ch) Activate Weapon 8 (Chainsaw)

The bits can be composed. So you can with a use byte of 03h fire and use at the same time.

If the Special Actions (SA) bit is 1, the meaning of the other bits changes totally:

In the bits 0 and 1 is now coded the Special Action itself.

-----------------
|1|x|x|x|x|x|0|1|       stands for pause/unpause
-----------------

and

-----------------
|1|x|x| SLN |1|0|       stands for save game in slot SLN (0<=SLN<=7).
----------------- 

The x-bits aren't important at all. DOOM itselft let they 0 but does not analyze them afterwards.

DOOM saves the game even during the replay of a lmp.

3.4.5. Special entries

If there are no actions at all, all 4 bytes contain 00h. This is a wait tic. The end of the lmp is coded in the go byte of an uncomplete game tic. Because there is no go value of -128 (80h), DOOM can't make a mistake.