]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - cl_main.c
qw support is 99% working
[xonotic/darkplaces.git] / cl_main.c
index 3151111e052ae138bc2e670d05a7d35d5ef4b7a3..46db360763b6ecc578ec564065e91d1cfb90ac2a 100644 (file)
--- a/cl_main.c
+++ b/cl_main.c
@@ -29,46 +29,48 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 // we need to declare some mouse variables here, because the menu system
 // references them even when on a unix system.
 
-cvar_t csqc_progname = {0, "csqc_progname","csprogs.dat"};     //[515]: csqc crc check and right csprogs name according to progs.dat
-cvar_t csqc_progcrc = {CVAR_READONLY, "csqc_progcrc","0"};
+cvar_t csqc_progname = {0, "csqc_progname","csprogs.dat","name of csprogs.dat file to load"};  //[515]: csqc crc check and right csprogs name according to progs.dat
+cvar_t csqc_progcrc = {CVAR_READONLY, "csqc_progcrc","0","CRC of csprogs.dat file to load"};
 
-cvar_t cl_shownet = {0, "cl_shownet","0"};
-cvar_t cl_nolerp = {0, "cl_nolerp", "0"};
+cvar_t cl_shownet = {0, "cl_shownet","0","1 = print packet size, 2 = print packet message list"};
+cvar_t cl_nolerp = {0, "cl_nolerp", "0","network update smoothing"};
 
-cvar_t cl_itembobheight = {0, "cl_itembobheight", "0"}; // try 8
-cvar_t cl_itembobspeed = {0, "cl_itembobspeed", "0.5"};
+cvar_t cl_itembobheight = {0, "cl_itembobheight", "0","how much items bob up and down (try 8)"};
+cvar_t cl_itembobspeed = {0, "cl_itembobspeed", "0.5","how frequently items bob up and down"};
 
-cvar_t lookspring = {CVAR_SAVE, "lookspring","0"};
-cvar_t lookstrafe = {CVAR_SAVE, "lookstrafe","0"};
-cvar_t sensitivity = {CVAR_SAVE, "sensitivity","3", 1, 30};
+cvar_t lookspring = {CVAR_SAVE, "lookspring","0","returns pitch to level with the floor when no longer holding a pitch key"};
+cvar_t lookstrafe = {CVAR_SAVE, "lookstrafe","0","move instead of turning"};
+cvar_t sensitivity = {CVAR_SAVE, "sensitivity","3","mouse speed multiplier"};
 
-cvar_t m_pitch = {CVAR_SAVE, "m_pitch","0.022"};
-cvar_t m_yaw = {CVAR_SAVE, "m_yaw","0.022"};
-cvar_t m_forward = {CVAR_SAVE, "m_forward","1"};
-cvar_t m_side = {CVAR_SAVE, "m_side","0.8"};
+cvar_t m_pitch = {CVAR_SAVE, "m_pitch","0.022","mouse pitch speed multiplier"};
+cvar_t m_yaw = {CVAR_SAVE, "m_yaw","0.022","mouse yaw speed multiplier"};
+cvar_t m_forward = {CVAR_SAVE, "m_forward","1","mouse forward speed multiplier"};
+cvar_t m_side = {CVAR_SAVE, "m_side","0.8","mouse side speed multiplier"};
 
-cvar_t freelook = {CVAR_SAVE, "freelook", "1"};
+cvar_t freelook = {CVAR_SAVE, "freelook", "1","mouse controls pitch instead of forward/back"};
 
-cvar_t r_draweffects = {0, "r_draweffects", "1"};
+cvar_t r_draweffects = {0, "r_draweffects", "1","renders temporary sprite effects"};
 
