The easiest way to explain a message is to give a short
C like program fragment to parse such a message. Each message can be
described by its ID
or its name.
ID
0x00
Something is bad. This message should never appear.
none
ID
0x01
No operation.
none
ID
0x02
Disconnect from the server. Stops the game.
none
ID
0x03
Updates directly any values in the player state.
long index;
is the index in the playerstate
array.
Possible indices are:
Normal DEM files use index 11 to 14 only.
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 found_monsters
15 ??? . . . 31 ???
long value;
is the new value.
long playerstate[32];
is the array to describe the player state. Many other messages change (indirectly) some values in it.
index = ReadByte;
if (index > 0x1F) {
error("svc_updatestat: %i is invalid", index);
}
value = ReadLong;
playerstate[index] = value;
ID
0x04
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.
long serverprotocol;
is the version number of the
server. It should be 0x0F
.
serverprotocol = ReadLong;
if (serverprotocol != 0x0F) {
error("CL_ParseServerMessage: Server is protocol %i instead of %i\n",
serverprotocol, 0x0F);
}
ID
0x05
Sets the camera position to the origin of this entity.
long entity;
is the entity with the camera.
entity = ReadShort;
ID
0x06
This message starts the play of a sound at a specific point.
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. Possible values (for all kind of sounds) are:
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 idle monsters get this attenuation 3 ATTN_STATIC spawnstaticsound messages get this attenuation
long channel;
is the sound channel. There are 8 possible sound channels in Quake but the game uses 5 only. Possible values are:
value QuakeC purpose 0 CHAN_AUTO big powerups 1 CHAN_WEAPON weapon use sounds 2 CHAN_VOICE pain calls 3 CHAN_ITEM item get sounds 4 CHAN_BODY jump and fall sounds
long entity;
is the entity which caused the sound.
long soundnum;
is the sound number in the sound-table.
ve3_t origin;
is the origin of the sound.
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;
ID
0x07
This is the time stamp of a block of messages. A time message should appear in every block.
float time;
is the time in seconds from the beginning of the current level (not of the recording).
time = ReadFloat;
ID
0x08
The client prints the text in the top left corner of the screen. The text appears on the console as well.
char* text;
is the text to be displayed. The text contains something like ``You get 5 shells''. There are special non-printable characters in the text: ``\n'' means new line and ``\002'' changes the color of the following text. The value 2 may be a color number but I'm not sure about this.
text = ReadString;
ID
0x09
The client transfers the text to the console and runs it.
char* text;
is the command, which the client has to execute. These are commands like ``bf\n'' to make a flash after you take something.
text = ReadString;
ID
0x0A
This message set the camera orientation.
vec3_t angles;
is the new camera orientation.
for (i=0 ; i<3 ; i++) angles[i] = ReadAngle;
ID
0x0B
This message is usually one of the first messages after a level start. It loads model and sound files.
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[256];
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.
long nummodels;
is the number of models in the model-table.
char* precache_sounds[256];
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.
long numsounds;
is the number of sounds in the sound-table.
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]);
ID
0x0C
This message defines a light style.
long style;
is the light style number.
char* string;
is a string of letters ``a'' .. ``z'', where ``a'' means black and ``z'' white. All known effects from nervous flashing: ``az'' to slow dimming: ``zyxwvu ... edcba'' can so be described.
style = ReadByte;
string = ReadString;
ID
0x0D
This message sets the player name.
variables
long player;
is the internal player number (client 1 is player number 0).
char* netname;
is the new player name.
player = ReadByte;
netname = ReadString;
ID
0x0E
This message updates the frag count of a specific player.
long player;
is the internal player number (client 1 is player number 0).
long frags;
is the new frag count for this player.
player = ReadByte;
frags = ReadShort;
ID
0x0F
This message updates the status line and the camera coordinates.
long mask;
is a bitmask to show which values are coming.
float view_ofs_z;
is an additional view offset because the camera is at the origin of the entitiy and not at the eyes (is -8 if the player is death).
float ang_ofs_1;
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 | Supernailgun |
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 | Flechettes 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 | unknwon | Rune 3 |
31 | 0x80000000 | unknown | Rune 4 |
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 Supernailgun 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)
long uk_bit_b10, uk_bit_b11; // unknown (unused ??)
mask = ReadShort;
view_ofs_z = mask & 0x0001 ? (float) ReadChar : 22.0;
ang_ofs_1 = 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;
items = mask & 0x0200 ? ReadLong : 0x4001;
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;
ID
0x10
Stops a sound. I never found such a message in a DEM file.
long uk_short; // unknown (an index??)
uk_short = ReadShort;
ID
0x11
Updates the colors of the specified player.
long player;
is the internal player number (client 1 is player 0).
long colors;
is the combined color of this player.
long shirtcolor;
is the color of the shirt
(0 <= shirtcolor
<= 3).
long pantscolor;
is the color of the pants
(0 <= pantscolor
<= 3).
player = ReadByte;
colors = ReadByte;
shirtcolor = (colors>>4) & 0x0F;
pantscolor = colors & 0x0F;
ID
0x12
This starts particles flying around. This happens, if a barrel explodes or blood particles fly after being hit by an axe, shells or nails.
vec3_t origin;
is the origin of the particles.
vec3_t vel;
is the velocity of the particles.
long color;
is the color of the particles (blood is 73).
long count;
is the number of the particles
for (i=0 ; i<3 ; i++) origin[i] = ReadCoord;
for (i=0 ; i<3 ; i++) vel[i] = (vec_t) ReadChar * 0.0625;
color = ReadByte;
count = ReadByte;
ID
0x13
Tells how severe was a hit and from which points it came.
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.
save = ReadByte;
take = ReadByte;
for (i=0 ; i<3 ; i++) origin[i] = ReadCoord;
ID
0x14
This message creates a static entity and sets the internal default values.
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.
if (StaticEntityCount > 127) error("Too many static entities");
StaticEntityCount++;
default_modelindex = ReadByte;
default_frame = ReadByte;
default_colormap = ReadByte;
default_skin = ReadByte;
for (i=0 ; i<3 ; i++) {
default_origin[i] = ReadCoord;
default_angles[i] = ReadAngle;
}
ID
0x15
This is OBSOLETE. It should never occur in DEM files.
error ("CL_ParseServerMessage: Illegible server message\n");
ID
0x16
This message creates a dynamic entity and sets the internal default values.
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.
entity = ReadShort;
if (entity > 449) error("CL_EntityNum: %i is an invalid number", entity);
default_modelindex = ReadByte;
default_frame = ReadByte;
default_colormap = ReadByte;
default_skin = ReadByte;
for (i=0 ; i<3 ; i++) {
default_origin[i] = ReadCoord;
default_angles[i] = ReadAngle;
}
ID
0x17
This message creates a temporary entity.
long entitytype;
is the type of the temporary entity. There are two kinds of temporary entities:
is a small point like entity.
value | QuakeC | purpose |
0 | TE_SPIKE | unknown |
1 | TE_SUPERSPIKE | superspike hits (spike traps) |
2 | TE_GUNSHOT | hit on the wall (Axe, Shotgun) |
3 | TE_EXPLOSION | grenade/missile explosion |
4 | TE_TAREXPLOSION | explosion of a tarbaby |
7 | TE_WIZSPIKE | wizard's hit |
8 | TE_KNIGHTSPIKE | hell knight's shot hit |
10 | TE_LAVASPLASH | Chthon awakes and falls dead |
11 | TE_TELEPORT | teleport end |
is a 2 dimensional entity.
value QuakeC purpose 5 TE_LIGHTNING1 flash of the Shambler 6 TE_LIGHTNING2 flash of the Thunderbolt 9 TE_LIGHTNING3 flash in e1m7 to kill Chthon
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.
entitytype = ReadByte;
if (entitytype > 11)
error("CL_ParserTEnt: bad type");
switch (entitytype) {
case 0,1,2,3,4,7,8,10,11:
for (i=0 ; i<3 ; i++) org[i] = ReadCoord;
break;
case 5,6,9:
entity = ReadEntity;
for (i=0 ; i<3 ; i++) origin[i] = ReadCoord;
for (i=0 ; i<3 ; i++) trace_endpos[i] = ReadCoord;
break;
}
ID
0x18
Set the pause state. The time stands still but all entities get their update messages.
long pausestate;
is 1 to start the pause and 0 to stop it.
pausestate = ReadByte;
if (pausestate) {
// pause is on
}
else {
// pause is off
}
ID
0x19
This message selects the client state.
is the client state. The possible values are:
value purpose 1 after model/sound precache, start spawning entities (``prespawn'') 2 start initializing light effects 3 start 3D rendering
signon = ReadByte;
ID
0x1A
Prints the specified text at the center of the screen.
char* text;
is the text to be displayed.
text = ReadString;
ID
0x1B
This message indicates the death of a monster.
long killed_monsters;
is the number of killed monsters.
It may be displayed with the console command showscores
.
killed_mosters++;
ID
0x1C
This message receives a client, if the player enters a secret area.
It comes usually with a print
message.
long found_secrets;
is the number of found secrets. It may
be displayed with the console command showscores
.
found_secrets++;
ID
0x1D
This message starts a static (ambient) sound not connected to an entity but to a position.
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. Possible values (for all kind of sounds) are:
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 idle monsters get this attenuation 3 ATTN_STATIC all spawnstaticsound messages get thisattenuation
for (i=0 ; i<3 ; i++) origin[i] = ReadCoord;
soundnum = ReadByte;
vol = (float) ReadByte / 255.0;
attenuation = (float) ReadByte / 64.0;
ID
0x1E
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.
none
ID
0x1F
Displays the episode end screen and some text.
char* text;
is the episode end text.
text = ReadString;
ID
0x20
This message selects the audio CD track numbers.
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.
fromtrack = ReadByte;
totrack = ReadByte;
ID
0x21
Displays the help and sell screen.
none
ID
>=0x80
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).
long mask;
is a bit mask to reduce the amount of data to be sent. Only the changed parts 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 attack_state;
shows how the entity attacks. I'm not really sure about the explanation because I found only the values 0 and 2 in DEM files. The possible values are:
value QuakeC purpose 0 none don't attack 1 AS_STRAIGHT straight shot 2 AS_SLIDING move to a side 3 AS_MELEE single combat (dog, ogre) 4 AS_MISSILE shooting attack
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.)
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;
attack_state = mask & 0x2000 ? ReadByte : default_attack_state;
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;