]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - cl_parse.c
reorganized rgbgen/alphagen/tcgen fields into their own structs to clean
[xonotic/darkplaces.git] / cl_parse.c
index ba4972dcb90d21fca888f674abb397a6dc620aa1..bedd95dda67fe092b4ec12ae8a284691128ff45e 100644 (file)
@@ -164,12 +164,15 @@ cvar_t cl_sound_tink1 = {0, "cl_sound_tink1", "weapons/tink1.wav", "sound to pla
 cvar_t cl_sound_ric1 = {0, "cl_sound_ric1", "weapons/ric1.wav", "sound to play with 5% chance during TE_SPIKE/TE_SUPERSPIKE (empty cvar disables sound)"};
 cvar_t cl_sound_ric2 = {0, "cl_sound_ric2", "weapons/ric2.wav", "sound to play with 5% chance during TE_SPIKE/TE_SUPERSPIKE (empty cvar disables sound)"};
 cvar_t cl_sound_ric3 = {0, "cl_sound_ric3", "weapons/ric3.wav", "sound to play with 10% chance during TE_SPIKE/TE_SUPERSPIKE (empty cvar disables sound)"};
+
+#define RIC_GUNSHOT            1
+#define RIC_GUNSHOTQUAD        2
 cvar_t cl_sound_ric_gunshot = {0, "cl_sound_ric_gunshot", "0", "specifies if and when the related cl_sound_ric and cl_sound_tink sounds apply to TE_GUNSHOT/TE_GUNSHOTQUAD, 0 = no sound, 1 = TE_GUNSHOT, 2 = TE_GUNSHOTQUAD, 3 = TE_GUNSHOT and TE_GUNSHOTQUAD"};
 cvar_t cl_sound_r_exp3 = {0, "cl_sound_r_exp3", "weapons/r_exp3.wav", "sound to play during TE_EXPLOSION and related effects (empty cvar disables sound)"};
 cvar_t cl_serverextension_download = {0, "cl_serverextension_download", "0", "indicates whether the server supports the download command"};
 cvar_t cl_joinbeforedownloadsfinish = {CVAR_SAVE, "cl_joinbeforedownloadsfinish", "1", "if non-zero the game will begin after the map is loaded before other downloads finish"};
 cvar_t cl_nettimesyncfactor = {CVAR_SAVE, "cl_nettimesyncfactor", "0", "rate at which client time adapts to match server time, 1 = instantly, 0.125 = slowly, 0 = not at all (bounding still applies)"};
-cvar_t cl_nettimesyncboundmode = {CVAR_SAVE, "cl_nettimesyncboundmode", "5", "method of restricting client time to valid values, 0 = no correction, 1 = tight bounding (jerky with packet loss), 2 = loose bounding (corrects it if out of bounds), 3 = leniant bounding (ignores temporary errors due to varying framerate), 4 = slow adjustment method from Quake3, 5 = slightly nicer version of Quake3 method"};
+cvar_t cl_nettimesyncboundmode = {CVAR_SAVE, "cl_nettimesyncboundmode", "6", "method of restricting client time to valid values, 0 = no correction, 1 = tight bounding (jerky with packet loss), 2 = loose bounding (corrects it if out of bounds), 3 = leniant bounding (ignores temporary errors due to varying framerate), 4 = slow adjustment method from Quake3, 5 = slighttly nicer version of Quake3 method, 6 = bounding + Quake3"};
 cvar_t cl_nettimesyncboundtolerance = {CVAR_SAVE, "cl_nettimesyncboundtolerance", "0.25", "how much error is tolerated by bounding check, as a fraction of frametime, 0.25 = up to 25% margin of error tolerated, 1 = use only new time, 0 = use only old time (same effect as setting cl_nettimesyncfactor to 1)"};
 cvar_t cl_iplog_name = {CVAR_SAVE, "cl_iplog_name", "darkplaces_iplog.txt", "name of iplog file containing player addresses for iplog_list command and automatic ip logging when parsing status command"};
 
@@ -326,13 +329,13 @@ void CL_ParseEntityLump(char *entdata)
        data = entdata;
        if (!data)
                return;
-       if (!COM_ParseTokenConsole(&data))
+       if (!COM_ParseToken_Simple(&data, false))
                return; // error
        if (com_token[0] != '{')
                return; // error
        while (1)
        {
-               if (!COM_ParseTokenConsole(&data))
+               if (!COM_ParseToken_Simple(&data, false))
                        return; // error
                if (com_token[0] == '}')
                        break; // end of worldspawn
@@ -342,7 +345,7 @@ void CL_ParseEntityLump(char *entdata)
                        strlcpy (key, com_token, sizeof (key));
                while (key[strlen(key)-1] == ' ') // remove trailing spaces
                        key[strlen(key)-1] = 0;
-               if (!COM_ParseTokenConsole(&data))
+               if (!COM_ParseToken_Simple(&data, false))
                        return; // error
                strlcpy (value, com_token, sizeof (value));
                if (!strcmp("sky", key))
@@ -474,9 +477,13 @@ static void QW_CL_RequestNextDownload(void)
 
                cls.qw_downloadtype = dl_none;
 
+               // parse the Q3 shader files
+               Mod_LoadQ3Shaders();
+
                // touch all of the precached models that are still loaded so we can free
                // anything that isn't needed
-               Mod_ClearUsed();
+               if (!sv.active)
+                       Mod_ClearUsed();
                for (i = 1;i < MAX_MODELS && cl.model_name[i][0];i++)
                        Mod_FindName(cl.model_name[i]);
                // precache any models used by the client (this also marks them used)
@@ -941,6 +948,10 @@ void CL_BeginDownloads(qboolean aborteddownload)
        {
                // loading models
 
+               // parse the Q3 shader files
+               if (cl.loadmodel_current < 2)
+                       Mod_LoadQ3Shaders();
+
                for (;cl.loadmodel_current < cl.loadmodel_total;cl.loadmodel_current++)
                {
                        if (cl.model_precache[cl.loadmodel_current] && cl.model_precache[cl.loadmodel_current]->Draw)
@@ -1414,17 +1425,27 @@ void CL_ParseServerInfo (void)
                str = MSG_ReadString ();
                strlcpy (cl.levelname, str, sizeof(cl.levelname));
 
-               // get the movevars
-               cl.qw_movevars_gravity            = MSG_ReadFloat();
-               cl.qw_movevars_stopspeed          = MSG_ReadFloat();
-               cl.qw_movevars_maxspeed           = MSG_ReadFloat();
-               cl.qw_movevars_spectatormaxspeed  = MSG_ReadFloat();
-               cl.qw_movevars_accelerate         = MSG_ReadFloat();
-               cl.qw_movevars_airaccelerate      = MSG_ReadFloat();
-               cl.qw_movevars_wateraccelerate    = MSG_ReadFloat();
-               cl.qw_movevars_friction           = MSG_ReadFloat();
-               cl.qw_movevars_waterfriction      = MSG_ReadFloat();
-               cl.qw_movevars_entgravity         = MSG_ReadFloat();
+               // get the movevars that are defined in the qw protocol
+               cl.movevars_gravity            = MSG_ReadFloat();
+               cl.movevars_stopspeed          = MSG_ReadFloat();
+               cl.movevars_maxspeed           = MSG_ReadFloat();
+               cl.movevars_spectatormaxspeed  = MSG_ReadFloat();
+               cl.movevars_accelerate         = MSG_ReadFloat();
+               cl.movevars_airaccelerate      = MSG_ReadFloat();
+               cl.movevars_wateraccelerate    = MSG_ReadFloat();
+               cl.movevars_friction           = MSG_ReadFloat();
+               cl.movevars_waterfriction      = MSG_ReadFloat();
+               cl.movevars_entgravity         = MSG_ReadFloat();
+
+               // other movevars not in the protocol...
+               cl.movevars_wallfriction = 0;
+               cl.movevars_timescale = 1;
+               cl.movevars_jumpvelocity = 270;
+               cl.movevars_edgefriction = 2;
+               cl.movevars_maxairspeed = 30;
+               cl.movevars_stepheight = 18;
+               cl.movevars_airaccel_qw = 1;
+               cl.movevars_airaccel_sideways_friction = 0;
 
                // seperate the printfs so the server message can have a color
                Con_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n\2%s\n", str);
@@ -1500,7 +1521,8 @@ void CL_ParseServerInfo (void)
 
                // touch all of the precached models that are still loaded so we can free
                // anything that isn't needed
-               Mod_ClearUsed();
+               if (!sv.active)
+                       Mod_ClearUsed();
                for (i = 1;i < nummodels;i++)
                        Mod_FindName(cl.model_name[i]);
                // precache any models used by the client (this also marks them used)
@@ -1621,7 +1643,7 @@ void CL_MoveLerpEntityStates(entity_t *ent)
                ent->render.framelerp = 1;
                // reset various persistent stuff
                ent->persistent.muzzleflash = 0;
-               VectorCopy(ent->state_current.origin, ent->persistent.trail_origin);
+               ent->persistent.trail_allowed = false;
        }
        else if (DotProduct(odelta, odelta) > 1000*1000 || (cl.fixangle[0] && !cl.fixangle[1]))
        {
@@ -1634,6 +1656,7 @@ void CL_MoveLerpEntityStates(entity_t *ent)
                VectorCopy(ent->state_current.angles, ent->persistent.oldangles);
                VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
                VectorCopy(ent->state_current.angles, ent->persistent.newangles);
+               ent->persistent.trail_allowed = false;
        }
        else if (ent->state_current.flags & RENDER_STEP)
        {
@@ -2087,7 +2110,7 @@ void CL_ParseTempEntity(void)
                        VectorSet(pos2, pos[0] + radius, pos[1] + radius, pos[2] + radius);
                        VectorSet(pos, pos[0] - radius, pos[1] - radius, pos[2] - radius);
                        CL_ParticleEffect(EFFECT_TE_GUNSHOT, radius, pos, pos2, vec3_origin, vec3_origin, NULL, 0);
-                       if(cl_sound_ric_gunshot.integer == 1 || cl_sound_ric_gunshot.integer == 3)
+                       if(cl_sound_ric_gunshot.integer & RIC_GUNSHOT)
                        {
                                if (rand() % 5)
                                        S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
@@ -2293,7 +2316,7 @@ void CL_ParseTempEntity(void)
                        MSG_ReadVector(pos, cls.protocol);
                        CL_FindNonSolidLocation(pos, pos, 4);
                        CL_ParticleEffect(EFFECT_TE_GUNSHOT, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
-                       if(cl_sound_ric_gunshot.integer == 1 || cl_sound_ric_gunshot.integer == 3)
+                       if(cl_sound_ric_gunshot.integer & RIC_GUNSHOT)
                        {
                                if (rand() % 5)
                                        S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
@@ -2315,7 +2338,7 @@ void CL_ParseTempEntity(void)
                        MSG_ReadVector(pos, cls.protocol);
                        CL_FindNonSolidLocation(pos, pos, 4);
                        CL_ParticleEffect(EFFECT_TE_GUNSHOTQUAD, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
-                       if(cl_sound_ric_gunshot.integer >= 2)
+                       if(cl_sound_ric_gunshot.integer & RIC_GUNSHOTQUAD)
                        {
                                if (rand() % 5)
                                        S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
@@ -2523,6 +2546,15 @@ void CL_ParsePointParticles(void)
        CL_ParticleEffect(effectindex, count, origin, origin, velocity, velocity, NULL, 0);
 }
 
+void CL_ParsePointParticles1(void)
+{
+       int effectindex;
+       vec3_t origin;
+       effectindex = (unsigned short)MSG_ReadShort();
+       MSG_ReadVector(origin, cls.protocol);
+       CL_ParticleEffect(effectindex, 1, origin, origin, vec3_origin, vec3_origin, NULL, 0);
+}
+
 typedef struct cl_iplog_item_s
 {
        char *address;
@@ -2681,6 +2713,9 @@ qboolean CL_ExaminePrintString(const char *text)
        if (!strcmp(text, "Client ping times:\n"))
        {
                cl.parsingtextmode = CL_PARSETEXTMODE_PING;
+               // hide ping reports in demos
+               if (cls.demoplayback)
+                       cl.parsingtextexpectingpingforscores = 1;
                for(cl.parsingtextplayerindex = 0; cl.parsingtextplayerindex < cl.maxclients && !cl.scores[cl.parsingtextplayerindex].name[0]; cl.parsingtextplayerindex++)
                        ;
                if (cl.parsingtextplayerindex >= cl.maxclients) // should never happen, since the client itself should be in cl.scores
@@ -2817,12 +2852,13 @@ extern cvar_t slowmo;
 static void CL_NetworkTimeReceived(double newtime)
 {
        double timehigh;
-       if (cls.timedemo || (cl.islocalgame && !sv_fixedframeratesingleplayer.integer) || cl.mtime[0] == newtime || cls.signon < SIGNONS)
-               cl.time = cl.mtime[1] = cl.mtime[0] = newtime;
-       else
+       cl.mtime[1] = cl.mtime[0];
+       cl.mtime[0] = newtime;
+       if (cls.timedemo || (cl.islocalgame && !sv_fixedframeratesingleplayer.integer) || cl.mtime[1] == cl.mtime[0] || cls.signon < SIGNONS)
+               cl.time = cl.mtime[1] = newtime;
+       else if (cls.protocol != PROTOCOL_QUAKEWORLD && !cls.demoplayback)
        {
-               cl.mtime[1] = max(cl.mtime[0], newtime - 0.1);
-               cl.mtime[0] = newtime;
+               cl.mtime[1] = max(cl.mtime[1], cl.mtime[0] - 0.1);
                if (developer.integer >= 100 && vid_activewindow)
                {
                        if (cl.time < cl.mtime[1] - (cl.mtime[0] - cl.mtime[1]))
@@ -2851,9 +2887,9 @@ static void CL_NetworkTimeReceived(double newtime)
                        else if (fabs(cl.time - cl.mtime[1]) > 0.1)
                                cl.time += 0.5 * (cl.mtime[1] - cl.time); // fast
                        else if (cl.time > cl.mtime[1])
-                               cl.time -= 0.002 * slowmo.value; // fall into the past by 2ms
+                               cl.time -= 0.002 * cl.movevars_timescale; // fall into the past by 2ms
                        else
-                               cl.time += 0.001 * slowmo.value; // creep forward 1ms
+                               cl.time += 0.001 * cl.movevars_timescale; // creep forward 1ms
                }
                else if (cl_nettimesyncboundmode.integer == 5)
                {
@@ -2862,7 +2898,12 @@ static void CL_NetworkTimeReceived(double newtime)
                        else if (fabs(cl.time - cl.mtime[1]) > 0.1)
                                cl.time += 0.5 * (cl.mtime[1] - cl.time); // fast
                        else
-                               cl.time = bound(cl.time - 0.002 * slowmo.value, cl.mtime[1], cl.time + 0.001 * slowmo.value); // slow adjust
+                               cl.time = bound(cl.time - 0.002 * cl.movevars_timescale, cl.mtime[1], cl.time + 0.001 * cl.movevars_timescale);
+               }
+               else if (cl_nettimesyncboundmode.integer == 6)
+               {
+                       cl.time = bound(cl.mtime[1], cl.time, cl.mtime[0]);
+                       cl.time = bound(cl.time - 0.002 * cl.movevars_timescale, cl.mtime[1], cl.time + 0.001 * cl.movevars_timescale);
                }
        }
        // this packet probably contains a player entity update, so we will need
@@ -2895,6 +2936,7 @@ CL_ParseServerMessage
 =====================
 */
 int parsingerror = false;
+extern void CL_UpdateMoveVars(void);
 void CL_ParseServerMessage(void)
 {
        int                     cmd;
@@ -2944,6 +2986,8 @@ void CL_ParseServerMessage(void)
                // fade weapon view kick
                cl.qw_weaponkick = min(cl.qw_weaponkick + 10 * bound(0, cl.time - cl.oldtime, 0.1), 0);
 
+               cls.servermovesequence = cls.netcon->qw.incoming_sequence;
+
                while (1)
                {
                        if (msg_badread)
@@ -3242,11 +3286,13 @@ void CL_ParseServerMessage(void)
                                break;
 
                        case qw_svc_maxspeed:
-                               cl.qw_movevars_maxspeed = MSG_ReadFloat();
+                               cl.movevars_maxspeed = MSG_ReadFloat();
                                break;
 
                        case qw_svc_entgravity:
-                               cl.qw_movevars_entgravity = MSG_ReadFloat();
+                               cl.movevars_entgravity = MSG_ReadFloat();
+                               if (!cl.movevars_entgravity)
+                                       cl.movevars_entgravity = 1.0f;
                                break;
 
                        case qw_svc_setpause:
@@ -3260,10 +3306,24 @@ void CL_ParseServerMessage(void)
                        }
                }
 
-               // fully kill the still slightly dead qw player entities each frame
-               for (i = 1;i < cl.maxclients;i++)
-                       if (!cl.entities_active[i])
-                               cl.entities[i].state_current.active = false;
+               // fully kill the still slightly dead qw player entities each frame,
+               // but only if a player update was received
+               for (i = 1;i <= cl.maxclients;i++)
+                       if (cl.entities_active[i])
+                               break;
+               if (i <= cl.maxclients)
+               {
+                       // kill all non-updated entities this frame
+                       for (i = 1;i <= cl.maxclients;i++)
+                               if (!cl.entities_active[i])
+                                       cl.entities[i].state_current.active = false;
+               }
+               else
+               {
+                       // no update this frame, restore the cl.entities_active for good measure
+                       for (i = 1;i <= cl.maxclients;i++)
+                               cl.entities_active[i] = cl.entities[i].state_current.active;
+               }
        }
        else
        {
@@ -3673,6 +3733,9 @@ void CL_ParseServerMessage(void)
                        case svc_pointparticles:
                                CL_ParsePointParticles();
                                break;
+                       case svc_pointparticles1:
+                               CL_ParsePointParticles1();
+                               break;
                        }
                }
        }
@@ -3682,6 +3745,8 @@ void CL_ParseServerMessage(void)
 
        EntityFrameQuake_ISeeDeadEntities();
 
+       CL_UpdateMoveVars();
+
        parsingerror = false;
 
        // LordHavoc: this was at the start of the function before cl_autodemo was