-cvar_t cl_explosions_alpha_start = {CVAR_SAVE, "cl_explosions_alpha_start", "1.5"};
-cvar_t cl_explosions_alpha_end = {CVAR_SAVE, "cl_explosions_alpha_end", "0"};
-cvar_t cl_explosions_size_start = {CVAR_SAVE, "cl_explosions_size_start", "16"};
-cvar_t cl_explosions_size_end = {CVAR_SAVE, "cl_explosions_size_end", "128"};
-cvar_t cl_explosions_lifetime = {CVAR_SAVE, "cl_explosions_lifetime", "0.5"};
+cvar_t cl_explosions_alpha_start = {CVAR_SAVE, "cl_explosions_alpha_start", "1.5","starting alpha of an explosion shell"};
+cvar_t cl_explosions_alpha_end = {CVAR_SAVE, "cl_explosions_alpha_end", "0","end alpha of an explosion shell (just before it disappears)"};
+cvar_t cl_explosions_size_start = {CVAR_SAVE, "cl_explosions_size_start", "16","starting size of an explosion shell"};
+cvar_t cl_explosions_size_end = {CVAR_SAVE, "cl_explosions_size_end", "128","ending alpha of an explosion shell (just before it disappears)"};
+cvar_t cl_explosions_lifetime = {CVAR_SAVE, "cl_explosions_lifetime", "0.5","how long an explosion shell lasts"};
 
-cvar_t cl_stainmaps = {CVAR_SAVE, "cl_stainmaps", "1"};
-cvar_t cl_stainmaps_clearonload = {CVAR_SAVE, "cl_stainmaps_clearonload", "1"};
+cvar_t cl_stainmaps = {CVAR_SAVE, "cl_stainmaps", "1","stains lightmaps, much faster than decals but blurred"};
+cvar_t cl_stainmaps_clearonload = {CVAR_SAVE, "cl_stainmaps_clearonload", "1","clear stainmaps on map restart"};
 
-cvar_t cl_beams_polygons = {CVAR_SAVE, "cl_beams_polygons", "1"};
-cvar_t cl_beams_relative = {CVAR_SAVE, "cl_beams_relative", "1"};
-cvar_t cl_beams_lightatend = {CVAR_SAVE, "cl_beams_lightatend", "0"};
+cvar_t cl_beams_polygons = {CVAR_SAVE, "cl_beams_polygons", "1","use beam polygons instead of models"};
+cvar_t cl_beams_relative = {CVAR_SAVE, "cl_beams_relative", "1","beams are relative to owner (smooth sweeps)"};
+cvar_t cl_beams_lightatend = {CVAR_SAVE, "cl_beams_lightatend", "0","make a light at the end of the beam"};
 
-cvar_t cl_noplayershadow = {CVAR_SAVE, "cl_noplayershadow", "0"};
+cvar_t cl_noplayershadow = {CVAR_SAVE, "cl_noplayershadow", "0","hide player shadow"};
 
-cvar_t cl_prydoncursor = {0, "cl_prydoncursor", "0"};
+cvar_t qport = {0, "qport", "0", "identification key for playing on qw servers (allows you to maintain a connection to a quakeworld server even if your port changes)"};
 
-cvar_t cl_deathnoviewmodel = {0, "cl_deathnoviewmodel", "1"};
+cvar_t cl_prydoncursor = {0, "cl_prydoncursor", "0", "enables a mouse pointer which is able to click on entities in the world, useful for point and click mods, see PRYDON_CLIENTCURSOR extension in dpextensions.qc"};
+
+cvar_t cl_deathnoviewmodel = {0, "cl_deathnoviewmodel", "1", "hides gun model when dead"};
 
 vec3_t cl_playerstandmins;
 vec3_t cl_playerstandmaxs;
