#include "cl_collision.h"
#include "csprogs.h"
#include "libcurl.h"
+#include "utf8lib.h"
+#include "menu.h"
+#include "cl_video.h"
-char *svc_strings[128] =
+const char *svc_strings[128] =
{
"svc_bad",
"svc_nop",
"svc_pointparticles1", // 62 // [short] effectnum [vector] start, same as svc_pointparticles except velocity is zero and count is 1
};
-char *qw_svc_strings[128] =
+const char *qw_svc_strings[128] =
{
"qw_svc_bad", // 0
"qw_svc_nop", // 1
//=============================================================================
-cvar_t demo_nehahra = {0, "demo_nehahra", "0", "reads all quake demos as nehahra movie protocol"};
+cvar_t cl_worldmessage = {CVAR_READONLY, "cl_worldmessage", "", "title of current level"};
+cvar_t cl_worldname = {CVAR_READONLY, "cl_worldname", "", "name of current worldmodel"};
+cvar_t cl_worldnamenoextension = {CVAR_READONLY, "cl_worldnamenoextension", "", "name of current worldmodel without extension"};
+cvar_t cl_worldbasename = {CVAR_READONLY, "cl_worldbasename", "", "name of current worldmodel without maps/ prefix or extension"};
+
cvar_t developer_networkentities = {0, "developer_networkentities", "0", "prints received entities, value is 0-4 (higher for more info)"};
cvar_t cl_gameplayfix_soundsmovewithentities = {0, "cl_gameplayfix_soundsmovewithentities", "1", "causes sounds made by lifts, players, projectiles, and any other entities, to move with the entity, so for example a rocket noise follows the rocket rather than staying at the starting position"};
cvar_t cl_sound_wizardhit = {0, "cl_sound_wizardhit", "wizard/hit.wav", "sound to play during TE_WIZSPIKE (empty cvar disables sound)"};
{
float time;
static double nextmsg = -1;
+ static double nextupdate = -1;
#if 0
static double lasttime = -1;
#endif
qboolean oldbadread;
sizebuf_t old;
+ if(cls.state != ca_dedicated)
+ {
+ if((time = Sys_DoubleTime()) >= nextupdate)
+ {
+ SCR_UpdateLoadingScreenIfShown();
+ nextupdate = time + 2;
+ }
+ }
+
// no need if server is local and definitely not if this is a demo
if (!cls.netcon || cls.protocol == PROTOCOL_QUAKEWORLD || cls.signon >= SIGNONS)
return;
R_SetSkyBox(value);
else if (!strcmp("fog", key))
{
+ FOG_clear(); // so missing values get good defaults
r_refdef.fog_start = 0;
r_refdef.fog_alpha = 1;
r_refdef.fog_end = 16384;
+ r_refdef.fog_height = 1<<30;
+ r_refdef.fog_fadedepth = 128;
#if _MSC_VER >= 1400
#define sscanf sscanf_s
#endif
- sscanf(value, "%f %f %f %f %f %f %f", &r_refdef.fog_density, &r_refdef.fog_red, &r_refdef.fog_green, &r_refdef.fog_blue, &r_refdef.fog_alpha, &r_refdef.fog_start, &r_refdef.fog_end);
+ sscanf(value, "%f %f %f %f %f %f %f %f %f", &r_refdef.fog_density, &r_refdef.fog_red, &r_refdef.fog_green, &r_refdef.fog_blue, &r_refdef.fog_alpha, &r_refdef.fog_start, &r_refdef.fog_end, &r_refdef.fog_height, &r_refdef.fog_fadedepth);
}
else if (!strcmp("fog_density", key))
r_refdef.fog_density = atof(value);
r_refdef.fog_start = atof(value);
else if (!strcmp("fog_end", key))
r_refdef.fog_end = atof(value);
+ else if (!strcmp("fog_height", key))
+ r_refdef.fog_height = atof(value);
+ else if (!strcmp("fog_fadedepth", key))
+ r_refdef.fog_fadedepth = atof(value);
+ else if (!strcmp("fog_heighttexture", key))
+ {
+ FOG_clear(); // so missing values get good defaults
+#if _MSC_VER >= 1400
+ sscanf_s(value, "%f %f %f %f %f %f %f %f %f %s", &r_refdef.fog_density, &r_refdef.fog_red, &r_refdef.fog_green, &r_refdef.fog_blue, &r_refdef.fog_alpha, &r_refdef.fog_start, &r_refdef.fog_end, &r_refdef.fog_height, &r_refdef.fog_fadedepth, r_refdef.fog_height_texturename, (unsigned int)sizeof(r_refdef.fog_height_texturename));
+#else
+ sscanf(value, "%f %f %f %f %f %f %f %f %f %63s", &r_refdef.fog_density, &r_refdef.fog_red, &r_refdef.fog_green, &r_refdef.fog_blue, &r_refdef.fog_alpha, &r_refdef.fog_start, &r_refdef.fog_end, &r_refdef.fog_height, &r_refdef.fog_fadedepth, r_refdef.fog_height_texturename);
+#endif
+ r_refdef.fog_height_texturename[63] = 0;
+ }
}
}
static void CL_SetupWorldModel(void)
{
// update the world model
- cl.entities[0].render.model = cl.worldmodel = cl.model_precache[1];
+ cl.entities[0].render.model = cl.worldmodel = CL_GetModelByIndex(1);
CL_UpdateRenderEntity(&cl.entities[0].render);
+ // make sure the cl.worldname and related cvars are set up now that we know the world model name
// set up csqc world for collision culling
if (cl.worldmodel)
- World_SetSize(&cl.world, cl.worldmodel->name, cl.worldmodel->normalmins, cl.worldmodel->normalmaxs);
+ {
+ strlcpy(cl.worldname, cl.worldmodel->name, sizeof(cl.worldname));
+ FS_StripExtension(cl.worldname, cl.worldnamenoextension, sizeof(cl.worldnamenoextension));
+ strlcpy(cl.worldbasename, !strncmp(cl.worldnamenoextension, "maps/", 5) ? cl.worldnamenoextension + 5 : cl.worldnamenoextension, sizeof(cl.worldbasename));
+ Cvar_SetQuick(&cl_worldmessage, cl.worldmessage);
+ Cvar_SetQuick(&cl_worldname, cl.worldname);
+ Cvar_SetQuick(&cl_worldnamenoextension, cl.worldnamenoextension);
+ Cvar_SetQuick(&cl_worldbasename, cl.worldbasename);
+ World_SetSize(&cl.world, cl.worldname, cl.worldmodel->normalmins, cl.worldmodel->normalmaxs);
+ }
else
+ {
+ Cvar_SetQuick(&cl_worldmessage, cl.worldmessage);
+ Cvar_SetQuick(&cl_worldnamenoextension, "");
+ Cvar_SetQuick(&cl_worldbasename, "");
World_SetSize(&cl.world, "", defaultmins, defaultmaxs);
+ }
+ World_Start(&cl.world);
// load or reload .loc file for team chat messages
CL_Locs_Reload_f();
// check memory integrity
Mem_CheckSentinelsGlobal();
+ // make menu know
+ MR_NewMap();
+
// load the csqc now
if (cl.loadcsqc)
{
cl.model_bolt2 = Mod_ForName("progs/bolt2.mdl", false, false, NULL);
cl.model_bolt3 = Mod_ForName("progs/bolt3.mdl", false, false, NULL);
cl.model_beam = Mod_ForName("progs/beam.mdl", false, false, NULL);
- Mod_PurgeUnused();
+
+ // we purge the models and sounds later in CL_SignonReply
+ //Mod_PurgeUnused();
// now we try to load everything that is new
cls.qw_downloadtype = dl_none;
- // load new sounds and unload old ones
- // FIXME: S_ServerSounds does not know about cl.sfx_ sounds
- S_ServerSounds(cl.sound_name, cls.qw_downloadnumber);
+ // clear sound usage flags for purging of unused sounds
+ S_ClearUsed();
// precache any sounds used by the client
cl.sfx_wizhit = S_PrecacheSound(cl_sound_wizardhit.string, false, true);
cl.sfx_ric3 = S_PrecacheSound(cl_sound_ric3.string, false, true);
cl.sfx_r_exp3 = S_PrecacheSound(cl_sound_r_exp3.string, false, true);
- // sounds
+ // sounds used by the game
for (i = 1;i < MAX_SOUNDS && cl.sound_name[i][0];i++)
- {
- // Don't lock the sfx here, S_ServerSounds already did that
- cl.sound_precache[i] = S_PrecacheSound(cl.sound_name[i], true, false);
- }
+ cl.sound_precache[i] = S_PrecacheSound(cl.sound_name[i], true, true);
+
+ // we purge the models and sounds later in CL_SignonReply
+ //S_PurgeUnused();
// check memory integrity
Mem_CheckSentinelsGlobal();
cl.activeweapon = cl.stats[STAT_ACTIVEWEAPON];
}
+#define LOADPROGRESSWEIGHT_SOUND 1.0
+#define LOADPROGRESSWEIGHT_MODEL 4.0
+#define LOADPROGRESSWEIGHT_WORLDMODEL 30.0
+#define LOADPROGRESSWEIGHT_WORLDMODEL_INIT 2.0
+
void CL_BeginDownloads(qboolean aborteddownload)
{
// quakeworld works differently
// if we got here...
// curl is done, so let's start with the business
+ if(!cl.loadbegun)
+ SCR_PushLoadingScreen(false, "Loading precaches", 1);
cl.loadbegun = true;
// if already downloading something from the previous level, don't stop it
if(cl.loadmodel_current == 1)
{
// worldmodel counts as 16 models (15 + world model setup), for better progress bar
- SCR_PushLoadingScreen(false, "Loading precached models", (cl.loadmodel_total + 15) / (float) (cl.loadmodel_total + cl.loadsound_total + 15));
+ SCR_PushLoadingScreen(false, "Loading precached models",
+ (
+ (cl.loadmodel_total - 1) * LOADPROGRESSWEIGHT_MODEL
+ + LOADPROGRESSWEIGHT_WORLDMODEL
+ + LOADPROGRESSWEIGHT_WORLDMODEL_INIT
+ ) / (
+ (cl.loadmodel_total - 1) * LOADPROGRESSWEIGHT_MODEL
+ + LOADPROGRESSWEIGHT_WORLDMODEL
+ + LOADPROGRESSWEIGHT_WORLDMODEL_INIT
+ + cl.loadsound_total * LOADPROGRESSWEIGHT_SOUND
+ )
+ );
SCR_BeginLoadingPlaque();
}
for (;cl.loadmodel_current < cl.loadmodel_total;cl.loadmodel_current++)
{
- SCR_PushLoadingScreen(true, cl.model_name[cl.loadmodel_current], (cl.loadmodel_current == 1 ? 15.0 : 1.0) / cl.loadmodel_total);
+ SCR_PushLoadingScreen(false, cl.model_name[cl.loadmodel_current],
+ (
+ (cl.loadmodel_current == 1) ? LOADPROGRESSWEIGHT_WORLDMODEL : LOADPROGRESSWEIGHT_MODEL
+ ) / (
+ (cl.loadmodel_total - 1) * LOADPROGRESSWEIGHT_MODEL
+ + LOADPROGRESSWEIGHT_WORLDMODEL
+ + LOADPROGRESSWEIGHT_WORLDMODEL_INIT
+ )
+ );
if (cl.model_precache[cl.loadmodel_current] && cl.model_precache[cl.loadmodel_current]->Draw)
{
SCR_PopLoadingScreen(false);
continue;
}
CL_KeepaliveMessage(true);
- cl.model_precache[cl.loadmodel_current] = Mod_ForName(cl.model_name[cl.loadmodel_current], false, false, cl.model_name[cl.loadmodel_current][0] == '*' ? cl.model_name[1] : NULL);
+
+ // if running a local game, calling Mod_ForName is a completely wasted effort...
+ if (sv.active)
+ cl.model_precache[cl.loadmodel_current] = sv.models[cl.loadmodel_current];
+ else
+ {
+ if(cl.loadmodel_current == 1)
+ {
+ // they'll be soon loaded, but make sure we apply freshly downloaded shaders from a curled pk3
+ Mod_FreeQ3Shaders();
+ }
+ cl.model_precache[cl.loadmodel_current] = Mod_ForName(cl.model_name[cl.loadmodel_current], false, false, cl.model_name[cl.loadmodel_current][0] == '*' ? cl.model_name[1] : NULL);
+ }
SCR_PopLoadingScreen(false);
if (cl.model_precache[cl.loadmodel_current] && cl.model_precache[cl.loadmodel_current]->Draw && cl.loadmodel_current == 1)
{
// we now have the worldmodel so we can set up the game world
- SCR_PushLoadingScreen(true, "world model setup", 1.0 / cl.loadmodel_total);
+ SCR_PushLoadingScreen(true, "world model setup",
+ (
+ LOADPROGRESSWEIGHT_WORLDMODEL_INIT
+ ) / (
+ (cl.loadmodel_total - 1) * LOADPROGRESSWEIGHT_MODEL
+ + LOADPROGRESSWEIGHT_WORLDMODEL
+ + LOADPROGRESSWEIGHT_WORLDMODEL_INIT
+ )
+ );
CL_SetupWorldModel();
SCR_PopLoadingScreen(true);
if (!cl.loadfinished && cl_joinbeforedownloadsfinish.integer)
{
// loading sounds
if(cl.loadsound_current == 1)
- SCR_PushLoadingScreen(false, "Loading precached sounds", cl.loadsound_total / (float) (cl.loadmodel_total + cl.loadsound_total + 15));
+ SCR_PushLoadingScreen(false, "Loading precached sounds",
+ (
+ cl.loadsound_total * LOADPROGRESSWEIGHT_SOUND
+ ) / (
+ (cl.loadmodel_total - 1) * LOADPROGRESSWEIGHT_MODEL
+ + LOADPROGRESSWEIGHT_WORLDMODEL
+ + LOADPROGRESSWEIGHT_WORLDMODEL_INIT
+ + cl.loadsound_total * LOADPROGRESSWEIGHT_SOUND
+ )
+ );
for (;cl.loadsound_current < cl.loadsound_total;cl.loadsound_current++)
{
- SCR_PushLoadingScreen(true, cl.sound_name[cl.loadsound_current], 1.0 / cl.loadsound_total);
+ SCR_PushLoadingScreen(false, cl.sound_name[cl.loadsound_current], 1.0 / cl.loadsound_total);
if (cl.sound_precache[cl.loadsound_current] && S_IsSoundPrecached(cl.sound_precache[cl.loadsound_current]))
{
SCR_PopLoadingScreen(false);
continue;
}
CL_KeepaliveMessage(true);
- // Don't lock the sfx here, S_ServerSounds already did that
- cl.sound_precache[cl.loadsound_current] = S_PrecacheSound(cl.sound_name[cl.loadsound_current], false, false);
+ cl.sound_precache[cl.loadsound_current] = S_PrecacheSound(cl.sound_name[cl.loadsound_current], false, true);
SCR_PopLoadingScreen(false);
}
SCR_PopLoadingScreen(false);
// finished loading sounds
}
- if(gamemode == GAME_NEXUIZ)
+ if(gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC)
Cvar_SetValueQuick(&cl_serverextension_download, false);
- // in Nexuiz, the built in download protocol is kinda broken (misses lots
+ // in Nexuiz/Xonotic, the built in download protocol is kinda broken (misses lots
// of dependencies) anyway, and can mess around with the game directory;
// until this is fixed, only support pk3 downloads via curl, and turn off
// individual file downloads other than for CSQC
- // on the other end of the download protocol, GAME_NEXUIZ enforces writing
+ // on the other end of the download protocol, GAME_NEXUIZ/GAME_XONOTIC enforces writing
// to dlcache only
// idea: support download of pk3 files using this protocol later
{
if (aborteddownload)
{
+
if (cl.downloadmodel_current == 1)
{
// the worldmodel failed, but we need to set up anyway
+ Mod_FreeQ3Shaders();
CL_SetupWorldModel();
if (!cl.loadfinished && cl_joinbeforedownloadsfinish.integer)
{
return;
}
}
+
+ if(cl.downloadmodel_current == 1)
+ {
+ // they'll be soon loaded, but make sure we apply freshly downloaded shaders from a curled pk3
+ Mod_FreeQ3Shaders();
+ }
+
cl.model_precache[cl.downloadmodel_current] = Mod_ForName(cl.model_name[cl.downloadmodel_current], false, false, cl.model_name[cl.downloadmodel_current][0] == '*' ? cl.model_name[1] : NULL);
if (cl.downloadmodel_current == 1)
{
return;
}
}
- // Don't lock the sfx here, S_ServerSounds already did that
- cl.sound_precache[cl.downloadsound_current] = S_PrecacheSound(cl.sound_name[cl.downloadsound_current], false, false);
+ cl.sound_precache[cl.downloadsound_current] = S_PrecacheSound(cl.sound_name[cl.downloadsound_current], false, true);
}
// finished loading sounds
if(cl.loadbegun)
Con_Printf("cl_begindownloads is only valid once per match\n");
else
- {
- SCR_PushLoadingScreen(false, "Loading precaches", 1);
CL_BeginDownloads(false);
- }
}
void CL_StopDownload(int size, int crc)
size_t inflated_size;
out = FS_Inflate(cls.qw_downloadmemory, cls.qw_downloadmemorycursize, &inflated_size, tempmempool);
Mem_Free(cls.qw_downloadmemory);
- Con_Printf("Inflated download: new size: %u (%g%%)\n", (unsigned)inflated_size, 100.0 - 100.0*(cls.qw_downloadmemorycursize / (float)inflated_size));
- cls.qw_downloadmemory = out;
- cls.qw_downloadmemorycursize = inflated_size;
+ if(out)
+ {
+ Con_Printf("Inflated download: new size: %u (%g%%)\n", (unsigned)inflated_size, 100.0 - 100.0*(cls.qw_downloadmemorycursize / (float)inflated_size));
+ cls.qw_downloadmemory = out;
+ cls.qw_downloadmemorycursize = inflated_size;
+ }
+ else
+ {
+ cls.qw_downloadmemory = NULL;
+ cls.qw_downloadmemorycursize = 0;
+ Con_Printf("Cannot inflate download, possibly corrupt or zlib not present\n");
+ }
}
if(!cls.qw_downloadmemory)
// save to disk only if we don't already have it
// (this is mainly for playing back demos)
existingcrc = FS_CRCFile(cls.qw_downloadname, &existingsize);
- if (existingsize || gamemode == GAME_NEXUIZ || !strcmp(cls.qw_downloadname, csqc_progname.string))
- // let csprogs ALWAYS go to dlcache, to prevent "viral csprogs"; also, never put files outside dlcache for Nexuiz
+ if (existingsize || gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC || !strcmp(cls.qw_downloadname, csqc_progname.string))
+ // let csprogs ALWAYS go to dlcache, to prevent "viral csprogs"; also, never put files outside dlcache for Nexuiz/Xonotic
{
if ((int)existingsize != size || existingcrc != crc)
{
void CL_ParseDownload(void)
{
int i, start, size;
- unsigned char data[65536];
+ static unsigned char data[NET_MAXMESSAGE];
start = MSG_ReadLong();
size = (unsigned short)MSG_ReadShort();
*/
static void CL_SignonReply (void)
{
- if (developer.integer >= 100)
- Con_Printf("CL_SignonReply: %i\n", cls.signon);
+ Con_DPrintf("CL_SignonReply: %i\n", cls.signon);
switch (cls.signon)
{
case 4:
// after the level has been loaded, we shouldn't need the shaders, and
// if they are needed again they will be automatically loaded...
+ // we also don't need the unused models or sounds from the last level
Mod_FreeQ3Shaders();
+ Mod_PurgeUnused();
+ S_PurgeUnused();
Con_ClearNotify();
if (COM_CheckParm("-profilegameonly"))
protocolversion_t protocol;
int nummodels, numsounds;
+ // if we start loading a level and a video is still playing, stop it
+ CL_VideoStop();
+
Con_DPrint("Serverinfo packet received.\n");
+ Collision_Cache_Reset(true);
// if server is active, we already began a loading plaque
if (!sv.active)
return;
}
// hack for unmarked Nehahra movie demos which had a custom protocol
- if (protocol == PROTOCOL_QUAKEDP && cls.demoplayback && demo_nehahra.integer)
+ if (protocol == PROTOCOL_QUAKEDP && cls.demoplayback && gamemode == GAME_NEHAHRA)
protocol = PROTOCOL_NEHAHRAMOVIE;
cls.protocol = protocol;
Con_DPrintf("Server protocol is %s\n", Protocol_NameForEnum(cls.protocol));
// get the full level name
str = MSG_ReadString ();
- strlcpy (cl.levelname, str, sizeof(cl.levelname));
+ strlcpy (cl.worldmessage, str, sizeof(cl.worldmessage));
// get the movevars that are defined in the qw protocol
cl.movevars_gravity = MSG_ReadFloat();
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);
+ Con_Printf("\n\n<===================================>\n\n\2%s\n", str);
// check memory integrity
Mem_CheckSentinelsGlobal();
// note: on QW protocol we can't set up the gameworld until after
// downloads finish...
// (we don't even know the name of the map yet)
+ // this also means cl_autodemo does not work on QW protocol...
+
+ strlcpy(cl.worldname, "", sizeof(cl.worldname));
+ strlcpy(cl.worldnamenoextension, "", sizeof(cl.worldnamenoextension));
+ strlcpy(cl.worldbasename, "qw", sizeof(cl.worldbasename));
+ Cvar_SetQuick(&cl_worldname, cl.worldname);
+ Cvar_SetQuick(&cl_worldnamenoextension, cl.worldnamenoextension);
+ Cvar_SetQuick(&cl_worldbasename, cl.worldbasename);
+
+ // check memory integrity
+ Mem_CheckSentinelsGlobal();
}
else
{
// parse signon message
str = MSG_ReadString ();
- strlcpy (cl.levelname, str, sizeof(cl.levelname));
+ strlcpy (cl.worldmessage, str, sizeof(cl.worldmessage));
// seperate the printfs so the server message can have a color
if (cls.protocol != PROTOCOL_NEHAHRAMOVIE) // no messages when playing the Nehahra movie
- 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);
+ Con_Printf("\n<===================================>\n\n\2%s\n", str);
// check memory integrity
Mem_CheckSentinelsGlobal();
strlcpy (cl.sound_name[numsounds], str, sizeof (cl.sound_name[numsounds]));
}
+ // set the base name for level-specific things... this gets updated again by CL_SetupWorldModel later
+ strlcpy(cl.worldname, cl.model_name[1], sizeof(cl.worldname));
+ FS_StripExtension(cl.worldname, cl.worldnamenoextension, sizeof(cl.worldnamenoextension));
+ strlcpy(cl.worldbasename, !strncmp(cl.worldnamenoextension, "maps/", 5) ? cl.worldnamenoextension + 5 : cl.worldnamenoextension, sizeof(cl.worldbasename));
+ Cvar_SetQuick(&cl_worldmessage, cl.worldmessage);
+ Cvar_SetQuick(&cl_worldname, cl.worldname);
+ Cvar_SetQuick(&cl_worldnamenoextension, cl.worldnamenoextension);
+ Cvar_SetQuick(&cl_worldbasename, cl.worldbasename);
+
// touch all of the precached models that are still loaded so we can free
// anything that isn't needed
if (!sv.active)
cl.model_bolt2 = Mod_ForName("progs/bolt2.mdl", false, false, NULL);
cl.model_bolt3 = Mod_ForName("progs/bolt3.mdl", false, false, NULL);
cl.model_beam = Mod_ForName("progs/beam.mdl", false, false, NULL);
- Mod_PurgeUnused();
- // do the same for sounds
- // FIXME: S_ServerSounds does not know about cl.sfx_ sounds
- S_ServerSounds (cl.sound_name, numsounds);
+ // we purge the models and sounds later in CL_SignonReply
+ //Mod_PurgeUnused();
+ //S_PurgeUnused();
+
+ // clear sound usage flags for purging of unused sounds
+ S_ClearUsed();
// precache any sounds used by the client
cl.sfx_wizhit = S_PrecacheSound(cl_sound_wizardhit.string, false, true);
cl.sfx_ric3 = S_PrecacheSound(cl_sound_ric3.string, false, true);
cl.sfx_r_exp3 = S_PrecacheSound(cl_sound_r_exp3.string, false, true);
+ // sounds used by the game
+ for (i = 1;i < MAX_SOUNDS && cl.sound_name[i][0];i++)
+ cl.sound_precache[i] = S_PrecacheSound(cl.sound_name[i], true, true);
+
// now we try to load everything that is new
cl.loadmodel_current = 1;
cl.downloadmodel_current = 1;
cl.loadbegun = false;
cl.loadfinished = false;
cl.loadcsqc = true;
- }
-
- // check memory integrity
- Mem_CheckSentinelsGlobal();
-// if cl_autodemo is set, automatically start recording a demo if one isn't being recorded already
- if (cl_autodemo.integer && cls.netcon && cls.protocol != PROTOCOL_QUAKEWORLD)
- {
- char demofile[MAX_OSPATH];
- char levelname[MAX_QPATH];
+ // check memory integrity
+ Mem_CheckSentinelsGlobal();
- if (cls.demorecording)
+ // if cl_autodemo is set, automatically start recording a demo if one isn't being recorded already
+ if (cl_autodemo.integer && cls.netcon && cls.protocol != PROTOCOL_QUAKEWORLD)
{
- // finish the previous level's demo file
- CL_Stop_f();
- }
+ char demofile[MAX_OSPATH];
- // start a new demo file
- strlcpy(levelname, FS_FileWithoutPath(cl.model_name[1]), sizeof(levelname));
- if (strrchr(levelname, '.'))
- *(strrchr(levelname, '.')) = 0;
- dpsnprintf (demofile, sizeof(demofile), "%s_%s.dem", Sys_TimeString (cl_autodemo_nameformat.string), levelname);
+ if (cls.demorecording)
+ {
+ // finish the previous level's demo file
+ CL_Stop_f();
+ }
- Con_Printf ("Auto-recording to %s.\n", demofile);
+ // start a new demo file
+ dpsnprintf (demofile, sizeof(demofile), "%s_%s.dem", Sys_TimeString (cl_autodemo_nameformat.string), cl.worldbasename);
- cls.demofile = FS_OpenRealFile(demofile, "wb", false);
- if (cls.demofile)
- {
- cls.forcetrack = -1;
- FS_Printf (cls.demofile, "%i\n", cls.forcetrack);
- cls.demorecording = true;
- strlcpy(cls.demoname, demofile, sizeof(cls.demoname));
- cls.demo_lastcsprogssize = -1;
- cls.demo_lastcsprogscrc = -1;
+ Con_Printf ("Auto-recording to %s.\n", demofile);
+
+ // Reset bit 0 for every new demo
+ Cvar_SetValueQuick(&cl_autodemo_delete,
+ (cl_autodemo_delete.integer & ~0x1)
+ |
+ ((cl_autodemo_delete.integer & 0x2) ? 0x1 : 0)
+ );
+
+ cls.demofile = FS_OpenRealFile(demofile, "wb", false);
+ if (cls.demofile)
+ {
+ cls.forcetrack = -1;
+ FS_Printf (cls.demofile, "%i\n", cls.forcetrack);
+ cls.demorecording = true;
+ strlcpy(cls.demoname, demofile, sizeof(cls.demoname));
+ cls.demo_lastcsprogssize = -1;
+ cls.demo_lastcsprogscrc = -1;
+ }
+ else
+ Con_Print ("ERROR: couldn't open.\n");
}
- else
- Con_Print ("ERROR: couldn't open.\n");
}
}
if (!(s->flags & RENDER_COLORMAPPED) && s->colormap > cl.maxclients)
Con_DPrintf("CL_ValidateState: colormap (%i) > cl.maxclients (%i)\n", s->colormap, cl.maxclients);
- model = cl.model_precache[s->modelindex];
- if (model && model->type && s->frame >= model->numframes)
- Con_DPrintf("CL_ValidateState: no such frame %i in \"%s\" (which has %i frames)\n", s->frame, model->name, model->numframes);
- if (model && model->type && s->skin > 0 && s->skin >= model->numskins && !(s->lightpflags & PFLAGS_FULLDYNAMIC))
- Con_DPrintf("CL_ValidateState: no such skin %i in \"%s\" (which has %i skins)\n", s->skin, model->name, model->numskins);
+ if (developer_extra.integer)
+ {
+ model = CL_GetModelByIndex(s->modelindex);
+ if (model && model->type && s->frame >= model->numframes)
+ Con_DPrintf("CL_ValidateState: no such frame %i in \"%s\" (which has %i frames)\n", s->frame, model->name, model->numframes);
+ if (model && model->type && s->skin > 0 && s->skin >= model->numskins && !(s->lightpflags & PFLAGS_FULLDYNAMIC))
+ Con_DPrintf("CL_ValidateState: no such skin %i in \"%s\" (which has %i skins)\n", s->skin, model->name, model->numskins);
+ }
}
void CL_MoveLerpEntityStates(entity_t *ent)
VectorCopy(ent->state_current.angles, ent->persistent.newangles);
ent->persistent.trail_allowed = false;
- if(ent->state_current.frame != ent->state_previous.frame)
+ // if(ent->state_current.frame != ent->state_previous.frame)
+ // do this even if we did change the frame
+ // teleport bit is only used if an animation restart, or a jump, is necessary
+ // so it should be always harmless to do this
{
- // if we ALSO changed animation frame in the process (but ONLY then!)
- // then let's reset the animation interpolation too
ent->render.framegroupblend[0].frame = ent->render.framegroupblend[1].frame = ent->state_current.frame;
ent->render.framegroupblend[0].start = ent->render.framegroupblend[1].start = cl.time;
ent->render.framegroupblend[0].lerp = 1;ent->render.framegroupblend[1].lerp = 0;
// note that this case must do everything the following case does too
}
+ else if ((ent->state_previous.effects & EF_RESTARTANIM_BIT) != (ent->state_current.effects & EF_RESTARTANIM_BIT))
+ {
+ ent->render.framegroupblend[1] = ent->render.framegroupblend[0];
+ ent->render.framegroupblend[1].lerp = 1;
+ ent->render.framegroupblend[0].frame = ent->state_current.frame;
+ ent->render.framegroupblend[0].start = cl.time;
+ ent->render.framegroupblend[0].lerp = 0;
+ }
else if (DotProduct(odelta, odelta) > 1000*1000
|| (cl.fixangle[0] && !cl.fixangle[1])
|| (ent->state_previous.tagindex != ent->state_current.tagindex)
// trigger muzzleflash effect if necessary
if (ent->state_current.effects & EF_MUZZLEFLASH)
ent->persistent.muzzleflash = 1;
+
+ // restart animation bit
+ if ((ent->state_previous.effects & EF_RESTARTANIM_BIT) != (ent->state_current.effects & EF_RESTARTANIM_BIT))
+ {
+ ent->render.framegroupblend[1] = ent->render.framegroupblend[0];
+ ent->render.framegroupblend[1].lerp = 1;
+ ent->render.framegroupblend[0].frame = ent->state_current.frame;
+ ent->render.framegroupblend[0].start = cl.time;
+ ent->render.framegroupblend[0].lerp = 0;
+ }
}
/*
}
// copy it to the current state
- ent->render.model = cl.model_precache[ent->state_baseline.modelindex];
+ ent->render.model = CL_GetModelByIndex(ent->state_baseline.modelindex);
ent->render.framegroupblend[0].frame = ent->state_baseline.frame;
ent->render.framegroupblend[0].lerp = 1;
// make torchs play out of sync
//VectorCopy (ent->state_baseline.angles, ent->render.angles);
Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, ent->state_baseline.origin[0], ent->state_baseline.origin[1], ent->state_baseline.origin[2], ent->state_baseline.angles[0], ent->state_baseline.angles[1], ent->state_baseline.angles[2], 1);
+ ent->render.allowdecals = true;
CL_UpdateRenderEntity(&ent->render);
}
effectindex = (unsigned short)MSG_ReadShort();
MSG_ReadVector(start, cls.protocol);
MSG_ReadVector(end, cls.protocol);
- CL_ParticleEffect(effectindex, VectorDistance(start, end), start, end, vec3_origin, vec3_origin, entityindex > 0 ? cl.entities + entityindex : NULL, 0);
+ CL_ParticleEffect(effectindex, 1, start, end, vec3_origin, vec3_origin, entityindex > 0 ? cl.entities + entityindex : NULL, 0);
}
void CL_ParsePointParticles(void)
return;
if (!cl_iplog_loaded)
CL_IPLog_Load();
- if (developer.integer >= 100)
- Con_Printf("CL_IPLog_Add(\"%s\", \"%s\", %i, %i);\n", address, name, checkexisting, addtofile);
+ if (developer_extra.integer)
+ Con_DPrintf("CL_IPLog_Add(\"%s\", \"%s\", %i, %i);\n", address, name, checkexisting, addtofile);
// see if it already exists
if (checkexisting)
{
{
if (!strcmp(cl_iplog_items[i].address, address) && !strcmp(cl_iplog_items[i].name, name))
{
- if (developer.integer >= 100)
- Con_Printf("... found existing \"%s\" \"%s\"\n", cl_iplog_items[i].address, cl_iplog_items[i].name);
+ if (developer_extra.integer)
+ Con_DPrintf("... found existing \"%s\" \"%s\"\n", cl_iplog_items[i].address, cl_iplog_items[i].name);
return;
}
}
// TODO: this ought to open the one in the userpath version of the base
// gamedir, not the current gamedir
Log_Printf(cl_iplog_name.string, "%s %s\n", address, name);
- if (developer.integer >= 100)
- Con_Printf("CL_IPLog_Add: appending this line to %s: %s %s\n", cl_iplog_name.string, address, name);
+ if (developer_extra.integer)
+ Con_DPrintf("CL_IPLog_Add: appending this line to %s: %s %s\n", cl_iplog_name.string, address, name);
}
}
if (cl.parsingtextmode == CL_PARSETEXTMODE_PING)
{
// if anything goes wrong, we'll assume this is not a ping report
- qboolean expected = cl.parsingtextexpectingpingforscores;
+ qboolean expected = cl.parsingtextexpectingpingforscores != 0;
cl.parsingtextexpectingpingforscores = 0;
cl.parsingtextmode = CL_PARSETEXTMODE_NONE;
t = text;
double timehigh;
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)
+ if (cl_nolerp.integer || 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.demoplayback)
{
else if (cls.protocol != PROTOCOL_QUAKEWORLD)
{
cl.mtime[1] = max(cl.mtime[1], cl.mtime[0] - 0.1);
- if (developer.integer >= 100 && vid_activewindow)
+ if (developer_extra.integer && vid_activewindow)
{
if (cl.time < cl.mtime[1] - (cl.mtime[0] - cl.mtime[1]))
- Con_Printf("--- cl.time < cl.mtime[1] (%f < %f ... %f)\n", cl.time, cl.mtime[1], cl.mtime[0]);
+ Con_DPrintf("--- cl.time < cl.mtime[1] (%f < %f ... %f)\n", cl.time, cl.mtime[1], cl.mtime[0]);
else if (cl.time > cl.mtime[0] + (cl.mtime[0] - cl.mtime[1]))
- Con_Printf("--- cl.time > cl.mtime[0] (%f > %f ... %f)\n", cl.time, cl.mtime[1], cl.mtime[0]);
+ Con_DPrintf("--- cl.time > cl.mtime[0] (%f > %f ... %f)\n", cl.time, cl.mtime[1], cl.mtime[0]);
}
cl.time += (cl.mtime[1] - cl.time) * bound(0, cl_nettimesyncfactor.value, 1);
timehigh = cl.mtime[1] + (cl.mtime[0] - cl.mtime[1]) * cl_nettimesyncboundtolerance.value;
VectorCopy(cl.mviewangles[0], cl.mviewangles[1]);
// update the csqc's server timestamps, critical for proper sync
CSQC_UpdateNetworkTimes(cl.mtime[0], cl.mtime[1]);
+
+ if (cl.mtime[0] > cl.mtime[1])
+ World_Physics_Frame(&cl.world, cl.mtime[0] - cl.mtime[1], cl.movevars_gravity);
}
#define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf("%3i:%s(%i)\n", msg_readcount-1, x, cmd);
int i;
protocolversion_t protocol;
unsigned char cmdlog[32];
- char *cmdlogname[32], *temp;
+ const char *cmdlogname[32], *temp;
int cmdindex, cmdcount = 0;
qboolean qwplayerupdatereceived;
+ qboolean strip_pqc;
// LordHavoc: moved demo message writing from before the packet parse to
// after the packet parse so that CL_Stop_f can be called by cl_autodemo
break;
case qw_svc_setpause:
- cl.paused = MSG_ReadByte ();
+ cl.paused = MSG_ReadByte () != 0;
if (cl.paused)
CDAudio_Pause ();
else
if (cmd == -1)
{
+// R_TimeReport("END OF MESSAGE");
SHOWNET("END OF MESSAGE");
break; // end of message
}
if (protocol == PROTOCOL_UNKNOWN)
Host_Error("CL_ParseServerMessage: Server is unrecognized protocol number (%i)", i);
// hack for unmarked Nehahra movie demos which had a custom protocol
- if (protocol == PROTOCOL_QUAKEDP && cls.demoplayback && demo_nehahra.integer)
+ if (protocol == PROTOCOL_QUAKEDP && cls.demoplayback && gamemode == GAME_NEHAHRA)
protocol = PROTOCOL_NEHAHRAMOVIE;
cls.protocol = protocol;
break;
break;
case svc_stufftext:
- CL_VM_Parse_StuffCmd(MSG_ReadString ()); //[515]: csqc
+ temp = MSG_ReadString();
+ /* if(utf8_enable.integer)
+ {
+ strip_pqc = true;
+ // we can safely strip and even
+ // interpret these in utf8 mode
+ }
+ else */ switch(cls.protocol)
+ {
+ case PROTOCOL_QUAKE:
+ case PROTOCOL_QUAKEDP:
+ // maybe add other protocols if
+ // so desired, but not DP7
+ strip_pqc = true;
+ break;
+ case PROTOCOL_DARKPLACES7:
+ default:
+ // ProQuake does not support
+ // these protocols
+ strip_pqc = false;
+ break;
+ }
+ if(strip_pqc)
+ {
+ // skip over ProQuake messages,
+ // TODO actually interpret them
+ // (they are sbar team score
+ // updates), see proquake cl_parse.c
+ if(*temp == 0x01)
+ {
+ ++temp;
+ while(*temp >= 0x01 && *temp <= 0x1F)
+ ++temp;
+ }
+ }
+ CL_VM_Parse_StuffCmd(temp); //[515]: csqc
break;
case svc_damage:
i -= 32768;
if (i >= 1 && i < MAX_SOUNDS)
{
- sfx_t *sfx = S_PrecacheSound (s, true, false);
+ sfx_t *sfx = S_PrecacheSound (s, true, true);
if (!sfx && snd_initialized.integer)
Con_DPrintf("svc_precache: S_PrecacheSound(\"%s\") failed\n", s);
cl.sound_precache[i] = sfx;
break;
case svc_setpause:
- cl.paused = MSG_ReadByte ();
+ cl.paused = MSG_ReadByte () != 0;
if (cl.paused)
CDAudio_Pause ();
else
MSG_ReadCoord(cls.protocol);
MSG_ReadCoord(cls.protocol);
MSG_ReadCoord(cls.protocol);
- MSG_ReadByte();
+ (void) MSG_ReadByte();
MSG_ReadLong();
MSG_ReadLong();
MSG_ReadString();
MSG_ReadCoord(cls.protocol);
MSG_ReadCoord(cls.protocol);
MSG_ReadCoord(cls.protocol);
- MSG_ReadByte();
+ (void) MSG_ReadByte();
MSG_ReadString();
}
else
CL_ParsePointParticles1();
break;
}
+// R_TimeReport(svc_strings[cmd]);
}
}
if (cls.signon == SIGNONS)
CL_UpdateItemsAndWeapon();
+// R_TimeReport("UpdateItems");
EntityFrameQuake_ISeeDeadEntities();
+// R_TimeReport("ISeeDeadEntities");
CL_UpdateMoveVars();
+// R_TimeReport("UpdateMoveVars");
parsingerror = false;
// LordHavoc: this was at the start of the function before cl_autodemo was
// implemented
if (cls.demorecording)
+ {
CL_WriteDemoMessage (&net_message);
+// R_TimeReport("WriteDemo");
+ }
}
void CL_Parse_DumpPacket(void)
void CL_Parse_Init(void)
{
- // LordHavoc: added demo_nehahra cvar
- Cvar_RegisterVariable (&demo_nehahra);
- if (gamemode == GAME_NEHAHRA)
- Cvar_SetValue("demo_nehahra", 1);
+ Cvar_RegisterVariable(&cl_worldmessage);
+ Cvar_RegisterVariable(&cl_worldname);
+ Cvar_RegisterVariable(&cl_worldnamenoextension);
+ Cvar_RegisterVariable(&cl_worldbasename);
+
Cvar_RegisterVariable(&developer_networkentities);
Cvar_RegisterVariable(&cl_gameplayfix_soundsmovewithentities);