  The unofficial DEM format description
  Uwe Girlich, uwe@planetquake.com
  v1.0.6, 3/12/1998

  This document describes the DEM file format. This file format is the
  result of ``recording'' a game in Quake or Hexen II.  This documenta-
  tion covers the Quake versions 0.91 through 1.09 and the Hexen II demo
  release.
  ______________________________________________________________________

  Table of Contents























































  1. Introduction

     1.1 Recording and Playback
     1.2 Versions

  2. Basics on the used client/server architecture

  3. Some remarks on the used demo format

     3.1 Advertising
     3.2 Difference to DOOM
     3.3 Opportunities of the DEM format
     3.4 Problems of the DEM format

  4. Some general remarks on the recording structure

     4.1 Entity
        4.1.1 Static Entity
        4.1.2 Dynamic Entity
        4.1.3 Temporary Entity
     4.2 Life-cycles
        4.2.1 Armor
        4.2.2 (Multi) Player
        4.2.3 Medikits, Chthon, etc.

  5. Quake font

  6. File structure

     6.1 CD track
        6.1.1 (TT
        6.1.2 step-by-step
        6.1.3 General hints
     6.2 Block of Messages
     6.3 Message
     6.4 Auxiliary routines

  7. List of all message types

     7.1 bad
     7.2 nop
     7.3 disconnect
     7.4 updatestat
     7.5 version
     7.6 setview
     7.7 sound
     7.8 time
     7.9 print
     7.10 stufftext
     7.11 setangle
     7.12 serverinfo
     7.13 lightstyle
     7.14 updatename
     7.15 updatefrags
     7.16 clientdata
     7.17 stopsound
     7.18 updatecolors
     7.19 particle
     7.20 damage
     7.21 spawnstatic
     7.22 spawnbinary
     7.23 spawnbaseline
     7.24 temp_entity
     7.25 setpause
     7.26 signonum
     7.27 centerprint
     7.28 killedmonster
     7.29 foundsecret
     7.30 spawnstaticsound
     7.31 intermission
     7.32 finale
     7.33 cdtrack
     7.34 sellscreen
     7.35 particle2
     7.36 cutscene
     7.37 midi_name
     7.38 updateclass
     7.39 particle3
     7.40 particle4
     7.41 set_view_flags
     7.42 clear_view_flags
     7.43 start_effect
     7.44 end_effect
     7.45 plaque
     7.46 particle_explosion
     7.47 set_view_tint
     7.48 reference
     7.49 clear_edicts
     7.50 update_inv
     7.51 updateentity

  8. Version History and Acknowledgements



  ______________________________________________________________________

  11..  IInnttrroodduuccttiioonn


  11..11..  RReeccoorrddiinngg aanndd PPllaayybbaacckk

  Recording a game in Quake is as easy as playing it: you need some
  console commands to do it well.

  To create a single player DEM file start the game as usual and use the
  console command _r_e_c_o_r_d _n_a_m_e _l_e_v_e_l _[_c_d_t_r_a_c_k_]. This starts level with
  the currently selected skill and writes a record in name.dem.  The
  recording will be written during all the play and this record file may
  grow unpredictable. Make sure that you have some MBytes free disk
  space.  To stop this recording use _s_t_o_p or even quit the whole game
  (_q_u_i_t). To play it back, use the commands _p_l_a_y_d_e_m_o _n_a_m_e or _t_i_m_e_d_e_m_o
  _n_a_m_e.

  To create a multi player DEM file start a ``listen'' server (recording
  from a dedicated server doesn't work) and use again the _r_e_c_o_r_d
  command. This starts the selected level and the player at the server
  is alone in this level. Now all the other clients can connect to the
  server as usual and play what they like (deathmatch or team). The
  recording lasts until the player at the listen server uses the
  _d_i_s_c_o_n_n_e_c_t, _s_t_o_p or _q_u_i_t command. The recording is from the point of
  view of the player at the listen server (client 1). The playback works
  as in the single player case.


  11..22..  VVeerrssiioonnss

  In this document I'll discuss the DEM format used by the various
  versions of Quake and the variant of the DEM format used by Hexen II
  (demo version).


  Exe:                   version                 platform
  ?                      0.91                    MS-DOS, SVGA, 8bpp
  ?                      0.92                    MS-DOS, SVGA, 8bpp
  ?                      0.92                    Linux, X11, 8bpp
  17:38:28 Jul 12 1996   1.0                     MS-DOS, SVGA, 8bpp
  ?                      1.01                    MS-DOS, SVGA, 8bpp
  22:32:43 Aug 4 1996    1.01                    Linux, X11, 8bpp
  22:32:43 Aug 4 1996    1.01                    Linux, X11, DGA, 8bpp
  ?                      1.05beta                MS-DOS, SVGA, 8bpp
  Sep 30 1996            1.06                    MS-DOS, SVGA, 8bpp
  16:49:53 Nov 22 1996   1.06                    Linux, X11, 8bpp
  22:44:36 Jan 17 1997   1.01                    Linux, X11, 16bpp
  ?                      1.07                    MS-DOS, SVGA, 8bpp
  ?                      1.07                    Linux, SVGA, 8bpp
  ? Mar 11 1997          1.08                    MS-DOS, SVGA, 8bpp
  ? Mar 21 1997          1.09                    Win32, DirectX, 8bpp
  15:28:15 Aug 7 1997    1.09                    Linux, SVGA, 8bpp
  00:36:23 Oct 14 1997   (X11 Quake 1.00) 1.09   Linux, X11, 8bpp, 16bpp
  ? Nov 7 1997           1.09                    Win32, Glide
  14:37:37 Nov 13 1997   (Linux GL 0.97) 1.09    Linux, SVGA, Glide, 16bpp


                          Covered Quake versions

  There is a small change in the Quake DEM format from 1.06 to 1.07. It
  will be discussed in the section ``clientdata''. A new message was
  introduced in 1.07 too (see section ``cutscene''. In version 1.08 the
  tteemmpp__eennttiittyy message changed a bit (see section ``temp_entity''). In
  version 1.09 the CD track reading changed totally (see section ``CD
  track'').

  I actually check my documentation with Linux Registered Quake 1.09
  (x/squake) and compare it rarely with MS-DOS Registered Quake 1.06.


                       OS       version    pak-file
                       Win32    demo       demo


                        Covered Hexen II versions

  The Hexen II DEM format isn't totally decoded yet. I have no Win32 at
  home and there is no Linux version available. It will take at least up
  to April 1998.


  22..  BBaassiiccss oonn tthhee uusseedd cclliieenntt//sseerrvveerr aarrcchhiitteeccttuurree

  Unlike DOOM and similar games Quake uses a ``server'' process (or even
  computer) which ``does'' all the game play. The ``clients'' (at least
  one) send to the server all input events (keys, mouse etc.) and
  receive all necessary information to draw the current picture. This
  prevents Quake from inconsistencies and the network load increases
  linear with the clients and not quadratic.

  The communication between server and clients is an asynchronous one.
  If you don't press any key, your computer won't send any packets to
  the server. But you receive from time to time (the network is
  unpredictable) a packet to describe the state of your client. It is
  obvious, that these packets must contain some time stamp information,
  the positions of all monsters in sight and some player state
  information like the current weapon, ammo etc.


  And exactly this is the DEM file format: the recording of all packets
  from the server to that client, who recorded the game (the first
  client).  I call these packets ``blocks of messages'' and the single
  information (time, position, ammo etc.) ``message''.  In the original
  QuakeC code are some comments referring to ``commands'' instead of
  ``messages'' but I won't change all my documentation after all.

  The (listen) server process does the actual recording (file write
  access).  Since every client gets all information to write the demo
  himself it was a matter of time until someone wrote a client proxy to
  record demos at the client side. I know two of them:

     ddpprrooxxyy
        written by Kekoa Proudfoot kekoa@graphics.stanford.edu.

     FFAAQQ--PPrrooxxyy
        written by Juha Kujala jmkujala@cc.jyu.fi and Ilkka Rajala
        r151925@proffa.cc.tut.fi.  For more information visit FAQ
        homepage at <http://www.modeemi.cs.tut.fi/quake/>.


  33..  SSoommee rreemmaarrkkss oonn tthhee uusseedd ddeemmoo ffoorrmmaatt


  33..11..  AAddvveerrttiissiinngg

  As the clever reader may know I'm the author of LMPC, the
  LMP/DMO/DEM/QWD Control Centre. With this tool you may

  +o  ``decompile'' an existing DEM file to a simple text file and

  +o  ``compile'' such a (modified) text file back to a binary DEM file.

     With LMPC it is very easy to analyse a DEM file but you can change
     it as well and so create a DEM file of a Quake game you never
     played.  The current version of LMPC can be found at my Demo Specs
     page <http://www.planetquake.com/demospecs>.


  33..22..  DDiiffffeerreennccee ttoo DDOOOOMM

  The recording of a DOOM game consists only of the player input. All
  the rest is random-number dependent but totally deterministic and will
  be recalculated during the playback.

  If you change a single action in a LMP file all the rest is garbage
  because all monsters now behave totally different and sooner or later
  (sooner) you run into a wall. This can't happen in a DEM file. The
  full movement of all objects is stored in it.

  This confronts us with new opportunities but also new problems.


  33..33..  OOppppoorrttuunniittiieess ooff tthhee DDEEMM ffoorrmmaatt

  With the cceenntteerrpprriinntt message it is possible to include some _s_u_b_-_t_i_t_l_e_s
  in a recording file to inform the watchers what will happen next.

  The player coordinates and the camera positions may be different. This
  makes it possible to simulate the Duke Nukem 3D feature of stationary
  cameras.  The client doesn't draw the entity with the ``viewpoint''.
  This is in general the player entity itself but this entity can be
  changed to anything else with the setview message.  Another problem is
  the entity selection of the server, which sends to the client only the
  entities in sight (of the client). Therefore it is impossible to
  enlarge the distance between the camera and the recording player too
  much. They both have to be on the same side of a wall.

  For people with too much spare-time Quake can replace a full 3D
  modelling system for cartoons or the like.

  The demo file can contain console commands, which the client runs
  during replay. With this feature it is possible to write a screen shot
  after every time stamp in the demo file. This makes it very easy to
  create a MPEG movie out of a DEM file.


  33..44..  PPrroobblleemmss ooff tthhee DDEEMM ffoorrmmaatt

  It is trivial to remove the ``godmode ON'' and other cheat messages
  from a recording. All the action doesn't change at all. These messages
  are only text print commands and the client behaviour doesn't depend
  on them.

  Fortunately I found a redundancy in the DEM format, which allows to
  detect a ``godmode'' cheater: Every damage message contains the health
  and armor decrease value. The next status line description (it
  contains the health and armor values to be displayed) can so be
  checked.


  44..  SSoommee ggeenneerraall rreemmaarrkkss oonn tthhee rreeccoorrddiinngg ssttrruuccttuurree


  44..11..  EEnnttiittyy

  An entity is an object. This may be the whole level (described by a
  BSP file), the player (described by a MDL file), an explosion
  (described by a SPR file) or the like.

  There are different kind of entities.


  44..11..11..  SSttaattiicc EEnnttiittyy

  A static entity doesn't interact with the rest of the game. These are
  flames (progs/flame.mdl) and the like. It will be created by the
  spawnstatic message.  It will never be necessary to reference such an
  entity. They don't get an entity number. The maximum number of static
  entities is 127.


  44..11..22..  DDyynnaammiicc EEnnttiittyy

  A dynamic entity is anything which changes its behaviour or its
  appearance.  These are ammunition boxes, spinning armours, player
  models and the like.  A dynamic entity will be created by the
  spawnbaseline message. The maximum number of dynamic entities is 449.


  44..11..33..  TTeemmppoorraarryy EEnnttiittyy

  A temporary entity will be created by the temp_entity message.  A
  temporary entity is a (as the name indicates) short time entity.

  Quake uses these entities for hits on the wall (point-like entities)
  or for the Thunderbolt flash (line-like entities).

  For more information on temporary entities look in section
  ``temp_entity''.




  44..22..  LLiiffee--ccyycclleess

  The Quake objects pass different life phases. The following
  information is not DEM specific but it may be of general interest to
  understand the cooperation of all the messages.


  44..22..11..  AArrmmoorr


  +o  To enable the client to display an armor the serverinfo message
     asks for the ``progs/armor.mdl'' model file and the
     ``items/armor1.wav'' sound file.

  +o  The armor starts its life with a spawnbaseline message during the
     initialise phase. The armor is now a dynamic entity and spins
     around.

  +o  The corresponding updateentity message appears only, if the camera
     is near enough to see the armor.

  +o  The player gets it in the play. This results in the sound message
     ``items/armor1.wav'' and a print message ``you got armor'' and the
     stufftext message ``bf\n'' to make a short flash.

  +o  The updateentity message for the armor doesn't appear ever again:
     the player got it.

  +o  From this moment the corresponding bit in the items variable in the
     clientdata message will be 1 and the armorvalue variable get its
     maximum (100/150/200).  From the items bit follows the colour of
     the picture to be drawn in the lower left corner of the status
     line.

  +o  Now the player may be hit by a grenade. The total damage value
     (damage=take+save) will be split in take (health-=take) and save
     (armorvalue-=save).  The save amount depends on the armor type
     (none/green/yellow/red): save=0.0/0.3/0.6/0.8*damage.  The damage
     message in the DEM file tells the reduction of the current armor.
     With the old clientdata value and the reduction it is easy to
     recompute the new clientdata armor value.  Any difference betrays
     the cheating player.

  +o  After some severe hits the armorvalue variable is 0 and the items
     bit falls back to 0 as well. There is no armor anymore.


  44..22..22..  ((MMuullttii)) PPllaayyeerr

  The following describes the deathmatch DEM messages of the two players
  Alice and Bob. Alice records the game from her -listen 3 server.


  +o  The serverinfo message contains the ``maxclients 3'' command to
     show how many clients are (at most) in this recording.

  +o  During the 1st initialisation phase there are 3 spawnbaseline
     messages to create the player models. In the 2nd initialisation
     phase player 0 gets its name (Alice), colour and frag count (0) .
     The other 2 players get an empty name string. In the 3rd phase
     Alice gets again her name and colour.  All these phases are
     controlled by signonnum messages.

  +o  The game starts. Alice (entity 1) is alone in the game and looks
     around.

  +o  Bob connects to Alice's server and it appears entity 2 (Bob's
     player model) a transport end temporary entity and a print message
     (``Bob entered the game'') to inform everyone. Then the player 1
     (Bob) gets his updatename and updatecolors message.

  +o  Alice doesn't hesitate and runs for him and shoots him with the
     Shotgun.  During every shot the clientdata message reduces the ammo
     count, the angles[0] command shows the wobble of Alice's screen and
     the weaponframe command selects the corresponding weapon frames.
     There is a sound message to start the weapons/guncock.wav file.
     Entity 1 gets its attack_state command. Alice hits Bob and so
     appear many particle messages (blood).  Every Shotgun shot contains
     6 parts. This means the shot can create anything from 6 particles
     (full hit) and 0 temporary entities (type 2: wall hits) to 0
     particles and 6 temporary entities. If there was at least one
     particle Bob creates a sound message to start player/pain?.wav.

  +o  Alice kills Bob. This creates the sound message to start
     player/death1.wav. Then comes the updatefrags message to give Alice
     1 frag and a print message to inform everyone ``Bob chewed on
     Alice's boomstick''. A new entity will be created on the fly with
     an updateentity message to display Bob's backpack.

  +o  Bob is dead, his entity 2 model remains in the death frame.

  +o  After some seconds he starts again by pressing SPACE. He reappears
     in a totally different part of the level. The dead body transforms
     from entity 2 to entity 4 (maxclients+1) and a temporary entity
     (transport end) informs about his return. He is out of sight from
     the point of Alice's view. This means there is no entity 2
     updateentity message.

  +o  Bob runs to Alice's room. He goes through a slipgate and appears
     with 4 temporary entities (type 11: transport end) and the entity 2
     in her room.

  +o  Bob shoots and kills Alice. The scenario is the same as above. Only
     the damage messages appear now too, because Alice was hit.

  +o  Bob uses the say console command (_s_a_y _t_h_i_s _s_u_c_k_s) and in the DEM
     file appears a print message ``\001Bob: this sucks''.

  +o  Bob disconnects from Alice's server. This results in a print
     message ``Bob left the game with 1 frags'' and updatename and
     updatecolor messages to remove client 2 (or player 1). It is a bit
     strange but there are 2 updatefrags messages: player 1 gets first 0
     frags (this I understand) and then again 1 frag (this I don't
     understand at all).

  +o  Entity 2 represents now the dead player 1.

  +o  Alice spins around (it is possible even if you are dead) and the
     two dead bodies from Bob are totally white because they represent
     player 1 and he got (as he left) the updatecolor message with the
     standard colours 0 and 0. She is alone, restarts again her play,
     goes to the level end slipgate and get the ranking screen
     (intermission message) with only one player (Alice). Then she stops
     the recording. The DEM file ends with a disconnect message.


  44..22..33..  MMeeddiikkiittss,, CChhtthhoonn,, eettcc..

  May be included later, if someone volunteers. Reading the QuakeC
  source is much easier.


  55..  QQuuaakkee ffoonntt

  A string may contain any 8 bit characters except `\377' and it ends
  with `\000'. The special characters `\n' and `\r' have their normal
  meaning.

  The Quake font is an extended ASCII font (7 bit) which contains in the
  upper half a similar font but with a different colour.

  If the first character of a string for the print message is `\001',
  the Quake client plays the intercom sound misc/talk.wav and prints all
  following characters of the string with the highest bit set.  Bit 7
  bit will be set with `\002' at the first position of the string as
  well but this does not play the intercom sound. The special characters
  `\n' and `\r' are not affected by the meta characters `\001' and
  `\002'.

  All 252 Quake font characters and their codes can be viewed in a PCX
  file created by playing a special screen shot DEM file at my Demo
  Specs page <http://www.planetquake.com/demospecs>.  The PCX file and
  the DEM text file are available as well.


  66..  FFiillee ssttrruuccttuurree

  To describe the file structure, which is very complicated, I use C
  like program fragments and struct definitions. This simplifies my task
  a lot.

  I invented all used names (messages, variables etc.) for myself, took
  them from the Quake binary, QuakeEd but almost all from the QuakeC
  source.



  66..11..  CCDD ttrraacckk

  Beside all the beauty in DEM files, there is a real mess called CD
  track at the very beginning of a DEM file.

  All DEM files should start with an ASCII string of the CD track number
  which was given to the record console command. The string should be
  terminated by `\n'.

  There are two totally different variants, how Quake reads this first
  bit in: the old fscanf-variant and the new step-by-step variant
  introduced with version 1.09.


  66..11..11..  ffssccaannff

  Quake reads the CD track bit with something like

       FILE *fp;
       int cdtrack;
       fscanf(fp,"%i\n",&cdtrack);


  This makes it possible (read the fscanf(3) man page!) to terminate the
  CD track string with any (positive) number of any whitespaces (` ',
  \t,\r,\n). You shouldn't come across anything more complicated than
  "4" or "-1" (default CD track of the level).

  Because of the possibility of multiple whitespaces at the end, Quake
  can't playback DEM files, where the first byte of the blocksize of the
  first block (see next section) can be interpreted as a whitespace.
  Quake wont playback such a file at all!

  The fscanf approach made it possible to create DEM files without any
  CD track at all at the beginning. The fscanf call return 0 instead of
  1 but who cares? The only thing to take into account is that the first
  byte of this DEM file have to be no ASCII number or whitespace or
  minus sign. So fscanf can't find the integer number and reads nothing.
  The track value is undefined.


  66..11..22..  sstteepp--bbyy--sstteepp

  Newer Quake versions try to overcome the multiple whitespace problem
  of the fscanf variant and read the track ``by hand''.  There is a
  difference between different Quake version, how to read in this

  The CD track parsing code goes as follows:



       FILE *fp;
       int cdtrack=0;
       int sign=0;

       while((number = ReadByte(FILE)) != '\n') {
         if (number == '-')
           sign=1;
         else
           track = track*10 + number - '0';
       }
       if (sign)
         track=-track;




  This code is much better but it can't detect files without any header.
  The other thing is it interprets ``1-\n'' as -1 but the old fscanf
  variant will be totally confused.


  66..11..33..  GGeenneerraall hhiinnttss

  My LMPC program tries to read any kind of DEM file, so you have the
  possibility to change and even remove a CD track. To be most
  compatibe, use only numbers and a minus sign at the beginning.

  If you didn't give a CD track number to the record console command the
  CD track string is ``-1\n''.  This means almost all DEM files start
  with ``-1\n''.  If you gave a CD track but it is not a number at all
  the string is ``0\n''.

  All the rest of the DEM file consists of ``blocks'' of ``messages''.


  66..22..  BBlloocckk ooff MMeessssaaggeess

  At first some QuakeEd-like coordinate typedef's:


       typedef float vec_t;

       typedef vec_t vec3_t[3];



  This is the block structure:


       typedef struct {
                        long            blocksize;
                        vec3_t          angles;
                        char            messages[blocksize];
                      } block_t;




  A block of messages starts with a size. Then 3 angles follow which
  describe the camera viewing direction. All the rest of a block are
  bytes which form one or more messages.

  The messages in a block are the same messages as in the server to
  client network protocol. The block header is different and the camera
  angles are missing in the network protocol. For more information on
  the network protocol look in The Unofficial Quake Specs at the
  official Quake-editing support site,
   <http://www.gamers.org/dEngine/quake/spec/>.

  Please note the missing camera angles in the network protocol. In an
  actual game every Quake client ``knows'' its viewing direction for
  itself and gets from the server only the position.


  66..33..  MMeessssaaggee

  This is the message structure:


       typedef struct {
                        unsigned char ID;
                        char          messagecontent[???];
                      } message_t;




  The length of a message depends on its type (or ID).


  66..44..  AAuuxxiilliiaarryy rroouuttiinneess

  Here comes the definition of some small auxiliary routines to simplify
  the main message description. get_next_unsigned_char,
  get_next_signed_char, get_next_short and get_next_long are basic
  functions and they do exactly what they are called. Please note: byte,
  char or short will be converted to long.  Second note: all multi-byte
  structures in the DEM file are Intel ordered.

  In the following I often use a count variable


       int i;




  without declaration. I hope this does not confuses you.




  long ReadByte
  {
    return (long) get_next_unsigned_char;
  }






       long ReadChar
       {
         return (long) get_next_signed_char;
       }






       long ReadShort
       {
         return (long) get_next_short;
       }






       long ReadLong
       {
         return get_next_long;
       }




  Note: A signed angle in a single byte. There are only 256 possible
  direction to look into.



       vec_t ReadAngle
       {
         return (vec_t) ReadChar / 256.0 * 360.0;
       }






       vec_t ReadCoord
       {
         return (vec_t) ReadShort * 0.125;
       }




  The string reading stops at '\0' or after 0x7FF bytes. The internal
  buffer has only 0x800 bytes available.



  char* ReadString
  {
    char* string_pointer;
    char string_buffer[0x800];

    string_pointer=string_buffer;
    for (i=0 ; i<0x7FF ; i++, string_pointer++) {
      if (! (*string_pointer = ReadChar) ) break;
    }
    *string_pointer = '\0';
    return strdup(string_buffer);
  }






       long ReadEntity
       {
         return ReadShort;
       }





  77..  LLiisstt ooff aallll mmeessssaaggee ttyyppeess

  The easiest way to explain a message is to give a short C like program
  fragment to parse such a message. It is not really the same code base
  as in LMPC but it should be _v_e_r_y similar. Each message can be
  described by its ID or its name.



  77..11..  bbaadd


     ID 0x00


     ppuurrppoossee
        Something is bad. This message should never appear.


     ppaarrssee rroouuttiinnee
        none



  77..22..  nnoopp


     ID 0x01


     ppuurrppoossee
        No operation.


     ppaarrssee rroouuttiinnee
        none



  77..33..  ddiissccoonnnneecctt


     ID 0x02


     ppuurrppoossee
        Disconnect from the server. Stops the game.


     ppaarrssee rroouuttiinnee
        none



  77..44..  uuppddaatteessttaatt


     ID 0x03


     ppuurrppoossee
        Updates directly any values in the player state.


     vvaarriiaabblleess


        long index;
           is the index in the playerstate array.

                         index    variable
                             0    health
                             1    ??? (not used)
                             2    weaponmodel
                             3    currentammo
                             4    armorvalue
                             5    weaponframe
                             6    ammo_shells
                             7    ammo_nails
                             8    ammo_rockets
                             9    ammo_cells
                            10    weapon
                            11    total_secrets
                            12    total_monsters
                            13    found_secrets
                            14    killed_monsters
                            15    ???
                             .
                             .
                             .
                            31    ???


                            updatestat indices

           Normal DEM files use index 11 to 14 only.


        long value;
           is the new value.


        long playerstate[32];
           is the internal array to describe the player state. Many
           other messages change (indirectly) some values in it.
     ppaarrssee rroouuttiinnee


          index = ReadByte;
          if (index > 0x1F) {
            error("svc_updatestat: %i is invalid", index);
          }
          value = ReadLong;
          playerstate[index] = value;






  77..55..  vveerrssiioonn


     ID 0x04


     ppuurrppoossee
        This message defines the version of the server. I never found
        such a message in a DEM file. It may be absorbed by the
        serverinfo message.


     vvaarriiaabblleess

        long serverprotocol;
           is the version number of the server. It should be 0x0F.


     ppaarrssee rroouuttiinnee


          serverprotocol = ReadLong;
          if (serverprotocol != 0x0F) {
            error("CL_ParseServerMessage: Server is protocol %i instead of %i\n",
                                                           serverprotocol, 0x0F);
          }






  77..66..  sseettvviieeww


     ID 0x05


     ppuurrppoossee
        Sets the camera position to the origin of this entity.


     vvaarriiaabblleess

        long entity;
           is the entity with the camera.


     ppaarrssee rroouuttiinnee


     entity = ReadShort;






  77..77..  ssoouunndd


     ID 0x06


     ppuurrppoossee
        This message starts the play of a sound at a specific point.


     vvaarriiaabblleess


        long mask;
           is a bitmask to reduce the amount of data.


        float vol;
           is the volume of the sound (0.0 off, 1.0 max)


        float attenuation;
           is the attenuation of the sound.

  value    QuakeC         purpose
  0        ATTN_NONE      i. e. player's death sound doesn't get an attenuation
  1        ATTN_NORM      the normal attenuation
  2        ATTN_IDLE      for idle monsters
  3        ATTN_STATIC    for spawnstaticsound messages


                            Sound attenuations


        long channel;
           is the sound channel. There are 8 possible sound channels for
           each entity in Quake but the game uses 5 only.

         value    QuakeC         purpose
         0        CHAN_AUTO      selects a channel automatically
         1        CHAN_WEAPON    weapon use sounds
         2        CHAN_VOICE     pain calls
         3        CHAN_ITEM      item get sounds
         4        CHAN_BODY      jump and fall sounds


                              Sound channels


        long entity;
           is the entity which caused the sound.


        long soundnum;
           is the sound number in the sound-table.


        vec3_t origin;
           is the origin of the sound.
     ppaarrssee rroouuttiinnee


          long entity_channel; // combined variable

          mask = ReadByte;
          vol = mask & 0x01 ? (float) ReadByte / 255.0 : 1.0;
          attenuation = mask & 0x02 ? (float) ReadByte / 64.0 : 1.0;
          entity_channel = ReadShort;
          channel = entity_channel & 0x07;
          entity = (entity_channel >> 3) & 0x1FFF;
          soundnum = ReadByte;
          for (i=0 ; i<3 ; i++) origin[i] = ReadCoord;






  77..88..  ttiimmee


     ID 0x07


     ppuurrppoossee
        This is the time stamp of a block of messages. A time message
        should appear in every game block.


     vvaarriiaabblleess

        float time;
           is the time in seconds from the beginning of the current
           level (not of the recording).


     ppaarrssee rroouuttiinnee


          time = ReadFloat;






  77..99..  pprriinntt


     ID 0x08


     ppuurrppoossee
        The client prints the text in the top left corner of the screen.
        There is space for 4 lines. They scroll up and the text
        disappears.  The text will be printed on the console as well.


     vvaarriiaabblleess

        char* text;
           is the text to be displayed.  The text contains something
           like ``You get 5 shells''.

           All font specials are explained in section ``Quake font''.
     ppaarrssee rroouuttiinnee


          text = ReadString;






  77..1100..  ssttuufffftteexxtt


     ID 0x09


     ppuurrppoossee
        The client transfers the text to the console and runs it.


     vvaarriiaabblleess

        char* text;
           is the command, which the client has to execute. These are
           commands like ``bf\n'' to make a flash after you took
           something.


     ppaarrssee rroouuttiinnee


          text = ReadString;






  77..1111..  sseettaannggllee


     ID 0x0A


     ppuurrppoossee
        This message set the camera orientation.


     vvaarriiaabblleess

        vec3_t angles;
           is the new camera orientation.


     ppaarrssee rroouuttiinnee


          for (i=0 ; i<3 ; i++) angles[i] = ReadAngle;








  77..1122..  sseerrvveerriinnffoo


     ID 0x0B


     ppuurrppoossee
        This message is usually the first messages in a DEM file and
        after a level change. It loads model and sound files.


     vvaarriiaabblleess


        long serverversion;
           is the version of the server.  It should be the same as the
           version of the client. Up to now this version was always
           0x0F.


        long maxclients;
           is the maximum number of clients in this recording. It is 1
           in single player recordings or the number after the -listen
           command line parameter.


        long multi;
           is 0 in single player recordings and 1 in multi player
           recordings. It actually toggles the ranking screen at the end
           of a level.


        char* mapname;
           is the name of the level.


        char* precache_models[MAX_MODELS+1];
           is the model-table.  It will be filled up with model names.
           Many other messages contain an index in this array.  The
           first used index is 1.  MAX_MODELS has the value 255 in Quake
           and (maybe) the value 511 in Hexen II.


        long nummodels;
           is the number of models in the model-table.


        char* precache_sounds[MAX_MODELS+1];
           is the sound-table.  It will be filled up with sound names.
           Many other messages contain an index in this array.  The
           first used index is 1.  MAX_SOUNDS has the value 255 in Quake
           and (maybe) the value 511 in Hexen II.


        long numsounds;
           is the number of sounds in the sound-table.



     ppaarrssee rroouuttiinnee






     serverversion = ReadLong;
     if (serverversion != 0x0F) {
       error("Server returned version %i, not %i", serverversion, 0x0F);
     }
     maxclients = ReadByte;
     multi = ReadByte;
     mapname = ReadString;
     nummodels = 0;
     do {
       if (++nummodels > 255) error("Server sent too many model_precache");
       precache_models[nummodels] = ReadString;
     } while (*precache_models[nummodels]);
     numsounds = 0;
     do {
       if (++numsounds > 255) error("Server sent too many sound_precache");
       precache_sounds[numsounds] = ReadString;
     } while (*precache_sounds[numsounds]);






  77..1133..  lliigghhttssttyyllee


     ID 0x0C


     ppuurrppoossee
        This message defines a light style.


     vvaarriiaabblleess

        long style;
           is the light style number.

        char* string;
           is a string of letters ``a'' .. ``z'', where ``a'' means
           black and ``z'' white.  All effects from nervous flashing:
           ``az'' to slow dimming: ``zyxwvu ... edcba'' can so be
           described.


     ppaarrssee rroouuttiinnee


          style = ReadByte;
          string = ReadString;






  77..1144..  uuppddaatteennaammee


     ID 0x0D


     ppuurrppoossee
        This message sets the player name.


     variables

        long player;
           is the internal player number (client 1 has the player entity
           0).

        char* netname;
           is the new player name.


     ppaarrssee rroouuttiinnee


          player = ReadByte;
          netname = ReadString;






  77..1155..  uuppddaatteeffrraaggss


     ID 0x0E


     ppuurrppoossee
        This message updates the frag count of a specific player.


     vvaarriiaabblleess

        long player;
           is the internal player number (client 1 has the player entity
           0).

        long frags;
           is the new frag count for this player.


     ppaarrssee rroouuttiinnee


          player = ReadByte;
          frags = ReadShort;






  77..1166..  cclliieennttddaattaa


     ID 0x0F


     ppuurrppoossee
        This message updates the status line and the camera coordinates.


     vvaarriiaabblleess



        long mask;
           is a bitmask to show which values are coming.


        float view_ofs_z;
           is an additional viewing offset because the camera is at the
           origin of the entity and not at the eyes (is -8 if the player
           is death).


        float punchangle_x;
           is an additional offset of the first angle.


        vec3_t angles;
           indicates the camera direction change.


        vec3_t vel;
           indicates the camera velocity.


        long items;
           contains a bit mask for the inventory.

  bit    value         QuakeC                 purpose
    0    0x00000001    IT_SHOTGUN             Shotgun (should be always 1)
    1    0x00000002    IT_SUPER_SHOTGUN       Double-barrelled Shotgun
    2    0x00000004    IT_NAILGUN             Nailgun
    3    0x00000008    IT_SUPER_NAILGUN       Perforator
    4    0x00000010    IT_GRENADE_LAUNCHER    Grenade Launcher
    5    0x00000020    IT_ROCKET_LAUNCHER     Rocket Launcher
    6    0x00000040    IT_LIGHTNING           Thunderbolt
    7    0x00000080    IT_EXTRA_WEAPON        extra weapon (there is no extra weapon)
    8    0x00000100    IT_SHELLS              Shells are active
    9    0x00000200    IT_NAILS               Nails are active
   10    0x00000400    IT_ROCKETS             Grenades are active
   11    0x00000800    IT_CELLS               Cells are active
   12    0x00001000    IT_AXE                 Axe (should be always 1)
   13    0x00002000    IT_ARMOR1              green Armor
   14    0x00004000    IT_ARMOR2              yellow Armor
   15    0x00008000    IT_ARMOR3              red Armor
   16    0x00010000    IT_SUPERHEALTH         Megahealth
   17    0x00020000    IT_KEY1                silver keycard (or runekey or key)
   18    0x00040000    IT_KEY2                gold keycard (or runekey or key)
   19    0x00080000    IT_INVISIBILITY        Ring of Shadows
   20    0x00100000    IT_INVULNERABILITY     Pentagram of Protection
   21    0x00200000    IT_SUIT                Biosuit
   22    0x00400000    IT_QUAD                Quad Damage
   23    0x00800000    unknown                unknown (is 0)
   24    0x01000000    unknown                unknown (is 0)
   25    0x02000000    unknown                unknown (is 0)
   26    0x04000000    unknown                unknown (is 0)
   27    0x08000000    unknown                unknown (is 0)
   28    0x10000000    unknown                Rune 1
   29    0x20000000    unknown                Rune 2
   30    0x40000000    unknown                Rune 3
   31    0x80000000    unknown                Rune 4


                                items bits

           You can find the default value for items in the parse
           routine: 0x4001. It looks like a programmer's mistake because
           this means Shotgun any yellow Armor. It should be 0x1001:
           Shotgun and Axe.
        long weaponframe;
           is the frame of the weapon model.


        long armorvalue;
           is the current armor.


        long weaponmodel;
           is the model number of the weapon in the model-table.


        long health;
           is the current health.


        long currentammo;
           is the current number of the current ammunition.


        long ammo_shells;
           is the current number of shells.


        long ammo_nails;
           is the current number of nails.


        long ammo_rockets;
           is the current number of rockets.


        long ammo_cells;
           is the current number of cells.


        long weapon;
           contains a bit mask for the current weapon.

  bit    value    QuakeC                weapon
  ?      0x00     not available         Axe
  0      0x01     IT_SHOTGUN            Shotgun
  1      0x02     IT_SUPER_SHOTGUN      Double-barrelled Shotgun
  2      0x04     IT_NAILGUN            Nailgun
  3      0x08     IT_SUPER_NAILGUN      Perforator
  4      0x10     IT_GRENADE_LAUNCHER   Grenade Launcher
  5      0x20     IT_ROCKET_LAUNCHER    Rocket Launcher
  6      0x40     IT_LIGHTNING          Thunderbolt
  7      0x80     IT_EXTRA_WEAPON       extra weapon (there is no extra weapon)


                               weapon bits


        float version;
           is the Quake version. Up to Quake 1.06 the bit 0x0200 in the
           mask variable indicated an used items entry. From 1.07 on the
           bit will be ignored and the items entry is compulsory. An old
           Quake client (<=1.06) can not play back the recording of a
           new Quake (>=1.07) because the unused bit is from 1.07 on
           always 0. The most compatible variant is to set the bit
           0x0200 and include an items entry. This is the standard
           behaviour of LMPC.



     ppaarrssee rroouuttiinnee


          long uk_bit_b10, uk_bit_b11; // unknown (unused ??)

          mask = ReadShort;
          view_ofs_z = mask & 0x0001 ? (float) ReadChar : 22.0;
          punchangle_x = mask & 0x0002 ? (float) ReadChar : 0.0;
          angles[0] = mask & 0x0004 ? (vec_t) ReadChar : 0.0;
          vel[0] = mask & 0x0020 ? (vec_t) ReadChar : 0.0;
          angles[1] = mask & 0x0008 ? (vec_t) ReadChar : 0.0;
          vel[1] = mask & 0x0040 ? (vec_t) ReadChar : 0.0;
          angles[2] = mask & 0x0010 ? (vec_t) ReadChar : 0.0;
          vel[2] = mask & 0x0080 ? (vec_t) ReadChar : 0.0;
          if (version<=1.06)
            items = mask & 0x0200 ? ReadLong : 0x4001;
          else
            items = ReadLong;
          uk_bit_b10 = mask & 0x0400 ? 1 : 0; // bit 10
          uk_bit_b11 = mask & 0x0800 ? 1 : 0; // bit 11
          weaponframe = mask & 0x1000 ? ReadByte : 0;
          armorvalue = mask & 0x2000 ? ReadByte : 0;
          weaponmodel = mask & 0x4000 ? ReadByte : 0;
          health = ReadShort;
          currentammo = ReadByte;
          ammo_shells = ReadByte;
          ammo_nails = ReadByte;
          ammo_rockets = ReadByte;
          ammo_cells = ReadByte;
          weapon = ReadByte;






  77..1177..  ssttooppssoouunndd


     ID 0x10


     ppuurrppoossee
        Stops a sound. I never found such a message in a DEM file.


     ppaarrssee rroouuttiinnee


          long uk_short;  // unknown (an index??)

          uk_short = ReadShort;






  77..1188..  uuppddaatteeccoolloorrss


     ID 0x11


     ppuurrppoossee
        Updates the colours of the specified player.
     vvaarriiaabblleess

        long player;
           is the internal player number (client 1 has player entity 0).

        long colors;
           is the combined colour of this player.

        long shirtcolor;
           is the colour of the shirt (0 <= shirtcolor <= 15).

        long pantscolor;
           is the colour of the pants (0 <= pantscolor <= 15).


     ppaarrssee rroouuttiinnee


          player = ReadByte;
          colors = ReadByte;
          shirtcolor = (colors>>4) & 0x0F;
          pantscolor = colors & 0x0F;






  77..1199..  ppaarrttiiccllee


     ID 0x12


     ppuurrppoossee
        This starts particles flying around. This happens, if a barrel
        explodes or blood particles fly after being hit by an axe,
        shells or nails.


     vvaarriiaabblleess

        vec3_t origin;
           is the origin of the particles.


        vec3_t vel;
           is the velocity of the particles.


        long color;
           is the colour of the particles (chunk 0, blood 73, barrel 75
           and thunderbolt 225).


        long count;
           is the number of the particles.



     ppaarrssee rroouuttiinnee





     for (i=0 ; i<3 ; i++) origin[i] = ReadCoord;
     for (i=0 ; i<3 ; i++) vel[i] = (vec_t) ReadChar * 0.0625;
     count = ReadByte;
     color = ReadByte;






  77..2200..  ddaammaaggee


     ID 0x13


     ppuurrppoossee
        Tells how severe was a hit and from which point it came.


     vvaarriiaabblleess

        long save;
           will be subtracted from the current armor.

        long take;
           will be subtracted from the current health.

        vec3_t origin;
           is the origin of the hit. It points to the weapon of a
           monster or player (not the origin of the monster entity) or
           it is (0,0,0) if the damage was caused by drowning or
           burning.


     ppaarrssee rroouuttiinnee


          save = ReadByte;
          take = ReadByte;
          for (i=0 ; i<3 ; i++) origin[i] = ReadCoord;






  77..2211..  ssppaawwnnssttaattiicc


     ID 0x14


     ppuurrppoossee
        This message creates a static entity and sets the internal
        default values.


     vvaarriiaabblleess


        long StaticEntityCount;
           is the number of already started static entities. The maximum
           number is 127.


        long default_modelindex;
           is the model number in the model-table.


        long default_frame;
           is the frame number of the model.


        long default_colormap;
           is the colormap number to display the model.


        long default_skin;
           is the skin number of the model.  This is used for things
           with different skins (like players or armors).


        vec3_t default_origin;
           is the origin of the entity.


        vec3_t default_angles;
           is the orientation of the entity.



     ppaarrssee rroouuttiinnee


          int data1, data2, data3;

          if (StaticEntityCount > 127) error("Too many static entities");
          StaticEntityCount++;
          default_modelindex = ReadByte;
          if (game == HEXENII) {
            default_modelindex |= ReadByte << 8;
          }
          default_frame = ReadByte;
          default_colormap = ReadByte;
          default_skin = ReadByte;
          if (game == HEXENII) {
            data1 = ReadByte; data2 = ReadByte; data3 = ReadByte;
          }
          for (i=0 ; i<3 ; i++) {
            default_origin[i] = ReadCoord;
            default_angles[i] = ReadAngle;
          }






  77..2222..  ssppaawwnnbbiinnaarryy


     ID 0x15


     ppuurrppoossee
        This is OBSOLETE. It should never occur in DEM files.


     ppaarrssee rroouuttiinnee


     error ("CL_ParseServerMessage: Illegible server message\n");






  77..2233..  ssppaawwnnbbaasseelliinnee


     ID 0x16


     ppuurrppoossee
        This message creates a dynamic entity and sets the internal
        default values.


     vvaarriiaabblleess


        long entity;
           is the number of the entity.


        long default_modelindex;
           is the model number in the model-table.


        long default_frame;
           is the frame number of the model.


        long default_colormap;
           is the colormap number to display the model.


        long default_skin;
           is the skin number of the model. This is used for things with
           different skins (like players or armors).


        vec3_t default_origin;
           is the origin of the entity.


        vec3_t default_angles;
           is the orientation of the entity.



     ppaarrssee rroouuttiinnee














     entity = ReadShort;
     if (entity > 449) error("CL_EntityNum: %i is an invalid number", entity);
     default_modelindex = ReadByte;
     if (game == HEXENII) {
       default_modelindex |= ReadByte << 8;
     }
     default_frame = ReadByte;
     default_colormap = ReadByte;
     default_skin = ReadByte;
     if (game == HEXENII) {
       data1 = ReadByte; data2 = ReadByte; data3 = ReadByte;
     }
     for (i=0 ; i<3 ; i++) {
       default_origin[i] = ReadCoord;
       default_angles[i] = ReadAngle;
     }






  77..2244..  tteemmpp__eennttiittyy


     ID 0x17


     ppuurrppoossee
        This message creates a temporary entity.


     vvaarriiaabblleess


        long entitytype;
           is the type of the temporary entity.  There are two kinds of
           temporary entities in Quake and three in Hexen II.
           TE_EXPLOSION2 and TE_BEAM was introduced with the Mission
           Pack # 2 (Quake version 1.08).

           ppooiinntt eennttiittyy
              is a small point like entity.

  value    QuakeC/HexenC      Quake purpose                    Hexen II purpose
      0    TE_SPIKE           unknown                          spike touch
      1    TE_SUPERSPIKE      superspike hits (spiketraps)     unknown (unused)
      2    TE_GUNSHOT         hit on the wall (Axe, Shotgun)   weapon hits the wall
      3    TE_EXPLOSION       grenade/missile explosion        general explosion
      4    TE_TAREXPLOSION    explosion of atarbaby            unknown (unused)
      7    TE_WIZSPIKE        wizard's hit                     wizspike touch
      8    TE_KNIGHTSPIKE     hell knight's shothit            knightspike touch
     10    TE_LAVASPLASH      Chthon awakes and fallsdead      unknown (unused)
     11    TE_TELEPORT        teleport end                     spawn of a monster
     12    TE_EXPLOSION2      other explosion                  unknown


                              point entities


           llaarrggee eennttiittyy
              is a 2 dimensional entity.





  value    QuakeC/HexenC    Quake purpose                 Hexen II purpose
      5    TE_LIGHTNING1    flash of theShambler          something with trap_lightning
      6    TE_LIGHTNING2    flash of theThunderbolt       unknown (unused)
      9    TE_LIGHTNING3    flash in e1m7 to killChthon   unknown (unused)
     13    TE_BEAM          grappling hook                unknown


                              line entities

      value    HexenC                 purpose
         25    TE_STREAM_CHAIN        chains of Staff of Set
         26    TE_STREAM_SUNSTAFF1    Lightbringer
         27    TE_STREAM_SUNSTAFF2    unknown (unused)
         28    TE_STREAM_LIGHTNING    Lighting from Eidolon
         29    TE_STREAM_COLORBEAM    attack of a Fallen Angel,Golem
         30    TE_STREAM_ICECHUNKS    Ice Mace
         31    TE_STREAM_GAZE         Medusa attack
         32    TE_STREAM_FAMINE       unknown (unused)


                         Hexen II stream entities
        long entity;
           is the entity which created the temporary entity.


        vec3_t origin;
           is the origin of the entity.


        vec3_t trace_endpos;
           is the destination of the large temporary entity.


        long tag_lflags;
           is a combined variable.


        long tag;
           is an internal number to count the currently flashing
           temporary entities.


        long lflags;
           is a flags collection.


        value    HexenC                purpose
         0x10    STREAM_ATTACHED       stream starts at theplayer
         0x20    STREAM_TRANSLUCENT    unknown (unused)


                          possible lflags values


        long duration;
           is the duration of the stream (was 1, 2 or 4).


        long color;
           is the colour of the temporary entity.


        long range;
           is the range for a TE_EXPLOSION2 explosion.

     QQuuaakkee ppaarrssee rroouuttiinnee


          entitytype = ReadByte;
          switch (entitytype) {
            case TE_SPIKE:
            case TE_SUPERSPIKE:
            case TE_GUNSHOT:
            case TE_EXPLOSION:
            case TE_TAREXPLOSION:
            case TE_WIZSPIKE:
            case TE_KNIGHT_SPIKE:
            case TE_LAVASPLASH:
            case TE_TELEPORT:
                   for (i=0 ; i<3 ; i++) org[i] = ReadCoord;
            break;
            case TE_LIGHTNING1:
            case TE_LIGHTNING2:
            case TE_LIGHTNING3:
            case TE_BEAM:
                   entity = ReadEntity;
                   for (i=0 ; i<3 ; i++) origin[i] = ReadCoord;
                   for (i=0 ; i<3 ; i++) trace_endpos[i] = ReadCoord;
            break;
            case TE_EXPLOSION2:
                   for (i=0 ; i<3 ; i++) origin[i] = ReadCoord;
                   color = ReadByte;
                   range = ReadRange;
            break;
            default:
              error("CL_ParseTEnt: bad type");
            break;
          }





     HHeexxeenn IIII ppaarrssee rroouuttiinnee



























     entitytype = ReadByte;
     switch (entitytype) {
       case TE_SPIKE:
       case TE_SUPERSPIKE:
       case TE_GUNSHOT:
       case TE_EXPLOSION:

       case TE_STREAM_CHAIN,TE_STREAM_SUNSTAFF1,TE_STREAM_SUNSTAFF2,
            TE_STREAM_LIGHTNING,TE_STREAM_COLORBEAM,TE_STREAM_ICECHUNKS,
            TE_STREAM_GAZE,TE_STREAM_FAMINE:
         switch (entitytype) {
           case TE_STREAM_COLORBEAM:
             entity = ReadEntity;
             tag_lflags = ReadByte;
             tag = tag_lflags & 0x0F;
             lflags = tag_flags & 0xF0;
             duration = ReadByte;
             color = ReadByte;
           break;
           case TE_STREAM_GAZE:
             tag_lflags = ReadByte;
             tag = tag_lflags & 0x0F;
             lflags = tag_flags & 0xF0;
             duration = ReadByte;
             entity = ReadEntity;
           break;
           default:
             entity = ReadEntity;
             tag_lflags = ReadByte;
             tag = tag_lflags & 0x0F;
             lflags = tag_flags & 0xF0;
             duration = ReadByte;
           break;
         }
         for (i=0 ; i<3 ; i++) origin[i] = ReadCoord;
         for (i=0 ; i<3 ; i++) trace_endpos[i] = ReadCoord;
       break;
       default:
         error("CL_ParserTEnt: bad type");
       break;
     }






  77..2255..  sseettppaauussee


     ID 0x18


     ppuurrppoossee
        Set the pause state. The time stands still but all entities get
        their update messages.


     vvaarriiaabblleess

        long pausestate;
           is 1 to start the pause and 0 to stop it.


     ppaarrssee rroouuttiinnee

     pausestate = ReadByte;
     if (pausestate) {
       // pause is on
     }
     else {
       // pause is off
     }






  77..2266..  ssiiggnnoonnuumm


     ID 0x19


     ppuurrppoossee
        This message selects the client state.


     vvaarriiaabblleess


        lloonngg ssiiggnnoonn;;
           is the client state.

  value    purpose
  1        after model/sound precache, start spawning entities (``prespawn'')
  2        start initialising light effects
  3        start 3D rendering


                              signon values



     ppaarrssee rroouuttiinnee


          signon = ReadByte;






  77..2277..  cceenntteerrpprriinntt


     ID 0x1A


     ppuurrppoossee
        Prints the specified text at the centre of the screen. There is
        only one text line with a maximum of 40 characters. To print
        more than this one line, use `\n' for a new line. Every text
        line (the first 40 characters) will be centred horizontally.

        All font specials are explained in section ``Quake font''.


     vvaarriiaabblleess

        char* text;
           is the text to be displayed.


     ppaarrssee rroouuttiinnee


          text = ReadString;






  77..2288..  kkiilllleeddmmoonnsstteerr


     ID 0x1B


     ppuurrppoossee
        This message indicates the death of a monster.


     vvaarriiaabblleess

        long killed_monsters;
           is the number of killed monsters.  It may be displayed with
           the console command _s_h_o_w_s_c_o_r_e_s.


     ppaarrssee rroouuttiinnee


          killed_monsters++;






  77..2299..  ffoouunnddsseeccrreett


     ID 0x1C


     ppuurrppoossee
        This message receives a client, if the player enters a secret
        area.  It comes usually with a print message.


     vvaarriiaabblleess

        long found_secrets;
           is the number of found secrets. It may be displayed with the
           console command _s_h_o_w_s_c_o_r_e_s.


     ppaarrssee rroouuttiinnee


          found_secrets++;



  77..3300..  ssppaawwnnssttaattiiccssoouunndd


     ID 0x1D


     ppuurrppoossee
        This message starts a static (ambient) sound not connected to an
        entity but to a position.


     vvaarriiaabblleess


        vec3_t origin;
           is the origin of the sound.


        long soundnum;
           is the sound number in the sound-table.


        float vol;
           is the volume (0.0 off, 1.0 max)


        float attenuation;
           is the attenuation of the sound.

  value    QuakeC         purpose
  0        ATTN_NONE      i. e. player's death sound doesn't get an attenuation
  1        ATTN_NORM      the normal attenuation
  2        ATTN_IDLE      attenuation for idle monsters
  3        ATTN_STATIC    attenuation for spawnstaticsound messages


                            Sound attenuation



     ppaarrssee rroouuttiinnee


          for (i=0 ; i<3 ; i++) origin[i] = ReadCoord;
          if (game==HEXENII)
            soundnum = ReadShort;
          else
            soundnum = ReadByte;
          vol = (float) ReadByte / 255.0;
          attenuation = (float) ReadByte / 64.0;






  77..3311..  iinntteerrmmiissssiioonn


     ID 0x1E


     ppuurrppoossee
        Displays the level end screen. Depending on the multi command in
        the serverinfo message this is either the single player summary
        screen or the multi player ranking screen.
     ppaarrssee rroouuttiinnee
        if (game==HexenII) { data = ReadByte; }



  77..3322..  ffiinnaallee


     ID 0x1F


     ppuurrppoossee
        Displays the episode end screen and some text.


     vvaarriiaabblleess

        char* text;
           is the episode end text.

     ppaarrssee rroouuttiinnee


          text = ReadString;






  77..3333..  ccddttrraacckk


     ID 0x20


     ppuurrppoossee
        This message selects the audio CD track numbers.


     vvaarriiaabblleess


        long fromtrack;
           is the start track.


        long totrack;
           is the last track. Both values are equal at the start of a
           game but become 2 and 3 at the end of an episode.



     ppaarrssee rroouuttiinnee


          fromtrack = ReadByte;
          totrack = ReadByte;








  77..3344..  sseellllssccrreeeenn


     ID 0x21


     ppuurrppoossee
        Displays the help and sell screen.


     ppaarrssee rroouuttiinnee
        none



  77..3355..  ppaarrttiiccllee22


     ID 0x22


     ppuurrppoossee
        Hexen II only. Unknown.


     ppaarrssee rroouuttiinnee
        unknown



  77..3366..  ccuuttsscceennee


     QQuuaakkee ID
        0x22 Hexen II ID0x23


     ppuurrppoossee
        This message appeared firstly with the Mission Pack #1 (Quake
        version 1.07). It is similar to ffiinnaallee as it displays an end
        screen and some text.


     vvaarriiaabblleess

        char* text;
           is the text.

     ppaarrssee rroouuttiinnee


          text = ReadString;






  77..3377..  mmiiddii__nnaammee


     ID 0x24


     ppuurrppoossee
        Hexen II only. Set the MIDI file name to play.
     vvaarriiaabblleess

        char* midifile;
           is MIDI file to play.

     ppaarrssee rroouuttiinnee


          midifile = ReadString;






  77..3388..  uuppddaatteeccllaassss


     ID 0x25


     ppuurrppoossee
        Hexen II only. Defines the character class of a player.


     vvaarriiaabblleess

        long player;
           is the player number (0 .. 15).

        long class;
           is the new character class for this player.


     ppaarrssee rroouuttiinnee


          player = ReadByte;
          class = ReadByte;






  77..3399..  ppaarrttiiccllee33


     ID 0x26


     ppuurrppoossee
        Hexen II only. Unknown (unused).


     ppaarrssee rroouuttiinnee
        unknown



  77..4400..  ppaarrttiiccllee44


     ID 0x27


     ppuurrppoossee
        Hexen II only. Used on morphing.


     vvaarriiaabblleess

        vec3_t origin;

        float radius;

        long color;

        long particletype;

               value    HexenC                      purpose
               0         PARTICLETYPE_STATIC        ??
               1         PARTICLETYPE_GRAV          ??
               2         PARTICLETYPE_FASTGRAV      ??
               3         PARTICLETYPE_SLOWGRAV      ??
               4         PARTICLETYPE_FIRE          ??
               5         PARTICLETYPE_EXPLODE       ??
               6         PARTICLETYPE_EXPLODE2      ??
               7         PARTICLETYPE_BLOB          ??
               8         PARTICLETYPE_BLOB2         ??
               9         PARTICLETYPE_RAIN          ??
               10        PARTICLETYPE_C_EXPLOSE     ??
               11        PARTICLETYPE_C_EXPLODE2    ??
               12        PARTICLETYPE_SPIT          ??
               13        PARTICLETYPE_FIREBALL      ??
               14        PARTICLETYPE_ICE           ??
               15        PARTICLETYPE_SPELL         ??


                      possible particletype values.


        long damage;


     ppaarrssee rroouuttiinnee
        unknown



  77..4411..  sseett__vviieeww__ffllaaggss


     ID 0x28


     ppuurrppoossee
        Hexen II only. Set some drawing falgs.


     vvaarriiaabblleess


        long drawflags;
           are some drawing flags.



     ppaarrssee rroouuttiinnee




                 value    HexenC                  purpose
                 0x01      MLS_FULLBRIGHT         ??
                 0x02      MLS_POWERMODE          ??
                 0x03      MLS_TORCH              ??
                 0x04      MLS_FIREFLICKER        ??
                 0x05      MLS_CRYSTALGOLEM       ??
                 0x07      MLS_ABSLIGHT           ??
                 0x08      SCALSE_TYPE_XYONLY     ??
                 0x10      SCALSE_TYPE_ZONLY      ??
                 0x20      SCALE_ORIGIN_BOTTOM    ??
                 0x40      SCALE_ORIGIN_TOP       ??
                 0x80      DRF_TRANSLUCENT        ??


                                Draw flags
     view_flags = ReadByte;






  77..4422..  cclleeaarr__vviieeww__ffllaaggss


     ID 0x29


     ppuurrppoossee
        Hexen II only. Unknown.


     vvaarriiaabblleess


        long view_flags;
           are some flags. ??FIXME??



     ppaarrssee rroouuttiinnee


          view_flags = ReadByte;






  77..4433..  ssttaarrtt__eeffffeecctt


     ID 0x2A


     ppuurrppoossee
        Hexen II only. Unknown.


     ppaarrssee rroouuttiinnee
        unknown



  77..4444..  eenndd__eeffffeecctt


     ID 0x2B


     ppuurrppoossee
        Hexen II only. Unknown.


     ppaarrssee rroouuttiinnee
        unknown



  77..4455..  ppllaaqquuee


     ID 0x2C


     ppuurrppoossee
        Hexen II only. Unknown.


     ppaarrssee rroouuttiinnee
        unknown



  77..4466..  ppaarrttiiccllee__eexxpplloossiioonn


     ID 0x2D


     ppuurrppoossee
        Hexen II only. Unknown.


     ppaarrssee rroouuttiinnee
        unknown



  77..4477..  sseett__vviieeww__ttiinntt


     ID 0x2E


     ppuurrppoossee
        Hexen II only. Unknown.


     ppaarrssee rroouuttiinnee
        unknown



  77..4488..  rreeffeerreennccee


     ID 0x2F


     ppuurrppoossee
        Hexen II only. Unknown.


     ppaarrssee rroouuttiinnee
        unknown



  77..4499..  cclleeaarr__eeddiiccttss


     ID 0x30


     ppuurrppoossee
        Hexen II only. Clears something of an edict. ??FIXME??  It looks
        not totally right.


     vvaarriiaabblleess

        long edict;
           is the edict.


     ppaarrssee rroouuttiinnee


          edict = ReadByte;






  77..5500..  uuppddaattee__iinnvv


     ID 0x31


     ppuurrppoossee
        Hexen II only. Unknown.


     ppaarrssee rroouuttiinnee
        unknown



  77..5511..  uuppddaatteeeennttiittyy


     ID >=0x80


     ppuurrppoossee
        This is the general entity update message. For every entity
        (potentially) in sight the server sends such a message. The
        message contains only the values, which changed since the
        creation (or spawning) of the entity (with spawnstatic,
        spawnbaseline).



     vvaarriiaabblleess

        long mask;
           is a bit mask to reduce the amount of data to be sent. Only
           the changed parts (with respect to the initial state) get
           their bit and their values.


        long entity;
           is the entity number.


        long modelindex;
           is the model number in the model-table.


        long frame;
           is the frame number of the model.


        long colormap;
           is the colormap number to display the model.


        long skin;
           is the skin number of the model. This is used for things with
           different skins (like players or armors).


        long effects;
           contains a bit mask for special entity effects.

  bit    value    QuakeC            purpose
  0      0x01     EF_BRIGHTFIELD    not used
  1      0x02     EF_MUZZLEFLASH    attack state of most entities
  2      0x04     EF_BRIGHTLIGHT    not used
  3      0x08     EF_DIMLIGHT       Quad Damage, Pentagram of Protection, Enforcer's laser


                           Quake effects values


  bit    value    HexenC            purpose
  0      0x01     EF_BRIGHTFIELD    not used
  1      0x02     EF_MUZZLEFLASH    attack state of most entities
  2      0x04     EF_BRIGHTLIGHT    not used
  ?      0x06     EF_TORCHLIGHT     ??
  3      0x08     EF_DIMLIGHT       Quad Damage, Pentagram of Protection, Enforcer's laser
  4      0x10     EF_DARKLIGHT      ??
  5      0x20     EF_DARKFIELD      ??
  6      0x40     EF_LIGHT          ??
  7      0x80     EF_NODRAW         ??


                         Hexen II effects values


        vec3_t origin;
           is the origin of the entity.


        vec3_t angles;
           is the orientation of the entity.



        long new;
           is 1 if the entity gets some really new values (modelindex
           etc.)



     ppaarrssee rroouuttiinnee


          mask = ID & 0x07F;
          if (mask & 0x0001) mask |= (ReadByte) << 8;
          entity = mask & 0x4000 ? ReadShort : ReadByte;
          modelindex = mask & 0x0400 ? ReadByte : default_modelindex;
          frame = mask & 0x0040 ? ReadByte : default_frame;
          colormap = mask & 0x0800 ? ReadByte : default_colormap;
          skin = mask & 0x1000 ? ReadByte : default_skin;
          effects = mask & 0x2000 ? ReadByte : default_effects;
          origin[0] = mask & 0x0002 ? ReadCoord : default_origin[0];
          angles[0] = mask & 0x0100 ? ReadAngle : default_angles[0];
          origin[1] = mask & 0x0004 ? ReadCoord : default_origin[1];
          angles[1] = mask & 0x0010 ? ReadAngle : default_angles[1];
          origin[2] = mask & 0x0008 ? ReadCoord : default_origin[2];
          angles[2] = mask & 0x0200 ? ReadAngle : default_angles[2];
          new = mask & 0x0020 ? 1 : 0;






  88..  VVeerrssiioonn HHiissttoorryy aanndd AAcckknnoowwlleeddggeemmeennttss


     00..00..11,, 77 JJuullyy,, 11999966

     +o  First version (working paper) completed.

     +o  Many thanks to Steffen Winterfeldt (Steffen.Winterfeldt@itp.uni-
        leipzig.de) for his unbelievable reverse engineering work. He
        worked out all the structure information.


     00..00..22,, 88 JJuullyy,, 11999966

     +o  Stupid spawnstatic error corrected.


     00..00..33,, 99 JJuullyy,, 11999966

     +o  I finally understood the multi player recordings.

     +o  More info on sound, particle, spawnstaticsound.


     00..00..44,, 1144 JJuullyy,, 11999966

     +o  Many new values decoded.

     +o  Tables for weapons and status line.

     +o  More general remarks.


     00..00..55,, 1166 JJuullyy,, 11999966


     +o  Many new values decoded.

     +o  Variables entry in the message description.

     +o  Life-cycles.


     11..00..00,, 2288 JJuullyy,, 11999966

     +o  QuakeC source is published. Many things get their right names
        now.

     +o  Life-cycles for multi player.

     +o  This version is the first reliable one.


     11..00..11,, 2299 JJuullyy,, 11999966

     +o  Almost all identifier names match now the QuakeC names.

     +o  Grammar check by SW.


     11..00..22,, 3300 JJuullyy,, 11999966

     +o  Serious semantic mistake corrected (spawn/update).

     +o  Some minor layout improvements.


     11..00..33,, 1177 NNoovveemmbbeerr,, 11999966

     +o  I (finally) checked registered Quake: nothing special.

     +o  effects and punchangle_x get their proper names.


     11..00..44,, 88 FFeebbrruuaarryy,, 11999977

     +o  Info on Quake font included.

     +o  CD track header format finally corrected.

     +o  Info on dproxy and FAQ-Proxy included.


     11..00..55,, 2288 JJuullyy,, 11999977

     +o  Info on 1.06/1.07 problem included.

     +o  Source is SGML-Tools 0.99.10 based.


     11..00..66,, 1122 MMaarrcchh,, 11999988

     +o  SGML-Tools 1.0.5 used.

     +o  First few Hexen II infos.

     +o  New home is PlanetQuake.

     +o  CD track section rewritten.

     +o  Thanks to Stefan Schwoon () (ssch0098@rz.uni-hildesheim.de) for
        his hints on some 1.07 and 1.08 changes.


































