@@ -122,6 +124,7 @@ CL_ClearState
 void CL_ClearState(void)
 {
        int i;
+       entity_t *ent;
 
        if (cl_entities) Mem_Free(cl_entities);cl_entities = NULL;
        if (cl_csqcentities) Mem_Free(cl_csqcentities);cl_csqcentities = NULL;  //[515]: csqc
@@ -136,6 +139,7 @@ void CL_ClearState(void)
        if (cl_brushmodel_entities) Mem_Free(cl_brushmodel_entities);cl_brushmodel_entities = NULL;
        if (cl.entitydatabase) EntityFrame_FreeDatabase(cl.entitydatabase);cl.entitydatabase = NULL;
        if (cl.entitydatabase4) EntityFrame4_FreeDatabase(cl.entitydatabase4);cl.entitydatabase4 = NULL;
+       if (cl.entitydatabaseqw) EntityFrameQW_FreeDatabase(cl.entitydatabaseqw);cl.entitydatabaseqw = NULL;
        if (cl.scores) Mem_Free(cl.scores);cl.scores = NULL;
 
        if (!sv.active)
@@ -143,11 +147,12 @@ void CL_ClearState(void)
 
 // wipe the entire cl structure
        memset (&cl, 0, sizeof(cl));
+
+       S_StopAllSounds();
+
        // reset the view zoom interpolation
        cl.mviewzoom[0] = cl.mviewzoom[1] = 1;
 
-       SZ_Clear (&cls.message);
-
        cl_num_entities = 0;
        cl_num_csqcentities = 0;        //[515]: csqc
        cl_num_static_entities = 0;
@@ -213,6 +218,27 @@ void CL_ClearState(void)
                VectorSet(cl_playercrouchmaxs, 16, 16, 24);
        }
 
+       // disable until we get textures for it
+       R_ResetSkyBox();
+
+       ent = &cl_entities[0];
+       // entire entity array was cleared, so just fill in a few fields
+       ent->state_current.active = true;
+       ent->render.model = cl.worldmodel = NULL; // no world model yet
+       ent->render.scale = 1; // some of the renderer still relies on scale
+       ent->render.alpha = 1;
+       ent->render.colormap = -1; // no special coloring
+       ent->render.flags = RENDER_SHADOW | RENDER_LIGHT;
+       Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, 0, 0, 0, 0, 0, 0, 1);
+       Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
+       CL_BoundingBoxForEntity(&ent->render);
+
+       // noclip is turned off at start
+       noclip_anglehack = false;
+
+       // mark all frames invalid for delta
+       memset(cl.qw_deltasequence, -1, sizeof(cl.qw_deltasequence));
+
        CL_Screen_NewMap();
        CL_Particles_Clear();
        CL_CGVM_Clear();
@@ -302,14 +328,30 @@ void CL_Disconnect(void)
                CL_StopPlayback();
        else if (cls.netcon)
        {
+               sizebuf_t buf;
+               unsigned char bufdata[8];
                if (cls.demorecording)
                        CL_Stop_f();
 
-               Con_DPrint("Sending clc_disconnect\n");
-               SZ_Clear(&cls.message);
-               MSG_WriteByte(&cls.message, clc_disconnect);
-               NetConn_SendUnreliableMessage(cls.netcon, &cls.message);
-               SZ_Clear(&cls.message);
+               // send disconnect message 3 times to improve chances of server
+               // receiving it (but it still fails sometimes)
+               memset(&buf, 0, sizeof(buf));
+               buf.data = bufdata;
+               buf.maxsize = sizeof(bufdata);
+               if (cls.protocol == PROTOCOL_QUAKEWORLD)
+               {
+                       Con_DPrint("Sending drop command\n");
+                       MSG_WriteByte(&buf, qw_clc_stringcmd);
+                       MSG_WriteString(&buf, "drop");
+               }
+               else
+               {
+                       Con_DPrint("Sending clc_disconnect\n");
+                       MSG_WriteByte(&buf, clc_disconnect);
+               }
+               NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol);
+               NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol);
+               NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol);
                NetConn_Close(cls.netcon);
                cls.netcon = NULL;
        }
@@ -323,7 +365,7 @@ void CL_Disconnect_f(void)
 {
        CL_Disconnect ();
        if (sv.active)
-               Host_ShutdownServer (false);
+               Host_ShutdownServer ();
 }
 
 
@@ -348,6 +390,9 @@ void CL_EstablishConnection(const char *host)
        // stop demo loop in case this fails
        CL_Disconnect();
 
+       // make sure the client ports are open before attempting to connect
+       NetConn_UpdateSockets();
+
        // run a network frame
        //NetConn_ClientFrame();SV_VM_Begin();NetConn_ServerFrame();SV_VM_End();
 
@@ -649,7 +694,7 @@ void CL_UpdateLights(void)
        f = cl.time * 10;
        i = (int)floor(f);
        frac = f - i;
-       for (j = 0;j < MAX_LIGHTSTYLES;j++)
+       for (j = 0;j < cl_max_lightstyle;j++)
        {
                if (!cl_lightstyle || !cl_lightstyle[j].length)
                {
@@ -664,6 +709,61 @@ void CL_UpdateLights(void)
        }
 }
 
+void CL_AddQWCTFFlagModel(entity_t *player, int skin)
+{
+       float f;
+       entity_t *flag;
+       matrix4x4_t flagmatrix;
+
+       // this code taken from QuakeWorld
+       f = 14;
+       if (player->render.frame2 >= 29 && player->render.frame2 <= 40)
+       {
+               if (player->render.frame2 >= 29 && player->render.frame2 <= 34)
+               { //axpain
+                       if      (player->render.frame2 == 29) f = f + 2;
+                       else if (player->render.frame2 == 30) f = f + 8;
+                       else if (player->render.frame2 == 31) f = f + 12;
+                       else if (player->render.frame2 == 32) f = f + 11;
+                       else if (player->render.frame2 == 33) f = f + 10;
+                       else if (player->render.frame2 == 34) f = f + 4;
+               }
+               else if (player->render.frame2 >= 35 && player->render.frame2 <= 40)
+               { // pain
+                       if      (player->render.frame2 == 35) f = f + 2;
+                       else if (player->render.frame2 == 36) f = f + 10;
+                       else if (player->render.frame2 == 37) f = f + 10;
+                       else if (player->render.frame2 == 38) f = f + 8;
+                       else if (player->render.frame2 == 39) f = f + 4;
+                       else if (player->render.frame2 == 40) f = f + 2;
+               }
+       }
+       else if (player->render.frame2 >= 103 && player->render.frame2 <= 118)
+       {
+               if      (player->render.frame2 >= 103 && player->render.frame2 <= 104) f = f + 6;  //nailattack
+               else if (player->render.frame2 >= 105 && player->render.frame2 <= 106) f = f + 6;  //light
+               else if (player->render.frame2 >= 107 && player->render.frame2 <= 112) f = f + 7;  //rocketattack
+               else if (player->render.frame2 >= 112 && player->render.frame2 <= 118) f = f + 7;  //shotattack
+       }
+       // end of code taken from QuakeWorld
+
+       flag = CL_NewTempEntity();
+       if (!flag)
+               return;
+
+       flag->render.model = cl.model_precache[cl.qw_modelindex_flag];
+       flag->render.skinnum = skin;
+       flag->render.colormap = -1; // no special coloring
+       flag->render.alpha = 1;
+       VectorSet(flag->render.colormod, 1, 1, 1);
+       // attach the flag to the player matrix
+       Matrix4x4_CreateFromQuakeEntity(&flagmatrix, -f, -22, 0, 0, 0, -45, 1);
+       Matrix4x4_Concat(&flag->render.matrix, &player->render.matrix, &flagmatrix);
+       Matrix4x4_Invert_Simple(&flag->render.inversematrix, &flag->render.matrix);
+       R_LerpAnimation(&flag->render);
+       CL_BoundingBoxForEntity(&flag->render);
+}
+
 #define MAXVIEWMODELS 32
 entity_t *viewmodels[MAXVIEWMODELS];
 int numviewmodels;
@@ -709,14 +809,14 @@ void CL_LinkNetworkEntity(entity_t *e)
                        e->render.colormap = e->state_current.colormap;
                        cb = (e->render.colormap & 0xF) << 4;cb += (cb >= 128 && cb < 224) ? 4 : 12;
                        cbcolor = (unsigned char *) (&palette_complete[cb]);
-                       e->render.colormap_pantscolor[0] = cbcolor[0] * (1.0f / 255.0f) * e->render.colormod[0];
-                       e->render.colormap_pantscolor[1] = cbcolor[1] * (1.0f / 255.0f) * e->render.colormod[1];
-                       e->render.colormap_pantscolor[2] = cbcolor[2] * (1.0f / 255.0f) * e->render.colormod[2];
+                       e->render.colormap_pantscolor[0] = cbcolor[0] * (1.0f / 255.0f);
+                       e->render.colormap_pantscolor[1] = cbcolor[1] * (1.0f / 255.0f);
+                       e->render.colormap_pantscolor[2] = cbcolor[2] * (1.0f / 255.0f);
                        cb = (e->render.colormap & 0xF0);cb += (cb >= 128 && cb < 224) ? 4 : 12;
                        cbcolor = (unsigned char *) (&palette_complete[cb]);
-                       e->render.colormap_shirtcolor[0] = cbcolor[0] * (1.0f / 255.0f) * e->render.colormod[0];
-                       e->render.colormap_shirtcolor[1] = cbcolor[1] * (1.0f / 255.0f) * e->render.colormod[1];
-                       e->render.colormap_shirtcolor[2] = cbcolor[2] * (1.0f / 255.0f) * e->render.colormod[2];
+                       e->render.colormap_shirtcolor[0] = cbcolor[0] * (1.0f / 255.0f);
+                       e->render.colormap_shirtcolor[1] = cbcolor[1] * (1.0f / 255.0f);
+                       e->render.colormap_shirtcolor[2] = cbcolor[2] * (1.0f / 255.0f);
                }
                else if (e->state_current.colormap && cl.scores != NULL)
                {
@@ -725,14 +825,14 @@ void CL_LinkNetworkEntity(entity_t *e)
                        e->render.colormap = cl.scores[e->state_current.colormap - 1].colors; // color it
                        cb = (e->render.colormap & 0xF) << 4;cb += (cb >= 128 && cb < 224) ? 4 : 12;
                        cbcolor = (unsigned char *) (&palette_complete[cb]);
-                       e->render.colormap_pantscolor[0] = cbcolor[0] * (1.0f / 255.0f) * e->render.colormod[0];
-                       e->render.colormap_pantscolor[1] = cbcolor[1] * (1.0f / 255.0f) * e->render.colormod[1];
-                       e->render.colormap_pantscolor[2] = cbcolor[2] * (1.0f / 255.0f) * e->render.colormod[2];
+                       e->render.colormap_pantscolor[0] = cbcolor[0] * (1.0f / 255.0f);
+                       e->render.colormap_pantscolor[1] = cbcolor[1] * (1.0f / 255.0f);
+                       e->render.colormap_pantscolor[2] = cbcolor[2] * (1.0f / 255.0f);
                        cb = (e->render.colormap & 0xF0);cb += (cb >= 128 && cb < 224) ? 4 : 12;
                        cbcolor = (unsigned char *) (&palette_complete[cb]);
-                       e->render.colormap_shirtcolor[0] = cbcolor[0] * (1.0f / 255.0f) * e->render.colormod[0];
-                       e->render.colormap_shirtcolor[1] = cbcolor[1] * (1.0f / 255.0f) * e->render.colormod[1];
-                       e->render.colormap_shirtcolor[2] = cbcolor[2] * (1.0f / 255.0f) * e->render.colormod[2];
+                       e->render.colormap_shirtcolor[0] = cbcolor[0] * (1.0f / 255.0f);
+                       e->render.colormap_shirtcolor[1] = cbcolor[1] * (1.0f / 255.0f);
+                       e->render.colormap_shirtcolor[2] = cbcolor[2] * (1.0f / 255.0f);
                }
                else
                {
@@ -984,6 +1084,11 @@ void CL_LinkNetworkEntity(entity_t *e)
                                dlightcolor[1] += 0.7f;
                                dlightcolor[2] += 0.3f;
                        }
+                       if (e->render.effects & (EF_FLAG1QW | EF_FLAG2QW))
+                       {
+                               // these are only set on player entities
+                               CL_AddQWCTFFlagModel(e, (e->render.effects & EF_FLAG2QW) != 0);
+                       }
                }
                // muzzleflash fades over time, and is offset a bit
                if (e->persistent.muzzleflash > 0)
@@ -1108,7 +1213,7 @@ void CL_LinkNetworkEntity(entity_t *e)
                // hide player shadow during intermission or nehahra movie
                if (!(e->render.effects & EF_NOSHADOW)
                 && !(e->render.flags & (RENDER_VIEWMODEL | RENDER_TRANSPARENT))
-                && (!(e->render.flags & RENDER_EXTERIORMODEL) || (!cl.intermission && cl.protocol != PROTOCOL_NEHAHRAMOVIE && !cl_noplayershadow.integer)))
+                && (!(e->render.flags & RENDER_EXTERIORMODEL) || (!cl.intermission && cls.protocol != PROTOCOL_NEHAHRAMOVIE && !cl_noplayershadow.integer)))
                        e->render.flags |= RENDER_SHADOW;
                // as soon as player is known we can call V_CalcRefDef
                if (!csqc_loaded)
@@ -1411,6 +1516,34 @@ void CL_RelinkBeams(void)
        }
 }
 
+static void CL_RelinkQWNails(void)
+{
+       int i;
+       vec_t *v;
+       entity_t *ent;
+
+       for (i = 0;i < cl.qw_num_nails;i++)
+       {
+               v = cl.qw_nails[i];
+
+               // if we're drawing effects, get a new temp entity
+               // (NewTempEntity adds it to the render entities list for us)
+               if (!(ent = CL_NewTempEntity()))
+                       continue;
+
+               // normal stuff
+               ent->render.model = cl.model_precache[cl.qw_modelindex_spike];
+               ent->render.colormap = -1; // no special coloring
+               ent->render.alpha = 1;
+               VectorSet(ent->render.colormod, 1, 1, 1);
+
+               Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, v[0], v[1], v[2], v[3], v[4], v[5], 1);
+               Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
+               R_LerpAnimation(&ent->render);
+               CL_BoundingBoxForEntity(&ent->render);
+       }
+}
+
 void CL_LerpPlayer(float frac)
 {
        int i;
@@ -1457,6 +1590,7 @@ void CSQC_RelinkAllEntities (int drawmask)
                CL_RelinkStaticEntities();
                CL_RelinkBeams();
                CL_RelinkEffects();
+               CL_RelinkQWNails();
        }
 }
 
@@ -1472,6 +1606,7 @@ extern void CL_ClientMovement_Replay();
 int CL_ReadFromServer(void)
 {
        CL_ReadDemoMessage();
+       CL_SendMove();
 
        r_refdef.time = cl.time;
        r_refdef.extraupdate = !r_speeds.integer;
@@ -1504,6 +1639,7 @@ int CL_ReadFromServer(void)
                        CL_RelinkStaticEntities();
                        CL_RelinkBeams();
                        CL_RelinkEffects();
+                       CL_RelinkQWNails();
                }
                else
                        csqc_frame = true;
@@ -1520,34 +1656,6 @@ int CL_ReadFromServer(void)
        return 0;
 }
 
-/*
-=================
-CL_SendCmd
-=================
-*/
-void CL_UpdatePrydonCursor(void);
-void CL_SendCmd(void)
-{
-       if (cls.demoplayback)
-       {
-               SZ_Clear(&cls.message);
-               return;
-       }
-
-       // send the reliable message (forwarded commands) if there is one
-       if (cls.message.cursize && NetConn_CanSendMessage(cls.netcon))
-       {
-               if (developer.integer)
-               {
-                       Con_Print("CL_SendCmd: sending reliable message:\n");
-                       SZ_HexDumpToConsole(&cls.message);
-               }
-               if (NetConn_SendReliableMessage(cls.netcon, &cls.message) == -1)
-                       Host_Error("CL_WriteToServer: lost server connection");
-               SZ_Clear(&cls.message);
-       }
-}
-
 // LordHavoc: pausedemo command
 static void CL_PauseDemo_f (void)
 {
@@ -1636,10 +1744,6 @@ void CL_Init (void)
        r_refdef.maxdrawqueuesize = 256 * 1024;
        r_refdef.drawqueue = (unsigned char *)Mem_Alloc(cl_mempool, r_refdef.maxdrawqueuesize);
 
-       cls.message.data = cls.message_buf;
-       cls.message.maxsize = sizeof(cls.message_buf);
-       cls.message.cursize = 0;
-
        CL_InitInput ();
 
 //
@@ -1671,17 +1775,17 @@ void CL_Init (void)
        Cvar_RegisterVariable (&cl_itembobspeed);
        Cvar_RegisterVariable (&cl_itembobheight);
 
-       Cmd_AddCommand ("entities", CL_PrintEntities_f);
-       Cmd_AddCommand ("disconnect", CL_Disconnect_f);
-       Cmd_AddCommand ("record", CL_Record_f);
-       Cmd_AddCommand ("stop", CL_Stop_f);
-       Cmd_AddCommand ("playdemo", CL_PlayDemo_f);
-       Cmd_AddCommand ("timedemo", CL_TimeDemo_f);
+       Cmd_AddCommand ("entities", CL_PrintEntities_f, "print information on network entities known to client");
+       Cmd_AddCommand ("disconnect", CL_Disconnect_f, "disconnect from server (or disconnect all clients if running a server)");
+       Cmd_AddCommand ("record", CL_Record_f, "record a demo");
+       Cmd_AddCommand ("stop", CL_Stop_f, "stop recording or playing a demo");
+       Cmd_AddCommand ("playdemo", CL_PlayDemo_f, "watch a demo file");
+       Cmd_AddCommand ("timedemo", CL_TimeDemo_f, "play back a demo as fast as possible and save statistics to benchmark.log");
 
-       Cmd_AddCommand ("fog", CL_Fog_f);
+       Cmd_AddCommand ("fog", CL_Fog_f, "set global fog parameters (density red green blue)");
 
        // LordHavoc: added pausedemo
-       Cmd_AddCommand ("pausedemo", CL_PauseDemo_f);
+       Cmd_AddCommand ("pausedemo", CL_PauseDemo_f, "pause demo playback (can also safely pause demo recording if using QUAKE, QUAKEDP or NEHAHRAMOVIE protocol, useful for making movies)");
 
        Cvar_RegisterVariable(&r_draweffects);
        Cvar_RegisterVariable(&cl_explosions_alpha_start);
@@ -1700,7 +1804,11 @@ void CL_Init (void)
 
        Cvar_RegisterVariable(&cl_deathnoviewmodel);
 
-       Cmd_AddCommand("timerefresh", CL_TimeRefresh_f);
+       // for QW connections
+       Cvar_RegisterVariable(&qport);
+       Cvar_SetValueQuick(&qport, (rand() * RAND_MAX + rand()) & 0xffff);
+
+       Cmd_AddCommand("timerefresh", CL_TimeRefresh_f, "turn quickly and print rendering statistcs");
 
        CL_Parse_Init();
        CL_Particles_Init();