X-Git-Url: http://git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=cl_parse.c;h=ecd250fc56da0f21100b204b00e5ff74cc9a1232;hp=8bf930c98b90d320247fcf8ba078ff108799c078;hb=2f5dfa4708db4112f682b31146a8db1d456a0482;hpb=7e3d1e3957d8b5f7c4586ac3a99af16f63e16c31 diff --git a/cl_parse.c b/cl_parse.c index 8bf930c9..ecd250fc 100644 --- a/cl_parse.c +++ b/cl_parse.c @@ -25,13 +25,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "csprogs.h" #include "libcurl.h" #include "utf8lib.h" +#ifdef CONFIG_MENU #include "menu.h" +#endif +#include "cl_video.h" +#include "float.h" const char *svc_strings[128] = { "svc_bad", "svc_nop", - "svc_disconnect", + "svc_disconnect", // (DP8) [string] null terminated parting message "svc_updatestat", "svc_version", // [int] server version "svc_setview", // [short] entity number @@ -161,110 +165,115 @@ const char *qw_svc_strings[128] = //============================================================================= -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 demo_nehahra = {0, "demo_nehahra", "0", "reads all quake demos as nehahra movie protocol"}; -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)"}; -cvar_t cl_sound_hknighthit = {0, "cl_sound_hknighthit", "hknight/hit.wav", "sound to play during TE_KNIGHTSPIKE (empty cvar disables sound)"}; -cvar_t cl_sound_tink1 = {0, "cl_sound_tink1", "weapons/tink1.wav", "sound to play with 80% chance during TE_SPIKE/TE_SUPERSPIKE (empty cvar disables sound)"}; -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)"}; -cvar_t cl_readpicture_force = {0, "cl_readpicture_force", "0", "when enabled, the low quality pictures read by ReadPicture() are preferred over the high quality pictures on the file system"}; +cvar_t cl_worldmessage = {CF_CLIENT | CF_READONLY, "cl_worldmessage", "", "title of current level"}; +cvar_t cl_worldname = {CF_CLIENT | CF_READONLY, "cl_worldname", "", "name of current worldmodel"}; +cvar_t cl_worldnamenoextension = {CF_CLIENT | CF_READONLY, "cl_worldnamenoextension", "", "name of current worldmodel without extension"}; +cvar_t cl_worldbasename = {CF_CLIENT | CF_READONLY, "cl_worldbasename", "", "name of current worldmodel without maps/ prefix or extension"}; + +cvar_t developer_networkentities = {CF_CLIENT, "developer_networkentities", "0", "prints received entities, value is 0-10 (higher for more info, 10 being the most verbose)"}; +cvar_t cl_gameplayfix_soundsmovewithentities = {CF_CLIENT, "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 = {CF_CLIENT, "cl_sound_wizardhit", "wizard/hit.wav", "sound to play during TE_WIZSPIKE (empty cvar disables sound)"}; +cvar_t cl_sound_hknighthit = {CF_CLIENT, "cl_sound_hknighthit", "hknight/hit.wav", "sound to play during TE_KNIGHTSPIKE (empty cvar disables sound)"}; +cvar_t cl_sound_tink1 = {CF_CLIENT, "cl_sound_tink1", "weapons/tink1.wav", "sound to play with 80% chance during TE_SPIKE/TE_SUPERSPIKE (empty cvar disables sound)"}; +cvar_t cl_sound_ric1 = {CF_CLIENT, "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 = {CF_CLIENT, "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 = {CF_CLIENT, "cl_sound_ric3", "weapons/ric3.wav", "sound to play with 10% chance during TE_SPIKE/TE_SUPERSPIKE (empty cvar disables sound)"}; +cvar_t cl_readpicture_force = {CF_CLIENT, "cl_readpicture_force", "0", "when enabled, the low quality pictures read by ReadPicture() are preferred over the high quality pictures on the file system"}; #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", "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"}; - -static qboolean QW_CL_CheckOrDownloadFile(const char *filename); +cvar_t cl_sound_ric_gunshot = {CF_CLIENT, "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 = {CF_CLIENT, "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 = {CF_CLIENT, "cl_serverextension_download", "0", "indicates whether the server supports the download command"}; +cvar_t cl_joinbeforedownloadsfinish = {CF_CLIENT | CF_ARCHIVE, "cl_joinbeforedownloadsfinish", "1", "if non-zero the game will begin after the map is loaded before other downloads finish"}; +cvar_t cl_nettimesyncfactor = {CF_CLIENT | CF_ARCHIVE, "cl_nettimesyncfactor", "0", "rate at which client time adapts to match server time, 1 = instantly, 0.125 = slowly, 0 = not at all (only applied in bound modes 0, 1, 2, 3)"}; +cvar_t cl_nettimesyncboundmode = {CF_CLIENT | CF_ARCHIVE, "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 = slightly nicer version of Quake3 method, 6 = tight bounding + mode 5, 7 = jitter compensated dynamic adjustment rate"}; +cvar_t cl_nettimesyncboundtolerance = {CF_CLIENT | CF_ARCHIVE, "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) (only affects bound modes 2 and 3)"}; +cvar_t cl_iplog_name = {CF_CLIENT | CF_ARCHIVE, "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"}; + +static qbool QW_CL_CheckOrDownloadFile(const char *filename); static void QW_CL_RequestNextDownload(void); -static void QW_CL_NextUpload(void); -void QW_CL_StartUpload(unsigned char *data, int size); -//static qboolean QW_CL_IsUploading(void); -static void QW_CL_StopUpload(void); -void CL_VM_UpdateIntermissionState(int intermission); -qboolean CL_VM_Event_Sound(int sound_num, float volume, int channel, float attenuation, int ent, vec3_t pos); +static void QW_CL_NextUpload_f(cmd_state_t *cmd); +//static qbool QW_CL_IsUploading(void); +static void QW_CL_StopUpload_f(cmd_state_t *cmd); /* ================== CL_ParseStartSoundPacket ================== */ -void CL_ParseStartSoundPacket(int largesoundindex) +static void CL_ParseStartSoundPacket(int largesoundindex) { vec3_t pos; int channel, ent; int sound_num; - int volume; + int nvolume; int field_mask; float attenuation; + float speed; + int fflags = CHANNELFLAG_NONE; if (cls.protocol == PROTOCOL_QUAKEWORLD) { - channel = MSG_ReadShort(); + channel = MSG_ReadShort(&cl_message); if (channel & (1<<15)) - volume = MSG_ReadByte (); + nvolume = MSG_ReadByte(&cl_message); else - volume = DEFAULT_SOUND_PACKET_VOLUME; + nvolume = DEFAULT_SOUND_PACKET_VOLUME; if (channel & (1<<14)) - attenuation = MSG_ReadByte () / 64.0; + attenuation = MSG_ReadByte(&cl_message) / 64.0; else attenuation = DEFAULT_SOUND_PACKET_ATTENUATION; + speed = 1.0f; + ent = (channel>>3)&1023; channel &= 7; - sound_num = MSG_ReadByte (); + sound_num = MSG_ReadByte(&cl_message); } else { - field_mask = MSG_ReadByte(); + field_mask = MSG_ReadByte(&cl_message); if (field_mask & SND_VOLUME) - volume = MSG_ReadByte (); + nvolume = MSG_ReadByte(&cl_message); else - volume = DEFAULT_SOUND_PACKET_VOLUME; + nvolume = DEFAULT_SOUND_PACKET_VOLUME; if (field_mask & SND_ATTENUATION) - attenuation = MSG_ReadByte () / 64.0; + attenuation = MSG_ReadByte(&cl_message) / 64.0; else attenuation = DEFAULT_SOUND_PACKET_ATTENUATION; + if (field_mask & SND_SPEEDUSHORT4000) + speed = ((unsigned short)MSG_ReadShort(&cl_message)) / 4000.0f; + else + speed = 1.0f; + if (field_mask & SND_LARGEENTITY) { - ent = (unsigned short) MSG_ReadShort (); - channel = MSG_ReadByte (); + ent = (unsigned short) MSG_ReadShort(&cl_message); + channel = MSG_ReadChar(&cl_message); } else { - channel = (unsigned short) MSG_ReadShort (); + channel = (unsigned short) MSG_ReadShort(&cl_message); ent = channel >> 3; channel &= 7; } if (largesoundindex || (field_mask & SND_LARGESOUND) || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3) - sound_num = (unsigned short) MSG_ReadShort (); + sound_num = (unsigned short) MSG_ReadShort(&cl_message); else - sound_num = MSG_ReadByte (); + sound_num = MSG_ReadByte(&cl_message); } - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); - if (sound_num >= MAX_SOUNDS) + if (sound_num < 0 || sound_num >= MAX_SOUNDS) { Con_Printf("CL_ParseStartSoundPacket: sound_num (%i) >= MAX_SOUNDS (%i)\n", sound_num, MAX_SOUNDS); return; @@ -279,8 +288,8 @@ void CL_ParseStartSoundPacket(int largesoundindex) if (ent >= cl.max_entities) CL_ExpandEntities(ent); - if( !CL_VM_Event_Sound(sound_num, volume / 255.0f, channel, attenuation, ent, pos) ) - S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0f, attenuation); + if( !CL_VM_Event_Sound(sound_num, nvolume / 255.0f, channel, attenuation, ent, pos, fflags, speed) ) + S_StartSound_StartPosition_Flags (ent, channel, cl.sound_precache[sound_num], pos, nvolume/255.0f, attenuation, 0, fflags, speed); } /* @@ -293,88 +302,97 @@ so the server doesn't disconnect. */ static unsigned char olddata[NET_MAXMESSAGE]; -void CL_KeepaliveMessage (qboolean readmessages) +void CL_KeepaliveMessage (qbool readmessages) { - float time; - static double nextmsg = -1; - static double nextupdate = -1; -#if 0 - static double lasttime = -1; -#endif - int oldreadcount; - qboolean oldbadread; + static double lastdirtytime = 0; + static qbool recursive = false; + double dirtytime; + double deltatime; + static double countdownmsg = 0; + static double countdownupdate = 0; sizebuf_t old; - if(cls.state != ca_dedicated) + qbool thisrecursive; + + thisrecursive = recursive; + recursive = true; + + dirtytime = Sys_DirtyTime(); + deltatime = dirtytime - lastdirtytime; + lastdirtytime = dirtytime; + if (deltatime <= 0 || deltatime >= 1800.0) + return; + + countdownmsg -= deltatime; + countdownupdate -= deltatime; + + if(!thisrecursive) { - if((time = Sys_DoubleTime()) >= nextupdate) + if(cls.state != ca_dedicated) { - SCR_UpdateLoadingScreenIfShown(); - nextupdate = time + 2; + if(countdownupdate <= 0) // check if time stepped backwards + { + SCR_UpdateLoadingScreenIfShown(); + countdownupdate = 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) + if (sv.active || !cls.netcon || cls.protocol == PROTOCOL_QUAKEWORLD || cls.signon >= SIGNONS) + { + recursive = thisrecursive; return; + } if (readmessages) { // read messages from server, should just be nops - oldreadcount = msg_readcount; - oldbadread = msg_badread; - old = net_message; - memcpy(olddata, net_message.data, net_message.cursize); + old = cl_message; + memcpy(olddata, cl_message.data, cl_message.cursize); NetConn_ClientFrame(); - msg_readcount = oldreadcount; - msg_badread = oldbadread; - net_message = old; - memcpy(net_message.data, olddata, net_message.cursize); + cl_message = old; + memcpy(cl_message.data, olddata, cl_message.cursize); } -#if 0 - if((time = Sys_DoubleTime()) >= lasttime + 1) - { - Con_Printf("long delta: %f\n", time - lasttime); - } - lasttime = Sys_DoubleTime(); -#endif - - if (cls.netcon && (time = Sys_DoubleTime()) >= nextmsg) + if (cls.netcon && countdownmsg <= 0) // check if time stepped backwards { sizebuf_t msg; unsigned char buf[4]; - nextmsg = time + 5; + countdownmsg = 5; // write out a nop - // LordHavoc: must use unreliable because reliable could kill the sigon message! + // LadyHavoc: must use unreliable because reliable could kill the sigon message! Con_Print("--> client to server keepalive\n"); memset(&msg, 0, sizeof(msg)); msg.data = buf; msg.maxsize = sizeof(buf); MSG_WriteChar(&msg, clc_nop); - NetConn_SendUnreliableMessage(cls.netcon, &msg, cls.protocol, 10000, false); + NetConn_SendUnreliableMessage(cls.netcon, &msg, cls.protocol, 10000, 0, false); } + + recursive = thisrecursive; } void CL_ParseEntityLump(char *entdata) { + qbool loadedsky = false; const char *data; char key[128], value[MAX_INPUTLINE]; - FOG_clear(); // LordHavoc: no fog until set - // LordHavoc: default to the map's sky (q3 shader parsing sets this) + FOG_clear(); // LadyHavoc: no fog until set + // LadyHavoc: default to the map's sky (q3 shader parsing sets this) R_SetSkyBox(cl.worldmodel->brush.skybox); data = entdata; if (!data) return; - if (!COM_ParseToken_Simple(&data, false, false)) + if (!COM_ParseToken_Simple(&data, false, false, true)) return; // error if (com_token[0] != '{') return; // error while (1) { - if (!COM_ParseToken_Simple(&data, false, false)) + if (!COM_ParseToken_Simple(&data, false, false, true)) return; // error if (com_token[0] == '}') break; // end of worldspawn @@ -384,15 +402,24 @@ 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_ParseToken_Simple(&data, false, false)) + if (!COM_ParseToken_Simple(&data, false, false, true)) return; // error strlcpy (value, com_token, sizeof (value)); if (!strcmp("sky", key)) + { + loadedsky = true; R_SetSkyBox(value); + } else if (!strcmp("skyname", key)) // non-standard, introduced by QuakeForge... sigh. + { + loadedsky = true; R_SetSkyBox(value); + } else if (!strcmp("qlsky", key)) // non-standard, introduced by QuakeLives (EEK) + { + loadedsky = true; R_SetSkyBox(value); + } else if (!strcmp("fog", key)) { FOG_clear(); // so missing values get good defaults @@ -435,14 +462,17 @@ void CL_ParseEntityLump(char *entdata) r_refdef.fog_height_texturename[63] = 0; } } + + if (!loadedsky && cl.worldmodel->brush.isq2bsp) + R_SetSkyBox("unit1_"); } -extern void CL_Locs_Reload_f(void); -extern void CL_VM_Init (void); +extern cvar_t con_chatsound_team_file; static const vec3_t defaultmins = {-4096, -4096, -4096}; static const vec3_t defaultmaxs = {4096, 4096, 4096}; static void CL_SetupWorldModel(void) { + prvm_prog_t *prog = CLVM_prog; // update the world model cl.entities[0].render.model = cl.worldmodel = CL_GetModelByIndex(1); CL_UpdateRenderEntity(&cl.entities[0].render); @@ -458,19 +488,19 @@ static void CL_SetupWorldModel(void) 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); + World_SetSize(&cl.world, cl.worldname, cl.worldmodel->normalmins, cl.worldmodel->normalmaxs, prog); } else { Cvar_SetQuick(&cl_worldmessage, cl.worldmessage); Cvar_SetQuick(&cl_worldnamenoextension, ""); Cvar_SetQuick(&cl_worldbasename, ""); - World_SetSize(&cl.world, "", defaultmins, defaultmaxs); + World_SetSize(&cl.world, "", defaultmins, defaultmaxs, prog); } World_Start(&cl.world); // load or reload .loc file for team chat messages - CL_Locs_Reload_f(); + CL_Locs_Reload_f(cmd_local); // make sure we send enough keepalives CL_KeepaliveMessage(false); @@ -482,13 +512,15 @@ static void CL_SetupWorldModel(void) CL_KeepaliveMessage(false); // load the team chat beep if possible - cl.foundtalk2wav = FS_FileExists("sound/misc/talk2.wav"); + cl.foundteamchatsound = FS_FileExists(con_chatsound_team_file.string); // check memory integrity Mem_CheckSentinelsGlobal(); +#ifdef CONFIG_MENU // make menu know MR_NewMap(); +#endif // load the csqc now if (cl.loadcsqc) @@ -499,9 +531,10 @@ static void CL_SetupWorldModel(void) } } -static qboolean QW_CL_CheckOrDownloadFile(const char *filename) +static qbool QW_CL_CheckOrDownloadFile(const char *filename) { qfile_t *file; + char vabuf[1024]; // see if the file already exists file = FS_OpenVirtualFile(filename, true); @@ -533,7 +566,7 @@ static qboolean QW_CL_CheckOrDownloadFile(const char *filename) } MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd); - MSG_WriteString(&cls.netcon->message, va("download %s", filename)); + MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "download %s", filename)); cls.qw_downloadnumber++; cls.qw_downloadpercent = 0; @@ -546,10 +579,17 @@ static void QW_CL_ProcessUserInfo(int slot); static void QW_CL_RequestNextDownload(void) { int i; + char vabuf[1024]; // clear name of file that just finished cls.qw_downloadname[0] = 0; + // skip the download fragment if playing a demo + if (!cls.netcon) + { + return; + } + switch (cls.qw_downloadtype) { case dl_single: @@ -562,7 +602,7 @@ static void QW_CL_RequestNextDownload(void) if (!cl.scores[cls.qw_downloadnumber].name[0]) continue; // check if we need to download the file, and return if so - if (!QW_CL_CheckOrDownloadFile(va("skins/%s.pcx", cl.scores[cls.qw_downloadnumber].qw_skin))) + if (!QW_CL_CheckOrDownloadFile(va(vabuf, sizeof(vabuf), "skins/%s.pcx", cl.scores[cls.qw_downloadnumber].qw_skin))) return; } @@ -578,7 +618,7 @@ static void QW_CL_RequestNextDownload(void) cls.signon = SIGNONS-1; // we'll go to SIGNONS when the first entity update is received MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd); - MSG_WriteString(&cls.netcon->message, va("begin %i", cl.qw_servercount)); + MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "begin %i", cl.qw_servercount)); } break; case dl_model: @@ -643,12 +683,12 @@ static void QW_CL_RequestNextDownload(void) CL_SetupWorldModel(); // add pmodel/emodel CRCs to userinfo - CL_SetInfo("pmodel", va("%i", FS_CRCFile("progs/player.mdl", NULL)), true, true, true, true); - CL_SetInfo("emodel", va("%i", FS_CRCFile("progs/eyes.mdl", NULL)), true, true, true, true); + CL_SetInfo("pmodel", va(vabuf, sizeof(vabuf), "%i", FS_CRCFile("progs/player.mdl", NULL)), true, true, true, true); + CL_SetInfo("emodel", va(vabuf, sizeof(vabuf), "%i", FS_CRCFile("progs/eyes.mdl", NULL)), true, true, true, true); // done checking sounds and models, send a prespawn command now MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd); - MSG_WriteString(&cls.netcon->message, va("prespawn %i 0 %i", cl.qw_servercount, cl.model_precache[1]->brush.qw_md4sum2)); + MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "prespawn %i 0 %i", cl.qw_servercount, cl.model_precache[1]->brush.qw_md4sum2)); if (cls.qw_downloadmemory) { @@ -669,7 +709,7 @@ static void QW_CL_RequestNextDownload(void) for (;cl.sound_name[cls.qw_downloadnumber][0];cls.qw_downloadnumber++) { // check if we need to download the file, and return if so - if (!QW_CL_CheckOrDownloadFile(va("sound/%s", cl.sound_name[cls.qw_downloadnumber]))) + if (!QW_CL_CheckOrDownloadFile(va(vabuf, sizeof(vabuf), "sound/%s", cl.sound_name[cls.qw_downloadnumber]))) return; } @@ -699,7 +739,7 @@ static void QW_CL_RequestNextDownload(void) // done with sound downloads, next we check models MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd); - MSG_WriteString(&cls.netcon->message, va("modellist %i %i", cl.qw_servercount, 0)); + MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "modellist %i %i", cl.qw_servercount, 0)); break; case dl_none: default: @@ -709,8 +749,8 @@ static void QW_CL_RequestNextDownload(void) static void QW_CL_ParseDownload(void) { - int size = (signed short)MSG_ReadShort(); - int percent = MSG_ReadByte(); + int size = (signed short)MSG_ReadShort(&cl_message); + int percent = MSG_ReadByte(&cl_message); //Con_Printf("download %i %i%% (%i/%i)\n", size, percent, cls.qw_downloadmemorycursize, cls.qw_downloadmemorymaxsize); @@ -718,7 +758,7 @@ static void QW_CL_ParseDownload(void) if (!cls.netcon) { if (size > 0) - msg_readcount += size; + cl_message.readcount += size; return; } @@ -729,7 +769,7 @@ static void QW_CL_ParseDownload(void) return; } - if (msg_readcount + (unsigned short)size > net_message.cursize) + if (cl_message.readcount + (unsigned short)size > cl_message.cursize) Host_Error("corrupt download message\n"); // make sure the buffer is big enough to include this new fragment @@ -748,7 +788,7 @@ static void QW_CL_ParseDownload(void) } // read the fragment out of the packet - MSG_ReadBytes(size, cls.qw_downloadmemory + cls.qw_downloadmemorycursize); + MSG_ReadBytes(&cl_message, size, cls.qw_downloadmemory + cls.qw_downloadmemorycursize); cls.qw_downloadmemorycursize += size; cls.qw_downloadspeedcount += size; @@ -777,13 +817,14 @@ static void QW_CL_ParseDownload(void) static void QW_CL_ParseModelList(void) { int n; - int nummodels = MSG_ReadByte(); + int nummodels = MSG_ReadByte(&cl_message); char *str; + char vabuf[1024]; // parse model precache list for (;;) { - str = MSG_ReadString(); + str = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); if (!str[0]) break; nummodels++; @@ -794,11 +835,11 @@ static void QW_CL_ParseModelList(void) strlcpy(cl.model_name[nummodels], str, sizeof (cl.model_name[nummodels])); } - n = MSG_ReadByte(); + n = MSG_ReadByte(&cl_message); if (n) { MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd); - MSG_WriteString(&cls.netcon->message, va("modellist %i %i", cl.qw_servercount, n)); + MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "modellist %i %i", cl.qw_servercount, n)); return; } @@ -811,13 +852,14 @@ static void QW_CL_ParseModelList(void) static void QW_CL_ParseSoundList(void) { int n; - int numsounds = MSG_ReadByte(); + int numsounds = MSG_ReadByte(&cl_message); char *str; + char vabuf[1024]; // parse sound precache list for (;;) { - str = MSG_ReadString(); + str = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); if (!str[0]) break; numsounds++; @@ -828,12 +870,12 @@ static void QW_CL_ParseSoundList(void) strlcpy(cl.sound_name[numsounds], str, sizeof (cl.sound_name[numsounds])); } - n = MSG_ReadByte(); + n = MSG_ReadByte(&cl_message); if (n) { MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd); - MSG_WriteString(&cls.netcon->message, va("soundlist %i %i", cl.qw_servercount, n)); + MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "soundlist %i %i", cl.qw_servercount, n)); return; } @@ -843,14 +885,14 @@ static void QW_CL_ParseSoundList(void) QW_CL_RequestNextDownload(); } -static void QW_CL_Skins_f(void) +static void QW_CL_Skins_f(cmd_state_t *cmd) { cls.qw_downloadnumber = 0; cls.qw_downloadtype = dl_skin; QW_CL_RequestNextDownload(); } -static void QW_CL_Changing_f(void) +static void QW_CL_Changing_f(cmd_state_t *cmd) { if (cls.qw_downloadmemory) // don't change when downloading return; @@ -861,7 +903,7 @@ static void QW_CL_Changing_f(void) Con_Printf("\nChanging map...\n"); } -void QW_CL_NextUpload(void) +void QW_CL_NextUpload_f(cmd_state_t *cmd) { int r, percent, size; @@ -888,7 +930,7 @@ void QW_CL_NextUpload(void) Con_Printf("Upload completed\n"); - QW_CL_StopUpload(); + QW_CL_StopUpload_f(cmd); } void QW_CL_StartUpload(unsigned char *data, int size) @@ -898,7 +940,7 @@ void QW_CL_StartUpload(unsigned char *data, int size) return; // abort existing upload if in progress - QW_CL_StopUpload(); + QW_CL_StopUpload_f(cmd_local); Con_DPrintf("Starting upload of %d bytes...\n", size); @@ -907,17 +949,17 @@ void QW_CL_StartUpload(unsigned char *data, int size) cls.qw_uploadsize = size; cls.qw_uploadpos = 0; - QW_CL_NextUpload(); + QW_CL_NextUpload_f(cmd_local); } #if 0 -qboolean QW_CL_IsUploading(void) +qbool QW_CL_IsUploading(void) { return cls.qw_uploaddata != NULL; } #endif -void QW_CL_StopUpload(void) +void QW_CL_StopUpload_f(cmd_state_t *cmd) { if (cls.qw_uploaddata) Mem_Free(cls.qw_uploaddata); @@ -946,16 +988,16 @@ static void QW_CL_ProcessUserInfo(int slot) static void QW_CL_UpdateUserInfo(void) { int slot; - slot = MSG_ReadByte(); + slot = MSG_ReadByte(&cl_message); if (slot >= cl.maxclients) { Con_Printf("svc_updateuserinfo >= cl.maxclients\n"); - MSG_ReadLong(); - MSG_ReadString(); + MSG_ReadLong(&cl_message); + MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); return; } - cl.scores[slot].qw_userid = MSG_ReadLong(); - strlcpy(cl.scores[slot].qw_userinfo, MSG_ReadString(), sizeof(cl.scores[slot].qw_userinfo)); + cl.scores[slot].qw_userid = MSG_ReadLong(&cl_message); + strlcpy(cl.scores[slot].qw_userinfo, MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof(cl.scores[slot].qw_userinfo)); QW_CL_ProcessUserInfo(slot); } @@ -965,9 +1007,9 @@ static void QW_CL_SetInfo(void) int slot; char key[2048]; char value[2048]; - slot = MSG_ReadByte(); - strlcpy(key, MSG_ReadString(), sizeof(key)); - strlcpy(value, MSG_ReadString(), sizeof(value)); + slot = MSG_ReadByte(&cl_message); + strlcpy(key, MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof(key)); + strlcpy(value, MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof(value)); if (slot >= cl.maxclients) { Con_Printf("svc_setinfo >= cl.maxclients\n"); @@ -983,8 +1025,8 @@ static void QW_CL_ServerInfo(void) char key[2048]; char value[2048]; char temp[32]; - strlcpy(key, MSG_ReadString(), sizeof(key)); - strlcpy(value, MSG_ReadString(), sizeof(value)); + strlcpy(key, MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof(key)); + strlcpy(value, MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof(value)); Con_DPrintf("SERVERINFO: %s=%s\n", key, value); InfoString_SetValue(cl.qw_serverinfo, sizeof(cl.qw_serverinfo), key, value); InfoString_GetValue(cl.qw_serverinfo, "teamplay", temp, sizeof(temp)); @@ -994,14 +1036,14 @@ static void QW_CL_ServerInfo(void) static void QW_CL_ParseNails(void) { int i, j; - int numnails = MSG_ReadByte(); + int numnails = MSG_ReadByte(&cl_message); vec_t *v; unsigned char bits[6]; for (i = 0;i < numnails;i++) { for (j = 0;j < 6;j++) - bits[j] = MSG_ReadByte(); - if (cl.qw_num_nails > 255) + bits[j] = MSG_ReadByte(&cl_message); + if (cl.qw_num_nails >= 255) continue; v = cl.qw_nails[cl.qw_num_nails++]; v[0] = ( ( bits[0] + ((bits[1]&15)<<8) ) <<1) - 4096; @@ -1036,8 +1078,9 @@ static void CL_UpdateItemsAndWeapon(void) #define LOADPROGRESSWEIGHT_WORLDMODEL 30.0 #define LOADPROGRESSWEIGHT_WORLDMODEL_INIT 2.0 -void CL_BeginDownloads(qboolean aborteddownload) +static void CL_BeginDownloads(qbool aborteddownload) { + char vabuf[1024]; // quakeworld works differently if (cls.protocol == PROTOCOL_QUAKEWORLD) return; @@ -1052,7 +1095,7 @@ void CL_BeginDownloads(qboolean aborteddownload) // if we got here... // curl is done, so let's start with the business if(!cl.loadbegun) - SCR_PushLoadingScreen(false, "Loading precaches", 1); + SCR_PushLoadingScreen("Loading precaches", 1); cl.loadbegun = true; // if already downloading something from the previous level, don't stop it @@ -1070,13 +1113,13 @@ void CL_BeginDownloads(qboolean aborteddownload) && csqc_progcrc.integer >= 0 && cl_serverextension_download.integer && (FS_CRCFile(csqc_progname.string, &progsize) != csqc_progcrc.integer || ((int)progsize != csqc_progsize.integer && csqc_progsize.integer != -1)) - && !FS_FileExists(va("dlcache/%s.%i.%i", csqc_progname.string, csqc_progsize.integer, csqc_progcrc.integer))) + && !FS_FileExists(va(vabuf, sizeof(vabuf), "dlcache/%s.%i.%i", csqc_progname.string, csqc_progsize.integer, csqc_progcrc.integer))) { Con_Printf("Downloading new CSQC code to dlcache/%s.%i.%i\n", csqc_progname.string, csqc_progsize.integer, csqc_progcrc.integer); if(cl_serverextension_download.integer == 2 && FS_HasZlib()) - Cmd_ForwardStringToServer(va("download %s deflate", csqc_progname.string)); + CL_ForwardToServer(va(vabuf, sizeof(vabuf), "download %s deflate", csqc_progname.string)); else - Cmd_ForwardStringToServer(va("download %s", csqc_progname.string)); + CL_ForwardToServer(va(vabuf, sizeof(vabuf), "download %s", csqc_progname.string)); return; } } @@ -1087,7 +1130,7 @@ void CL_BeginDownloads(qboolean aborteddownload) if(cl.loadmodel_current == 1) { // worldmodel counts as 16 models (15 + world model setup), for better progress bar - SCR_PushLoadingScreen(false, "Loading precached models", + SCR_PushLoadingScreen("Loading precached models", ( (cl.loadmodel_total - 1) * LOADPROGRESSWEIGHT_MODEL + LOADPROGRESSWEIGHT_WORLDMODEL @@ -1099,11 +1142,10 @@ void CL_BeginDownloads(qboolean aborteddownload) + cl.loadsound_total * LOADPROGRESSWEIGHT_SOUND ) ); - SCR_BeginLoadingPlaque(); } for (;cl.loadmodel_current < cl.loadmodel_total;cl.loadmodel_current++) { - SCR_PushLoadingScreen(false, cl.model_name[cl.loadmodel_current], + SCR_PushLoadingScreen(cl.model_name[cl.loadmodel_current], ( (cl.loadmodel_current == 1) ? LOADPROGRESSWEIGHT_WORLDMODEL : LOADPROGRESSWEIGHT_MODEL ) / ( @@ -1117,7 +1159,7 @@ void CL_BeginDownloads(qboolean aborteddownload) SCR_PopLoadingScreen(false); if(cl.loadmodel_current == 1) { - SCR_PushLoadingScreen(false, cl.model_name[cl.loadmodel_current], 1.0 / cl.loadmodel_total); + SCR_PushLoadingScreen(cl.model_name[cl.loadmodel_current], 1.0 / cl.loadmodel_total); SCR_PopLoadingScreen(false); } continue; @@ -1140,7 +1182,7 @@ void CL_BeginDownloads(qboolean aborteddownload) 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", + SCR_PushLoadingScreen("world model setup", ( LOADPROGRESSWEIGHT_WORLDMODEL_INIT ) / ( @@ -1156,7 +1198,7 @@ void CL_BeginDownloads(qboolean aborteddownload) cl.loadfinished = true; // now issue the spawn to move on to signon 2 like normal if (cls.netcon) - Cmd_ForwardStringToServer("prespawn"); + CL_ForwardToServer("prespawn"); } } } @@ -1168,7 +1210,7 @@ void CL_BeginDownloads(qboolean aborteddownload) { // loading sounds if(cl.loadsound_current == 1) - SCR_PushLoadingScreen(false, "Loading precached sounds", + SCR_PushLoadingScreen("Loading precached sounds", ( cl.loadsound_total * LOADPROGRESSWEIGHT_SOUND ) / ( @@ -1180,7 +1222,7 @@ void CL_BeginDownloads(qboolean aborteddownload) ); for (;cl.loadsound_current < cl.loadsound_total;cl.loadsound_current++) { - SCR_PushLoadingScreen(false, cl.sound_name[cl.loadsound_current], 1.0 / cl.loadsound_total); + SCR_PushLoadingScreen(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); @@ -1194,7 +1236,7 @@ void CL_BeginDownloads(qboolean aborteddownload) // finished loading sounds } - if(gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC) + if(IS_NEXUIZ_DERIVED(gamemode)) Cvar_SetValueQuick(&cl_serverextension_download, false); // in Nexuiz/Xonotic, the built in download protocol is kinda broken (misses lots // of dependencies) anyway, and can mess around with the game directory; @@ -1226,7 +1268,7 @@ void CL_BeginDownloads(qboolean aborteddownload) cl.loadfinished = true; // now issue the spawn to move on to signon 2 like normal if (cls.netcon) - Cmd_ForwardStringToServer("prespawn"); + CL_ForwardToServer("prespawn"); } } aborteddownload = false; @@ -1244,7 +1286,7 @@ void CL_BeginDownloads(qboolean aborteddownload) // regarding the * check: don't try to download submodels if (cl_serverextension_download.integer && cls.netcon && cl.model_name[cl.downloadmodel_current][0] != '*' && !sv.active) { - Cmd_ForwardStringToServer(va("download %s", cl.model_name[cl.downloadmodel_current])); + CL_ForwardToServer(va(vabuf, sizeof(vabuf), "download %s", cl.model_name[cl.downloadmodel_current])); // we'll try loading again when the download finishes return; } @@ -1256,7 +1298,7 @@ void CL_BeginDownloads(qboolean aborteddownload) 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); + cl.model_precache[cl.downloadmodel_current] = Mod_ForName(cl.model_name[cl.downloadmodel_current], false, true, cl.model_name[cl.downloadmodel_current][0] == '*' ? cl.model_name[1] : NULL); if (cl.downloadmodel_current == 1) { // we now have the worldmodel so we can set up the game world @@ -1268,7 +1310,7 @@ void CL_BeginDownloads(qboolean aborteddownload) cl.loadfinished = true; // now issue the spawn to move on to signon 2 like normal if (cls.netcon) - Cmd_ForwardStringToServer("prespawn"); + CL_ForwardToServer("prespawn"); } } } @@ -1294,10 +1336,9 @@ void CL_BeginDownloads(qboolean aborteddownload) dpsnprintf(soundname, sizeof(soundname), "sound/%s", cl.sound_name[cl.downloadsound_current]); if (!FS_FileExists(soundname) && !FS_FileExists(cl.sound_name[cl.downloadsound_current])) { - Con_Printf("Sound %s not found\n", soundname); if (cl_serverextension_download.integer && cls.netcon && !sv.active) { - Cmd_ForwardStringToServer(va("download %s", soundname)); + CL_ForwardToServer(va(vabuf, sizeof(vabuf), "download %s", soundname)); // we'll try loading again when the download finishes return; } @@ -1319,11 +1360,11 @@ void CL_BeginDownloads(qboolean aborteddownload) // now issue the spawn to move on to signon 2 like normal if (cls.netcon) - Cmd_ForwardStringToServer("prespawn"); + CL_ForwardToServer("prespawn"); } } -void CL_BeginDownloads_f(void) +static void CL_BeginDownloads_f(cmd_state_t *cmd) { // prevent cl_begindownloads from being issued multiple times in one match // to prevent accidentally cancelled downloads @@ -1333,7 +1374,7 @@ void CL_BeginDownloads_f(void) CL_BeginDownloads(false); } -void CL_StopDownload(int size, int crc) +static void CL_StopDownload(int size, int crc) { if (cls.qw_downloadmemory && cls.qw_downloadmemorycursize == size && CRC_Block(cls.qw_downloadmemory, cls.qw_downloadmemorycursize) == crc) { @@ -1351,7 +1392,7 @@ void CL_StopDownload(int size, int crc) { 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; + cls.qw_downloadmemorycursize = (int)inflated_size; } else { @@ -1373,7 +1414,7 @@ void CL_StopDownload(int size, int crc) // 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 || gamemode == GAME_XONOTIC || !strcmp(cls.qw_downloadname, csqc_progname.string)) + if (existingsize || IS_NEXUIZ_DERIVED(gamemode) || !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) @@ -1385,6 +1426,15 @@ void CL_StopDownload(int size, int crc) { Con_Printf("Downloaded \"%s\" (%i bytes, %i CRC)\n", name, size, crc); FS_WriteFile(name, cls.qw_downloadmemory, cls.qw_downloadmemorycursize); + if(!strcmp(cls.qw_downloadname, csqc_progname.string)) + { + if(cls.caughtcsprogsdata) + Mem_Free(cls.caughtcsprogsdata); + cls.caughtcsprogsdata = (unsigned char *) Mem_Alloc(cls.permanentmempool, cls.qw_downloadmemorycursize); + memcpy(cls.caughtcsprogsdata, cls.qw_downloadmemory, cls.qw_downloadmemorycursize); + cls.caughtcsprogsdatasize = cls.qw_downloadmemorycursize; + Con_DPrintf("Buffered \"%s\"\n", name); + } } } } @@ -1398,7 +1448,7 @@ void CL_StopDownload(int size, int crc) Con_Printf("Downloaded \"%s\" (%i bytes, %i CRC)\n", cls.qw_downloadname, size, crc); FS_WriteFile(cls.qw_downloadname, cls.qw_downloadmemory, cls.qw_downloadmemorycursize); extension = FS_FileExtension(cls.qw_downloadname); - if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3")) + if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3") || !strcasecmp(extension, "dpk")) FS_Rescan(); } } @@ -1418,12 +1468,12 @@ void CL_StopDownload(int size, int crc) cls.qw_downloadpercent = 0; } -void CL_ParseDownload(void) +static void CL_ParseDownload(void) { int i, start, size; static unsigned char data[NET_MAXMESSAGE]; - start = MSG_ReadLong(); - size = (unsigned short)MSG_ReadShort(); + start = MSG_ReadLong(&cl_message); + size = (unsigned short)MSG_ReadShort(&cl_message); // record the start/size information to ack in the next input packet for (i = 0;i < CL_MAX_DOWNLOADACKS;i++) @@ -1436,7 +1486,7 @@ void CL_ParseDownload(void) } } - MSG_ReadBytes(size, data); + MSG_ReadBytes(&cl_message, size, data); if (!cls.qw_downloadname[0]) { @@ -1457,11 +1507,11 @@ void CL_ParseDownload(void) cls.qw_downloadspeedcount += size; } -void CL_DownloadBegin_f(void) +static void CL_DownloadBegin_f(cmd_state_t *cmd) { - int size = atoi(Cmd_Argv(1)); + int size = atoi(Cmd_Argv(cmd, 1)); - if (size < 0 || size > 1<<30 || FS_CheckNastyPath(Cmd_Argv(2), false)) + if (size < 0 || size > 1<<30 || FS_CheckNastyPath(Cmd_Argv(cmd, 2), false)) { Con_Printf("cl_downloadbegin: received bogus information\n"); CL_StopDownload(0, 0); @@ -1474,23 +1524,23 @@ void CL_DownloadBegin_f(void) CL_StopDownload(0, 0); // we're really beginning a download now, so initialize stuff - strlcpy(cls.qw_downloadname, Cmd_Argv(2), sizeof(cls.qw_downloadname)); + strlcpy(cls.qw_downloadname, Cmd_Argv(cmd, 2), sizeof(cls.qw_downloadname)); cls.qw_downloadmemorymaxsize = size; cls.qw_downloadmemory = (unsigned char *) Mem_Alloc(cls.permanentmempool, cls.qw_downloadmemorymaxsize); cls.qw_downloadnumber++; cls.qw_download_deflate = false; - if(Cmd_Argc() >= 4) + if(Cmd_Argc(cmd) >= 4) { - if(!strcmp(Cmd_Argv(3), "deflate")) + if(!strcmp(Cmd_Argv(cmd, 3), "deflate")) cls.qw_download_deflate = true; // check further encodings here } - Cmd_ForwardStringToServer("sv_startdownload"); + CL_ForwardToServer("sv_startdownload"); } -void CL_StopDownload_f(void) +static void CL_StopDownload_f(cmd_state_t *cmd) { Curl_CancelAll(); if (cls.qw_downloadname[0]) @@ -1501,42 +1551,48 @@ void CL_StopDownload_f(void) CL_BeginDownloads(true); } -void CL_DownloadFinished_f(void) +static void CL_DownloadFinished_f(cmd_state_t *cmd) { - if (Cmd_Argc() < 3) + if (Cmd_Argc(cmd) < 3) { Con_Printf("Malformed cl_downloadfinished command\n"); return; } - CL_StopDownload(atoi(Cmd_Argv(1)), atoi(Cmd_Argv(2))); + CL_StopDownload(atoi(Cmd_Argv(cmd, 1)), atoi(Cmd_Argv(cmd, 2))); CL_BeginDownloads(false); } +extern cvar_t cl_topcolor; +extern cvar_t cl_bottomcolor; static void CL_SendPlayerInfo(void) { + char vabuf[1024]; + MSG_WriteByte (&cls.netcon->message, clc_stringcmd); + MSG_WriteString (&cls.netcon->message, va(vabuf, sizeof(vabuf), "name \"%s\"", cl_name.string)); + MSG_WriteByte (&cls.netcon->message, clc_stringcmd); - MSG_WriteString (&cls.netcon->message, va("name \"%s\"", cl_name.string)); + MSG_WriteString (&cls.netcon->message, va(vabuf, sizeof(vabuf), "color %i %i", cl_topcolor.integer, cl_bottomcolor.integer)); MSG_WriteByte (&cls.netcon->message, clc_stringcmd); - MSG_WriteString (&cls.netcon->message, va("color %i %i", cl_color.integer >> 4, cl_color.integer & 15)); + MSG_WriteString (&cls.netcon->message, va(vabuf, sizeof(vabuf), "rate %i", cl_rate.integer)); MSG_WriteByte (&cls.netcon->message, clc_stringcmd); - MSG_WriteString (&cls.netcon->message, va("rate %i", cl_rate.integer)); + MSG_WriteString (&cls.netcon->message, va(vabuf, sizeof(vabuf), "rate_burstsize %i", cl_rate_burstsize.integer)); if (cl_pmodel.integer) { MSG_WriteByte (&cls.netcon->message, clc_stringcmd); - MSG_WriteString (&cls.netcon->message, va("pmodel %i", cl_pmodel.integer)); + MSG_WriteString (&cls.netcon->message, va(vabuf, sizeof(vabuf), "pmodel %i", cl_pmodel.integer)); } if (*cl_playermodel.string) { MSG_WriteByte (&cls.netcon->message, clc_stringcmd); - MSG_WriteString (&cls.netcon->message, va("playermodel %s", cl_playermodel.string)); + MSG_WriteString (&cls.netcon->message, va(vabuf, sizeof(vabuf), "playermodel %s", cl_playermodel.string)); } if (*cl_playerskin.string) { MSG_WriteByte (&cls.netcon->message, clc_stringcmd); - MSG_WriteString (&cls.netcon->message, va("playerskin %s", cl_playerskin.string)); + MSG_WriteString (&cls.netcon->message, va(vabuf, sizeof(vabuf), "playerskin %s", cl_playerskin.string)); } } @@ -1563,7 +1619,7 @@ static void CL_SignonReply (void) // execute cl_begindownloads next frame // (after any commands added by svc_stufftext have been executed) // when done with downloads the "prespawn" will be sent - Cbuf_AddText("\ncl_begindownloads\n"); + Cbuf_AddText(cmd_local, "\ncl_begindownloads\n"); //MSG_WriteByte (&cls.netcon->message, clc_stringcmd); //MSG_WriteString (&cls.netcon->message, "prespawn"); @@ -1575,11 +1631,11 @@ static void CL_SignonReply (void) case 2: if (cls.netcon) { - // LordHavoc: quake sent the player info here but due to downloads + // LadyHavoc: quake sent the player info here but due to downloads // it is sent earlier instead // CL_SendPlayerInfo(); - // LordHavoc: changed to begin a loading stage and issue this when done + // LadyHavoc: changed to begin a loading stage and issue this when done MSG_WriteByte (&cls.netcon->message, clc_stringcmd); MSG_WriteString (&cls.netcon->message, "spawn"); } @@ -1602,7 +1658,7 @@ static void CL_SignonReply (void) S_PurgeUnused(); Con_ClearNotify(); - if (COM_CheckParm("-profilegameonly")) + if (Sys_CheckParm("-profilegameonly")) Sys_AllowProfiling(true); break; } @@ -1613,19 +1669,24 @@ static void CL_SignonReply (void) CL_ParseServerInfo ================== */ -void CL_ParseServerInfo (void) +static void CL_ParseServerInfo (void) { char *str; int i; protocolversion_t protocol; int nummodels, numsounds; + char vabuf[1024]; + + // 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) { - SCR_BeginLoadingPlaque(); + SCR_BeginLoadingPlaque(false); S_StopAllSounds(); // free q3 shaders so that any newly downloaded shaders will be active Mod_FreeQ3Shaders(); @@ -1643,7 +1704,7 @@ void CL_ParseServerInfo (void) CL_ClearState (); // parse protocol version number - i = MSG_ReadLong (); + i = MSG_ReadLong(&cl_message); protocol = Protocol_EnumForNumber(i); if (protocol == PROTOCOL_UNKNOWN) { @@ -1651,10 +1712,10 @@ void CL_ParseServerInfo (void) 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)); + Con_Printf("Server protocol is %s\n", Protocol_NameForEnum(cls.protocol)); cl.num_entities = 1; @@ -1662,9 +1723,9 @@ void CL_ParseServerInfo (void) { char gamedir[1][MAX_QPATH]; - cl.qw_servercount = MSG_ReadLong(); + cl.qw_servercount = MSG_ReadLong(&cl_message); - str = MSG_ReadString(); + str = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); Con_Printf("server gamedir is %s\n", str); strlcpy(gamedir[0], str, sizeof(gamedir[0])); @@ -1676,27 +1737,27 @@ void CL_ParseServerInfo (void) cl.maxclients = 32; // parse player number - i = MSG_ReadByte(); + i = MSG_ReadByte(&cl_message); // cl.qw_spectator is an unneeded flag, cl.scores[cl.playerentity].qw_spectator works better (it can be updated by the server during the game) //cl.qw_spectator = (i & 128) != 0; cl.realplayerentity = cl.playerentity = cl.viewentity = (i & 127) + 1; cl.scores = (scoreboard_t *)Mem_Alloc(cls.levelmempool, cl.maxclients*sizeof(*cl.scores)); // get the full level name - str = MSG_ReadString (); + str = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); strlcpy (cl.worldmessage, str, sizeof(cl.worldmessage)); // 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(); + cl.movevars_gravity = MSG_ReadFloat(&cl_message); + cl.movevars_stopspeed = MSG_ReadFloat(&cl_message); + cl.movevars_maxspeed = MSG_ReadFloat(&cl_message); + cl.movevars_spectatormaxspeed = MSG_ReadFloat(&cl_message); + cl.movevars_accelerate = MSG_ReadFloat(&cl_message); + cl.movevars_airaccelerate = MSG_ReadFloat(&cl_message); + cl.movevars_wateraccelerate = MSG_ReadFloat(&cl_message); + cl.movevars_friction = MSG_ReadFloat(&cl_message); + cl.movevars_waterfriction = MSG_ReadFloat(&cl_message); + cl.movevars_entgravity = MSG_ReadFloat(&cl_message); // other movevars not in the protocol... cl.movevars_wallfriction = 0; @@ -1717,7 +1778,7 @@ void CL_ParseServerInfo (void) if (cls.netcon) { MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd); - MSG_WriteString(&cls.netcon->message, va("soundlist %i %i", cl.qw_servercount, 0)); + MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "soundlist %i %i", cl.qw_servercount, 0)); } cl.loadbegun = false; @@ -1744,7 +1805,7 @@ void CL_ParseServerInfo (void) else { // parse maxclients - cl.maxclients = MSG_ReadByte (); + cl.maxclients = MSG_ReadByte(&cl_message); if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD) { Host_Error("Bad maxclients (%u) from server", cl.maxclients); @@ -1753,14 +1814,14 @@ void CL_ParseServerInfo (void) cl.scores = (scoreboard_t *)Mem_Alloc(cls.levelmempool, cl.maxclients*sizeof(*cl.scores)); // parse gametype - cl.gametype = MSG_ReadByte (); + cl.gametype = MSG_ReadByte(&cl_message); // the original id singleplayer demos are bugged and contain // GAME_DEATHMATCH even for singleplayer if (cl.maxclients == 1 && cls.protocol == PROTOCOL_QUAKE) cl.gametype = GAME_COOP; // parse signon message - str = MSG_ReadString (); + str = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); strlcpy (cl.worldmessage, str, sizeof(cl.worldmessage)); // seperate the printfs so the server message can have a color @@ -1773,7 +1834,7 @@ void CL_ParseServerInfo (void) // parse model precache list for (nummodels=1 ; ; nummodels++) { - str = MSG_ReadString(); + str = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); if (!str[0]) break; if (nummodels==MAX_MODELS) @@ -1785,7 +1846,7 @@ void CL_ParseServerInfo (void) // parse sound precache list for (numsounds=1 ; ; numsounds++) { - str = MSG_ReadString(); + str = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); if (!str[0]) break; if (numsounds==MAX_SOUNDS) @@ -1859,7 +1920,7 @@ void CL_ParseServerInfo (void) if (cls.demorecording) { // finish the previous level's demo file - CL_Stop_f(); + CL_Stop_f(cmd_local); } // start a new demo file @@ -1885,14 +1946,15 @@ void CL_ParseServerInfo (void) cls.demo_lastcsprogscrc = -1; } else - Con_Print ("ERROR: couldn't open.\n"); + Con_Print(CON_ERROR "ERROR: couldn't open.\n"); } } + cl.islocalgame = NetConn_IsLocalGame(); } void CL_ValidateState(entity_state_t *s) { - dp_model_t *model; + model_t *model; if (!s->active) return; @@ -2006,11 +2068,7 @@ void CL_MoveLerpEntityStates(entity_t *ent) { // not a monster ent->persistent.lerpstarttime = ent->state_previous.time; - // no lerp if it's singleplayer - if (cl.islocalgame && !sv_fixedframeratesingleplayer.integer) - ent->persistent.lerpdeltatime = 0; - else - ent->persistent.lerpdeltatime = bound(0, ent->state_current.time - ent->state_previous.time, 0.1); + ent->persistent.lerpdeltatime = bound(0, ent->state_current.time - ent->state_previous.time, 0.1); VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin); VectorCopy(ent->persistent.newangles, ent->persistent.oldangles); VectorCopy(ent->state_current.origin, ent->persistent.neworigin); @@ -2019,6 +2077,16 @@ void CL_MoveLerpEntityStates(entity_t *ent) // 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; + } } /* @@ -2026,7 +2094,7 @@ void CL_MoveLerpEntityStates(entity_t *ent) CL_ParseBaseline ================== */ -void CL_ParseBaseline (entity_t *ent, int large) +static void CL_ParseBaseline (entity_t *ent, int large) { int i; @@ -2035,25 +2103,25 @@ void CL_ParseBaseline (entity_t *ent, int large) ent->state_baseline.active = true; if (large) { - ent->state_baseline.modelindex = (unsigned short) MSG_ReadShort (); - ent->state_baseline.frame = (unsigned short) MSG_ReadShort (); + ent->state_baseline.modelindex = (unsigned short) MSG_ReadShort(&cl_message); + ent->state_baseline.frame = (unsigned short) MSG_ReadShort(&cl_message); } else if (cls.protocol == PROTOCOL_NEHAHRABJP || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3) { - ent->state_baseline.modelindex = (unsigned short) MSG_ReadShort (); - ent->state_baseline.frame = MSG_ReadByte (); + ent->state_baseline.modelindex = (unsigned short) MSG_ReadShort(&cl_message); + ent->state_baseline.frame = MSG_ReadByte(&cl_message); } else { - ent->state_baseline.modelindex = MSG_ReadByte (); - ent->state_baseline.frame = MSG_ReadByte (); + ent->state_baseline.modelindex = MSG_ReadByte(&cl_message); + ent->state_baseline.frame = MSG_ReadByte(&cl_message); } - ent->state_baseline.colormap = MSG_ReadByte(); - ent->state_baseline.skin = MSG_ReadByte(); + ent->state_baseline.colormap = MSG_ReadByte(&cl_message); + ent->state_baseline.skin = MSG_ReadByte(&cl_message); for (i = 0;i < 3;i++) { - ent->state_baseline.origin[i] = MSG_ReadCoord(cls.protocol); - ent->state_baseline.angles[i] = MSG_ReadAngle(cls.protocol); + ent->state_baseline.origin[i] = MSG_ReadCoord(&cl_message, cls.protocol); + ent->state_baseline.angles[i] = MSG_ReadAngle(&cl_message, cls.protocol); } ent->state_previous = ent->state_current = ent->state_baseline; } @@ -2066,7 +2134,7 @@ CL_ParseClientdata Server information pertaining to this client only ================== */ -void CL_ParseClientdata (void) +static void CL_ParseClientdata (void) { int i, bits; @@ -2093,89 +2161,89 @@ void CL_ParseClientdata (void) cl.mvelocity[0][2] = 0; cl.mviewzoom[0] = 1; - bits = (unsigned short) MSG_ReadShort (); + bits = (unsigned short) MSG_ReadShort(&cl_message); if (bits & SU_EXTEND1) - bits |= (MSG_ReadByte() << 16); + bits |= (MSG_ReadByte(&cl_message) << 16); if (bits & SU_EXTEND2) - bits |= (MSG_ReadByte() << 24); + bits |= (MSG_ReadByte(&cl_message) << 24); if (bits & SU_VIEWHEIGHT) - cl.stats[STAT_VIEWHEIGHT] = MSG_ReadChar (); + cl.stats[STAT_VIEWHEIGHT] = MSG_ReadChar(&cl_message); if (bits & SU_IDEALPITCH) - cl.idealpitch = MSG_ReadChar (); + cl.idealpitch = MSG_ReadChar(&cl_message); for (i = 0;i < 3;i++) { if (bits & (SU_PUNCH1<= MAX_SOUNDS) + { + Con_Printf("CL_ParseStaticSound: sound_num(%i) >= MAX_SOUNDS (%i)\n", sound_num, MAX_SOUNDS); + return; + } + + vol = MSG_ReadByte(&cl_message); + atten = MSG_ReadByte(&cl_message); S_StaticSound (cl.sound_precache[sound_num], org, vol/255.0f, atten); } -void CL_ParseEffect (void) +static void CL_ParseEffect (void) { vec3_t org; int modelindex, startframe, framecount, framerate; - MSG_ReadVector(org, cls.protocol); - modelindex = MSG_ReadByte (); - startframe = MSG_ReadByte (); - framecount = MSG_ReadByte (); - framerate = MSG_ReadByte (); + MSG_ReadVector(&cl_message, org, cls.protocol); + modelindex = MSG_ReadByte(&cl_message); + startframe = MSG_ReadByte(&cl_message); + framecount = MSG_ReadByte(&cl_message); + framerate = MSG_ReadByte(&cl_message); - CL_Effect(org, modelindex, startframe, framecount, framerate); + CL_Effect(org, CL_GetModelByIndex(modelindex), startframe, framecount, framerate); } -void CL_ParseEffect2 (void) +static void CL_ParseEffect2 (void) { vec3_t org; int modelindex, startframe, framecount, framerate; - MSG_ReadVector(org, cls.protocol); - modelindex = (unsigned short) MSG_ReadShort (); - startframe = (unsigned short) MSG_ReadShort (); - framecount = MSG_ReadByte (); - framerate = MSG_ReadByte (); + MSG_ReadVector(&cl_message, org, cls.protocol); + modelindex = (unsigned short) MSG_ReadShort(&cl_message); + startframe = (unsigned short) MSG_ReadShort(&cl_message); + framecount = MSG_ReadByte(&cl_message); + framerate = MSG_ReadByte(&cl_message); - CL_Effect(org, modelindex, startframe, framecount, framerate); + CL_Effect(org, CL_GetModelByIndex(modelindex), startframe, framecount, framerate); } -void CL_NewBeam (int ent, vec3_t start, vec3_t end, dp_model_t *m, int lightning) +void CL_NewBeam (int ent, vec3_t start, vec3_t end, model_t *m, int lightning) { int i; beam_t *b = NULL; @@ -2307,17 +2382,17 @@ void CL_NewBeam (int ent, vec3_t start, vec3_t end, dp_model_t *m, int lightning VectorCopy (end, b->end); } else - Con_Print("beam list overflow!\n"); + Con_DPrint("beam list overflow!\n"); } -void CL_ParseBeam (dp_model_t *m, int lightning) +static void CL_ParseBeam (model_t *m, int lightning) { int ent; vec3_t start, end; - ent = (unsigned short) MSG_ReadShort (); - MSG_ReadVector(start, cls.protocol); - MSG_ReadVector(end, cls.protocol); + ent = (unsigned short) MSG_ReadShort(&cl_message); + MSG_ReadVector(&cl_message, start, cls.protocol); + MSG_ReadVector(&cl_message, end, cls.protocol); if (ent >= MAX_EDICTS) { @@ -2328,7 +2403,7 @@ void CL_ParseBeam (dp_model_t *m, int lightning) CL_NewBeam(ent, start, end, m, lightning); } -void CL_ParseTempEntity(void) +static void CL_ParseTempEntity(void) { int type; vec3_t pos, pos2; @@ -2343,12 +2418,12 @@ void CL_ParseTempEntity(void) if (cls.protocol == PROTOCOL_QUAKEWORLD) { - type = MSG_ReadByte(); + type = MSG_ReadByte(&cl_message); switch (type) { case QW_TE_WIZSPIKE: // spike hitting wall - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 4); CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); S_StartSound(-1, 0, cl.sfx_wizhit, pos, 1, 1); @@ -2356,7 +2431,7 @@ void CL_ParseTempEntity(void) case QW_TE_KNIGHTSPIKE: // spike hitting wall - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 4); CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); S_StartSound(-1, 0, cl.sfx_knighthit, pos, 1, 1); @@ -2364,7 +2439,7 @@ void CL_ParseTempEntity(void) case QW_TE_SPIKE: // spike hitting wall - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 4); CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); if (rand() % 5) @@ -2382,7 +2457,7 @@ void CL_ParseTempEntity(void) break; case QW_TE_SUPERSPIKE: // super spike hitting wall - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 4); CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); if (rand() % 5) @@ -2401,16 +2476,16 @@ void CL_ParseTempEntity(void) case QW_TE_EXPLOSION: // rocket explosion - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 10); CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1); - CL_Effect(pos, cl.qw_modelindex_s_explod, 0, 6, 10); + CL_Effect(pos, CL_GetModelByIndex(cl.qw_modelindex_s_explod), 0, 6, 10); break; case QW_TE_TAREXPLOSION: // tarbaby explosion - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 10); CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1); @@ -2432,19 +2507,19 @@ void CL_ParseTempEntity(void) break; case QW_TE_LAVASPLASH: - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); break; case QW_TE_TELEPORT: - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); break; case QW_TE_GUNSHOT: // bullet hitting wall - radius = MSG_ReadByte(); - MSG_ReadVector(pos, cls.protocol); + radius = MSG_ReadByte(&cl_message); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 4); VectorSet(pos2, pos[0] + radius, pos[1] + radius, pos[2] + radius); VectorSet(pos, pos[0] - radius, pos[1] - radius, pos[2] - radius); @@ -2467,14 +2542,14 @@ void CL_ParseTempEntity(void) break; case QW_TE_BLOOD: - count = MSG_ReadByte(); - MSG_ReadVector(pos, cls.protocol); + count = MSG_ReadByte(&cl_message); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 4); CL_ParticleEffect(EFFECT_TE_BLOOD, count, pos, pos, vec3_origin, vec3_origin, NULL, 0); break; case QW_TE_LIGHTNINGBLOOD: - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 4); CL_ParticleEffect(EFFECT_TE_BLOOD, 2.5, pos, pos, vec3_origin, vec3_origin, NULL, 0); break; @@ -2485,12 +2560,12 @@ void CL_ParseTempEntity(void) } else { - type = MSG_ReadByte(); + type = MSG_ReadByte(&cl_message); switch (type) { case TE_WIZSPIKE: // spike hitting wall - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 4); CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); S_StartSound(-1, 0, cl.sfx_wizhit, pos, 1, 1); @@ -2498,7 +2573,7 @@ void CL_ParseTempEntity(void) case TE_KNIGHTSPIKE: // spike hitting wall - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 4); CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); S_StartSound(-1, 0, cl.sfx_knighthit, pos, 1, 1); @@ -2506,7 +2581,7 @@ void CL_ParseTempEntity(void) case TE_SPIKE: // spike hitting wall - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 4); CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); if (rand() % 5) @@ -2524,7 +2599,7 @@ void CL_ParseTempEntity(void) break; case TE_SPIKEQUAD: // quad spike hitting wall - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 4); CL_ParticleEffect(EFFECT_TE_SPIKEQUAD, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); if (rand() % 5) @@ -2542,7 +2617,7 @@ void CL_ParseTempEntity(void) break; case TE_SUPERSPIKE: // super spike hitting wall - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 4); CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); if (rand() % 5) @@ -2560,7 +2635,7 @@ void CL_ParseTempEntity(void) break; case TE_SUPERSPIKEQUAD: // quad super spike hitting wall - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 4); CL_ParticleEffect(EFFECT_TE_SUPERSPIKEQUAD, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); if (rand() % 5) @@ -2576,39 +2651,39 @@ void CL_ParseTempEntity(void) S_StartSound(-1, 0, cl.sfx_ric3, pos, 1, 1); } break; - // LordHavoc: added for improved blood splatters + // LadyHavoc: added for improved blood splatters case TE_BLOOD: // blood puff - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 4); - dir[0] = MSG_ReadChar(); - dir[1] = MSG_ReadChar(); - dir[2] = MSG_ReadChar(); - count = MSG_ReadByte(); + dir[0] = MSG_ReadChar(&cl_message); + dir[1] = MSG_ReadChar(&cl_message); + dir[2] = MSG_ReadChar(&cl_message); + count = MSG_ReadByte(&cl_message); CL_ParticleEffect(EFFECT_TE_BLOOD, count, pos, pos, dir, dir, NULL, 0); break; case TE_SPARK: // spark shower - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 4); - dir[0] = MSG_ReadChar(); - dir[1] = MSG_ReadChar(); - dir[2] = MSG_ReadChar(); - count = MSG_ReadByte(); + dir[0] = MSG_ReadChar(&cl_message); + dir[1] = MSG_ReadChar(&cl_message); + dir[2] = MSG_ReadChar(&cl_message); + count = MSG_ReadByte(&cl_message); CL_ParticleEffect(EFFECT_TE_SPARK, count, pos, pos, dir, dir, NULL, 0); break; case TE_PLASMABURN: - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 4); CL_ParticleEffect(EFFECT_TE_PLASMABURN, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); break; - // LordHavoc: added for improved gore + // LadyHavoc: added for improved gore case TE_BLOODSHOWER: // vaporized body - MSG_ReadVector(pos, cls.protocol); // mins - MSG_ReadVector(pos2, cls.protocol); // maxs - velspeed = MSG_ReadCoord(cls.protocol); // speed - count = (unsigned short) MSG_ReadShort(); // number of particles + MSG_ReadVector(&cl_message, pos, cls.protocol); // mins + MSG_ReadVector(&cl_message, pos2, cls.protocol); // maxs + velspeed = MSG_ReadCoord(&cl_message, cls.protocol); // speed + count = (unsigned short) MSG_ReadShort(&cl_message); // number of particles vel1[0] = -velspeed; vel1[1] = -velspeed; vel1[2] = -velspeed; @@ -2620,39 +2695,39 @@ void CL_ParseTempEntity(void) case TE_PARTICLECUBE: // general purpose particle effect - MSG_ReadVector(pos, cls.protocol); // mins - MSG_ReadVector(pos2, cls.protocol); // maxs - MSG_ReadVector(dir, cls.protocol); // dir - count = (unsigned short) MSG_ReadShort(); // number of particles - colorStart = MSG_ReadByte(); // color - colorLength = MSG_ReadByte(); // gravity (1 or 0) - velspeed = MSG_ReadCoord(cls.protocol); // randomvel + MSG_ReadVector(&cl_message, pos, cls.protocol); // mins + MSG_ReadVector(&cl_message, pos2, cls.protocol); // maxs + MSG_ReadVector(&cl_message, dir, cls.protocol); // dir + count = (unsigned short) MSG_ReadShort(&cl_message); // number of particles + colorStart = MSG_ReadByte(&cl_message); // color + colorLength = MSG_ReadByte(&cl_message); // gravity (1 or 0) + velspeed = MSG_ReadCoord(&cl_message, cls.protocol); // randomvel CL_ParticleCube(pos, pos2, dir, count, colorStart, colorLength != 0, velspeed); break; case TE_PARTICLERAIN: // general purpose particle effect - MSG_ReadVector(pos, cls.protocol); // mins - MSG_ReadVector(pos2, cls.protocol); // maxs - MSG_ReadVector(dir, cls.protocol); // dir - count = (unsigned short) MSG_ReadShort(); // number of particles - colorStart = MSG_ReadByte(); // color + MSG_ReadVector(&cl_message, pos, cls.protocol); // mins + MSG_ReadVector(&cl_message, pos2, cls.protocol); // maxs + MSG_ReadVector(&cl_message, dir, cls.protocol); // dir + count = (unsigned short) MSG_ReadShort(&cl_message); // number of particles + colorStart = MSG_ReadByte(&cl_message); // color CL_ParticleRain(pos, pos2, dir, count, colorStart, 0); break; case TE_PARTICLESNOW: // general purpose particle effect - MSG_ReadVector(pos, cls.protocol); // mins - MSG_ReadVector(pos2, cls.protocol); // maxs - MSG_ReadVector(dir, cls.protocol); // dir - count = (unsigned short) MSG_ReadShort(); // number of particles - colorStart = MSG_ReadByte(); // color + MSG_ReadVector(&cl_message, pos, cls.protocol); // mins + MSG_ReadVector(&cl_message, pos2, cls.protocol); // maxs + MSG_ReadVector(&cl_message, dir, cls.protocol); // dir + count = (unsigned short) MSG_ReadShort(&cl_message); // number of particles + colorStart = MSG_ReadByte(&cl_message); // color CL_ParticleRain(pos, pos2, dir, count, colorStart, 1); break; case TE_GUNSHOT: // bullet hitting wall - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, 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 & RIC_GUNSHOT) @@ -2674,7 +2749,7 @@ void CL_ParseTempEntity(void) case TE_GUNSHOTQUAD: // quad bullet hitting wall - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, 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 & RIC_GUNSHOTQUAD) @@ -2696,7 +2771,7 @@ void CL_ParseTempEntity(void) case TE_EXPLOSION: // rocket explosion - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 10); CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1); @@ -2704,7 +2779,7 @@ void CL_ParseTempEntity(void) case TE_EXPLOSIONQUAD: // quad rocket explosion - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 10); CL_ParticleEffect(EFFECT_TE_EXPLOSIONQUAD, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1); @@ -2712,60 +2787,60 @@ void CL_ParseTempEntity(void) case TE_EXPLOSION3: // Nehahra movie colored lighting explosion - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 10); - color[0] = MSG_ReadCoord(cls.protocol) * (2.0f / 1.0f); - color[1] = MSG_ReadCoord(cls.protocol) * (2.0f / 1.0f); - color[2] = MSG_ReadCoord(cls.protocol) * (2.0f / 1.0f); + color[0] = MSG_ReadCoord(&cl_message, cls.protocol) * (2.0f / 1.0f); + color[1] = MSG_ReadCoord(&cl_message, cls.protocol) * (2.0f / 1.0f); + color[2] = MSG_ReadCoord(&cl_message, cls.protocol) * (2.0f / 1.0f); CL_ParticleExplosion(pos); Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]); - CL_AllocLightFlash(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + CL_AllocLightFlash(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, NULL, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1); break; case TE_EXPLOSIONRGB: // colored lighting explosion - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 10); CL_ParticleExplosion(pos); - color[0] = MSG_ReadByte() * (2.0f / 255.0f); - color[1] = MSG_ReadByte() * (2.0f / 255.0f); - color[2] = MSG_ReadByte() * (2.0f / 255.0f); + color[0] = MSG_ReadByte(&cl_message) * (2.0f / 255.0f); + color[1] = MSG_ReadByte(&cl_message) * (2.0f / 255.0f); + color[2] = MSG_ReadByte(&cl_message) * (2.0f / 255.0f); Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]); - CL_AllocLightFlash(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + CL_AllocLightFlash(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, NULL, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1); break; case TE_TAREXPLOSION: // tarbaby explosion - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 10); CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1); break; case TE_SMALLFLASH: - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 10); CL_ParticleEffect(EFFECT_TE_SMALLFLASH, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); break; case TE_CUSTOMFLASH: - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 4); - radius = (MSG_ReadByte() + 1) * 8; - velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0); - color[0] = MSG_ReadByte() * (2.0f / 255.0f); - color[1] = MSG_ReadByte() * (2.0f / 255.0f); - color[2] = MSG_ReadByte() * (2.0f / 255.0f); + radius = (MSG_ReadByte(&cl_message) + 1) * 8; + velspeed = (MSG_ReadByte(&cl_message) + 1) * (1.0 / 256.0); + color[0] = MSG_ReadByte(&cl_message) * (2.0f / 255.0f); + color[1] = MSG_ReadByte(&cl_message) * (2.0f / 255.0f); + color[2] = MSG_ReadByte(&cl_message) * (2.0f / 255.0f); Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]); - CL_AllocLightFlash(NULL, &tempmatrix, radius, color[0], color[1], color[2], radius / velspeed, velspeed, 0, -1, true, 1, 0.25, 1, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + CL_AllocLightFlash(NULL, &tempmatrix, radius, color[0], color[1], color[2], radius / velspeed, velspeed, NULL, -1, true, 1, 0.25, 1, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); break; case TE_FLAMEJET: - MSG_ReadVector(pos, cls.protocol); - MSG_ReadVector(dir, cls.protocol); - count = MSG_ReadByte(); + MSG_ReadVector(&cl_message, pos, cls.protocol); + MSG_ReadVector(&cl_message, dir, cls.protocol); + count = MSG_ReadByte(&cl_message); CL_ParticleEffect(EFFECT_TE_FLAMEJET, count, pos, pos, dir, dir, NULL, 0); break; @@ -2791,63 +2866,65 @@ void CL_ParseTempEntity(void) break; // PGM 01/21/97 - // LordHavoc: for compatibility with the Nehahra movie... + // LadyHavoc: for compatibility with the Nehahra movie... case TE_LIGHTNING4NEH: - CL_ParseBeam(Mod_ForName(MSG_ReadString(), true, false, NULL), false); + CL_ParseBeam(Mod_ForName(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), true, false, NULL), false); break; case TE_LAVASPLASH: - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); break; case TE_TELEPORT: - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); break; case TE_EXPLOSION2: // color mapped explosion - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 10); - colorStart = MSG_ReadByte(); - colorLength = MSG_ReadByte(); + colorStart = MSG_ReadByte(&cl_message); + colorLength = MSG_ReadByte(&cl_message); + if (colorLength == 0) + colorLength = 1; CL_ParticleExplosion2(pos, colorStart, colorLength); tempcolor = palette_rgb[(rand()%colorLength) + colorStart]; color[0] = tempcolor[0] * (2.0f / 255.0f); color[1] = tempcolor[1] * (2.0f / 255.0f); color[2] = tempcolor[2] * (2.0f / 255.0f); Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]); - CL_AllocLightFlash(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + CL_AllocLightFlash(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, NULL, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1); break; case TE_TEI_G3: - MSG_ReadVector(pos, cls.protocol); - MSG_ReadVector(pos2, cls.protocol); - MSG_ReadVector(dir, cls.protocol); - CL_ParticleEffect(EFFECT_TE_TEI_G3, 1, pos, pos2, dir, dir, NULL, 0); + MSG_ReadVector(&cl_message, pos, cls.protocol); + MSG_ReadVector(&cl_message, pos2, cls.protocol); + MSG_ReadVector(&cl_message, dir, cls.protocol); + CL_ParticleTrail(EFFECT_TE_TEI_G3, 1, pos, pos2, dir, dir, NULL, 0, true, true, NULL, NULL, 1); break; case TE_TEI_SMOKE: - MSG_ReadVector(pos, cls.protocol); - MSG_ReadVector(dir, cls.protocol); - count = MSG_ReadByte(); + MSG_ReadVector(&cl_message, pos, cls.protocol); + MSG_ReadVector(&cl_message, dir, cls.protocol); + count = MSG_ReadByte(&cl_message); CL_FindNonSolidLocation(pos, pos, 4); CL_ParticleEffect(EFFECT_TE_TEI_SMOKE, count, pos, pos, vec3_origin, vec3_origin, NULL, 0); break; case TE_TEI_BIGEXPLOSION: - MSG_ReadVector(pos, cls.protocol); + MSG_ReadVector(&cl_message, pos, cls.protocol); CL_FindNonSolidLocation(pos, pos, 10); CL_ParticleEffect(EFFECT_TE_TEI_BIGEXPLOSION, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1); break; case TE_TEI_PLASMAHIT: - MSG_ReadVector(pos, cls.protocol); - MSG_ReadVector(dir, cls.protocol); - count = MSG_ReadByte(); + MSG_ReadVector(&cl_message, pos, cls.protocol); + MSG_ReadVector(&cl_message, dir, cls.protocol); + count = MSG_ReadByte(&cl_message); CL_FindNonSolidLocation(pos, pos, 5); CL_ParticleEffect(EFFECT_TE_TEI_PLASMAHIT, count, pos, pos, vec3_origin, vec3_origin, NULL, 0); break; @@ -2858,39 +2935,39 @@ void CL_ParseTempEntity(void) } } -void CL_ParseTrailParticles(void) +static void CL_ParseTrailParticles(void) { int entityindex; int effectindex; vec3_t start, end; - entityindex = (unsigned short)MSG_ReadShort(); + entityindex = (unsigned short)MSG_ReadShort(&cl_message); if (entityindex >= MAX_EDICTS) entityindex = 0; if (entityindex >= cl.max_entities) CL_ExpandEntities(entityindex); - effectindex = (unsigned short)MSG_ReadShort(); - MSG_ReadVector(start, cls.protocol); - MSG_ReadVector(end, cls.protocol); - CL_ParticleEffect(effectindex, 1, start, end, vec3_origin, vec3_origin, entityindex > 0 ? cl.entities + entityindex : NULL, 0); + effectindex = (unsigned short)MSG_ReadShort(&cl_message); + MSG_ReadVector(&cl_message, start, cls.protocol); + MSG_ReadVector(&cl_message, end, cls.protocol); + CL_ParticleTrail(effectindex, 1, start, end, vec3_origin, vec3_origin, entityindex > 0 ? cl.entities + entityindex : NULL, 0, true, true, NULL, NULL, 1); } -void CL_ParsePointParticles(void) +static void CL_ParsePointParticles(void) { int effectindex, count; vec3_t origin, velocity; - effectindex = (unsigned short)MSG_ReadShort(); - MSG_ReadVector(origin, cls.protocol); - MSG_ReadVector(velocity, cls.protocol); - count = (unsigned short)MSG_ReadShort(); + effectindex = (unsigned short)MSG_ReadShort(&cl_message); + MSG_ReadVector(&cl_message, origin, cls.protocol); + MSG_ReadVector(&cl_message, velocity, cls.protocol); + count = (unsigned short)MSG_ReadShort(&cl_message); CL_ParticleEffect(effectindex, count, origin, origin, velocity, velocity, NULL, 0); } -void CL_ParsePointParticles1(void) +static void CL_ParsePointParticles1(void) { int effectindex; vec3_t origin; - effectindex = (unsigned short)MSG_ReadShort(); - MSG_ReadVector(origin, cls.protocol); + effectindex = (unsigned short)MSG_ReadShort(&cl_message); + MSG_ReadVector(&cl_message, origin, cls.protocol); CL_ParticleEffect(effectindex, 1, origin, origin, vec3_origin, vec3_origin, NULL, 0); } @@ -2901,15 +2978,16 @@ typedef struct cl_iplog_item_s } cl_iplog_item_t; -static qboolean cl_iplog_loaded = false; +static qbool cl_iplog_loaded = false; static int cl_iplog_numitems = 0; static int cl_iplog_maxitems = 0; static cl_iplog_item_t *cl_iplog_items; static void CL_IPLog_Load(void); -static void CL_IPLog_Add(const char *address, const char *name, qboolean checkexisting, qboolean addtofile) +static void CL_IPLog_Add(const char *address, const char *name, qbool checkexisting, qbool addtofile) { int i; + size_t sz_name, sz_address; if (!address || !address[0] || !name || !name[0]) return; if (!cl_iplog_loaded) @@ -2942,21 +3020,26 @@ static void CL_IPLog_Add(const char *address, const char *name, qboolean checkex Mem_Free(olditems); } } - cl_iplog_items[cl_iplog_numitems].address = (char *) Mem_Alloc(cls.permanentmempool, strlen(address) + 1); - cl_iplog_items[cl_iplog_numitems].name = (char *) Mem_Alloc(cls.permanentmempool, strlen(name) + 1); - strlcpy(cl_iplog_items[cl_iplog_numitems].address, address, strlen(address) + 1); + sz_address = strlen(address) + 1; + sz_name = strlen(name) + 1; + cl_iplog_items[cl_iplog_numitems].address = (char *) Mem_Alloc(cls.permanentmempool, sz_address); + cl_iplog_items[cl_iplog_numitems].name = (char *) Mem_Alloc(cls.permanentmempool, sz_name); + strlcpy(cl_iplog_items[cl_iplog_numitems].address, address, sz_address); // TODO: maybe it would be better to strip weird characters from name when // copying it here rather than using a straight strcpy? - strlcpy(cl_iplog_items[cl_iplog_numitems].name, name, strlen(name) + 1); + strlcpy(cl_iplog_items[cl_iplog_numitems].name, name, sz_name); cl_iplog_numitems++; if (addtofile) { // add it to the iplog.txt file // TODO: this ought to open the one in the userpath version of the base // gamedir, not the current gamedir +// not necessary for mobile +#ifndef DP_MOBILETOUCH Log_Printf(cl_iplog_name.string, "%s %s\n", 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); +#endif } } @@ -2971,7 +3054,12 @@ static void CL_IPLog_Load(void) cl_iplog_loaded = true; // TODO: this ought to open the one in the userpath version of the base // gamedir, not the current gamedir +// not necessary for mobile +#ifndef DP_MOBILETOUCH filedata = FS_LoadFile(cl_iplog_name.string, tempmempool, true, &filesize); +#else + filedata = NULL; +#endif if (!filedata) return; text = (char *)filedata; @@ -3002,18 +3090,18 @@ static void CL_IPLog_Load(void) } } -static void CL_IPLog_List_f(void) +static void CL_IPLog_List_f(cmd_state_t *cmd) { int i, j; const char *addressprefix; - if (Cmd_Argc() > 2) + if (Cmd_Argc(cmd) > 2) { - Con_Printf("usage: %s 123.456.789.\n", Cmd_Argv(0)); + Con_Printf("usage: %s 123.456.789.\n", Cmd_Argv(cmd, 0)); return; } addressprefix = ""; - if (Cmd_Argc() >= 2) - addressprefix = Cmd_Argv(1); + if (Cmd_Argc(cmd) >= 2) + addressprefix = Cmd_Argv(cmd, 1); if (!cl_iplog_loaded) CL_IPLog_Load(); if (addressprefix && addressprefix[0]) @@ -3044,7 +3132,7 @@ static void CL_IPLog_List_f(void) } // look for anything interesting like player IP addresses or ping reports -qboolean CL_ExaminePrintString(const char *text) +static qbool CL_ExaminePrintString(const char *text) { int len; const char *t; @@ -3076,7 +3164,7 @@ qboolean CL_ExaminePrintString(const char *text) if (cl.parsingtextmode == CL_PARSETEXTMODE_PING) { // if anything goes wrong, we'll assume this is not a ping report - qboolean expected = cl.parsingtextexpectingpingforscores != 0; + qbool expected = cl.parsingtextexpectingpingforscores != 0; cl.parsingtextexpectingpingforscores = 0; cl.parsingtextmode = CL_PARSETEXTMODE_NONE; t = text; @@ -3187,14 +3275,13 @@ qboolean CL_ExaminePrintString(const char *text) return true; } -extern cvar_t slowmo; -extern void CSQC_UpdateNetworkTimes(double newtime, double oldtime); +extern cvar_t host_timescale; +extern cvar_t cl_lerpexcess; static void CL_NetworkTimeReceived(double newtime) { - double timehigh; cl.mtime[1] = cl.mtime[0]; cl.mtime[0] = newtime; - if (cl_nolerp.integer || cls.timedemo || (cl.islocalgame && !sv_fixedframeratesingleplayer.integer) || cl.mtime[1] == cl.mtime[0] || cls.signon < SIGNONS) + if (cl_nolerp.integer || cls.timedemo || cl.mtime[1] == cl.mtime[0] || cls.signon < SIGNONS) cl.time = cl.mtime[1] = newtime; else if (cls.demoplayback) { @@ -3206,7 +3293,9 @@ static void CL_NetworkTimeReceived(double newtime) } else if (cls.protocol != PROTOCOL_QUAKEWORLD) { + double timehigh = 0; // hush compiler warning cl.mtime[1] = max(cl.mtime[1], cl.mtime[0] - 0.1); + if (developer_extra.integer && vid_activewindow) { if (cl.time < cl.mtime[1] - (cl.mtime[0] - cl.mtime[1])) @@ -3214,22 +3303,31 @@ static void CL_NetworkTimeReceived(double newtime) else if (cl.time > cl.mtime[0] + (cl.mtime[0] - cl.mtime[1])) 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; - if (cl_nettimesyncboundmode.integer == 1) - cl.time = bound(cl.mtime[1], cl.time, cl.mtime[0]); - else if (cl_nettimesyncboundmode.integer == 2) + + if (cl_nettimesyncboundmode.integer < 4) { - if (cl.time < cl.mtime[1] || cl.time > timehigh) - cl.time = cl.mtime[1]; + // doesn't make sense for modes > 3 + 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; } - else if (cl_nettimesyncboundmode.integer == 3) + + switch (cl_nettimesyncboundmode.integer) { + case 1: + cl.time = bound(cl.mtime[1], cl.time, cl.mtime[0]); + break; + + case 2: + if (cl.time < cl.mtime[1] || cl.time > timehigh) + cl.time = cl.mtime[1]; + break; + + case 3: if ((cl.time < cl.mtime[1] && cl.oldtime < cl.mtime[1]) || (cl.time > timehigh && cl.oldtime > timehigh)) cl.time = cl.mtime[1]; - } - else if (cl_nettimesyncboundmode.integer == 4) - { + break; + + case 4: if (fabs(cl.time - cl.mtime[1]) > 0.5) cl.time = cl.mtime[1]; // reset else if (fabs(cl.time - cl.mtime[1]) > 0.1) @@ -3238,20 +3336,44 @@ static void CL_NetworkTimeReceived(double newtime) cl.time -= 0.002 * cl.movevars_timescale; // fall into the past by 2ms else cl.time += 0.001 * cl.movevars_timescale; // creep forward 1ms - } - else if (cl_nettimesyncboundmode.integer == 5) - { + break; + + case 5: if (fabs(cl.time - cl.mtime[1]) > 0.5) cl.time = cl.mtime[1]; // reset 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 * cl.movevars_timescale, cl.mtime[1], cl.time + 0.001 * cl.movevars_timescale); - } - else if (cl_nettimesyncboundmode.integer == 6) - { + break; + + case 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); + break; + + case 7: + /* bones_was_here: this aims to prevent disturbances in the force from affecting cl.time + * the rolling harmonic mean gives large time error outliers low significance + * correction rate is dynamic and gradual (max 10% of mean error per tic) + * time is correct within a few server frames of connect/map start + * can achieve microsecond accuracy when cl.realframetime is a multiple of sv.frametime + * prevents 0ms move frame times with uncapped fps + * smoothest mode esp. for vsynced clients on servers with aggressive inputtimeout + */ + { + unsigned char i; + float error; + // in event of packet loss, cl.mtime[1] could be very old, so avoid if possible + double target = cl.movevars_ticrate ? cl.mtime[0] - cl.movevars_ticrate : cl.mtime[1]; + cl.ts_error_stor[cl.ts_error_num] = 1.0f / max(fabs(cl.time - target), FLT_MIN); + cl.ts_error_num = (cl.ts_error_num + 1) % NUM_TS_ERRORS; + for (i = 0, error = 0.0f; i < NUM_TS_ERRORS; i++) + error += cl.ts_error_stor[i]; + error = 0.1f / (error / NUM_TS_ERRORS); + cl.time = bound(cl.time - error, target, cl.time + error); + } + break; } } // this packet probably contains a player entity update, so we will need @@ -3269,18 +3391,27 @@ static void CL_NetworkTimeReceived(double newtime) // update the csqc's server timestamps, critical for proper sync CSQC_UpdateNetworkTimes(cl.mtime[0], cl.mtime[1]); +#ifdef USEODE if (cl.mtime[0] > cl.mtime[1]) World_Physics_Frame(&cl.world, cl.mtime[0] - cl.mtime[1], cl.movevars_gravity); -} +#endif -#define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf("%3i:%s(%i)\n", msg_readcount-1, x, cmd); + // only lerp entities that also get an update in this frame, when lerp excess is used + if(cl_lerpexcess.value > 0) + { + int i; + for (i = 1;i < cl.num_entities;i++) + { + if (cl.entities_active[i]) + { + entity_t *ent = cl.entities + i; + ent->persistent.lerpdeltatime = 0; + } + } + } +} -//[515]: csqc -qboolean CL_VM_Parse_TempEntity (void); -void CL_VM_Parse_StuffCmd (const char *msg); -void CL_VM_Parse_CenterPrint (const char *msg); -void CSQC_AddPrintText (const char *msg); -void CSQC_ReadEntities (void); +#define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf("%3i:%s(%i)\n", cl_message.readcount-1, x, cmd); /* ===================== @@ -3288,7 +3419,6 @@ CL_ParseServerMessage ===================== */ int parsingerror = false; -extern void CL_UpdateMoveVars(void); void CL_ParseServerMessage(void) { int cmd; @@ -3297,16 +3427,17 @@ void CL_ParseServerMessage(void) unsigned char cmdlog[32]; const char *cmdlogname[32], *temp; int cmdindex, cmdcount = 0; - qboolean qwplayerupdatereceived; - qboolean strip_pqc; + qbool qwplayerupdatereceived; + qbool strip_pqc; + char vabuf[1024]; - // LordHavoc: moved demo message writing from before the packet parse to + // LadyHavoc: 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 // code in CL_ParseServerinfo //if (cls.demorecording) - // CL_WriteDemoMessage (&net_message); + // CL_WriteDemoMessage (&cl_message); - cl.last_received_message = realtime; + cl.last_received_message = host.realtime; CL_KeepaliveMessage(false); @@ -3314,7 +3445,7 @@ void CL_ParseServerMessage(void) // if recording demos, copy the message out // if (cl_shownet.integer == 1) - Con_Printf("%f %i\n", realtime, net_message.cursize); + Con_Printf("%f %i\n", host.realtime, cl_message.cursize); else if (cl_shownet.integer == 2) Con_Print("------------------\n"); @@ -3327,7 +3458,7 @@ void CL_ParseServerMessage(void) if (cls.protocol == PROTOCOL_QUAKEWORLD) { - CL_NetworkTimeReceived(realtime); // qw has no clock + CL_NetworkTimeReceived(host.realtime); // qw has no clock // kill all qw nails cl.qw_num_nails = 0; @@ -3341,10 +3472,10 @@ void CL_ParseServerMessage(void) while (1) { - if (msg_badread) + if (cl_message.badread) Host_Error ("CL_ParseServerMessage: Bad QW server message"); - cmd = MSG_ReadByte (); + cmd = MSG_ReadByte(&cl_message); if (cmd == -1) { @@ -3360,9 +3491,9 @@ void CL_ParseServerMessage(void) cmdlogname[cmdindex] = qw_svc_strings[cmd]; if (!cmdlogname[cmdindex]) { - // LordHavoc: fix for bizarre problem in MSVC that I do not understand (if I assign the string pointer directly it ends up storing a NULL pointer) - temp = ""; - cmdlogname[cmdindex] = temp; + // LadyHavoc: fix for bizarre problem in MSVC that I do not understand (if I assign the string pointer directly it ends up storing a NULL pointer) + const char *d = ""; + cmdlogname[cmdindex] = d; } // other commands @@ -3370,7 +3501,7 @@ void CL_ParseServerMessage(void) { default: { - char description[32*64], temp[64]; + char description[32*64], logtemp[64]; int count; strlcpy(description, "packet dump: ", sizeof(description)); i = cmdcount - 32; @@ -3380,8 +3511,8 @@ void CL_ParseServerMessage(void) i &= 31; while(count > 0) { - dpsnprintf(temp, sizeof(temp), "%3i:%s ", cmdlog[i], cmdlogname[i]); - strlcat(description, temp, sizeof(description)); + dpsnprintf(logtemp, sizeof(logtemp), "%3i:%s ", cmdlog[i], cmdlogname[i]); + strlcat(description, logtemp, sizeof(description)); count--; i++; i &= 31; @@ -3397,31 +3528,30 @@ void CL_ParseServerMessage(void) break; case qw_svc_disconnect: - Con_Printf("Server disconnected\n"); if (cls.demonum != -1) CL_NextDemo(); else - CL_Disconnect(); - return; + CL_DisconnectEx(true, "Server disconnected"); + break; case qw_svc_print: - i = MSG_ReadByte(); - temp = MSG_ReadString(); + i = MSG_ReadByte(&cl_message); + temp = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); if (CL_ExaminePrintString(temp)) // look for anything interesting like player IP addresses or ping reports { if (i == 3) // chat - CSQC_AddPrintText(va("\1%s", temp)); //[515]: csqc + CSQC_AddPrintText(va(vabuf, sizeof(vabuf), "\1%s", temp)); //[515]: csqc else CSQC_AddPrintText(temp); } break; case qw_svc_centerprint: - CL_VM_Parse_CenterPrint(MSG_ReadString ()); //[515]: csqc + CL_VM_Parse_CenterPrint(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring))); //[515]: csqc break; case qw_svc_stufftext: - CL_VM_Parse_StuffCmd(MSG_ReadString ()); //[515]: csqc + CL_VM_Parse_StuffCmd(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring))); //[515]: csqc break; case qw_svc_damage: @@ -3436,7 +3566,7 @@ void CL_ParseServerMessage(void) case qw_svc_setangle: for (i=0 ; i<3 ; i++) - cl.viewangles[i] = MSG_ReadAngle (cls.protocol); + cl.viewangles[i] = MSG_ReadAngle(&cl_message, cls.protocol); if (!cls.demoplayback) { cl.fixangle[0] = true; @@ -3448,13 +3578,13 @@ void CL_ParseServerMessage(void) break; case qw_svc_lightstyle: - i = MSG_ReadByte (); + i = MSG_ReadByte(&cl_message); if (i >= cl.max_lightstyle) { Con_Printf ("svc_lightstyle >= MAX_LIGHTSTYLES"); break; } - strlcpy (cl.lightstyle[i].map, MSG_ReadString(), sizeof (cl.lightstyle[i].map)); + strlcpy (cl.lightstyle[i].map, MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof (cl.lightstyle[i].map)); cl.lightstyle[i].map[MAX_STYLESTRING - 1] = 0; cl.lightstyle[i].length = (int)strlen(cl.lightstyle[i].map); break; @@ -3464,41 +3594,41 @@ void CL_ParseServerMessage(void) break; case qw_svc_stopsound: - i = (unsigned short) MSG_ReadShort(); + i = (unsigned short) MSG_ReadShort(&cl_message); S_StopSound(i>>3, i&7); break; case qw_svc_updatefrags: - i = MSG_ReadByte(); + i = MSG_ReadByte(&cl_message); if (i >= cl.maxclients) Host_Error("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients"); - cl.scores[i].frags = (signed short) MSG_ReadShort(); + cl.scores[i].frags = (signed short) MSG_ReadShort(&cl_message); break; case qw_svc_updateping: - i = MSG_ReadByte(); + i = MSG_ReadByte(&cl_message); if (i >= cl.maxclients) Host_Error("CL_ParseServerMessage: svc_updateping >= cl.maxclients"); - cl.scores[i].qw_ping = MSG_ReadShort(); + cl.scores[i].qw_ping = MSG_ReadShort(&cl_message); break; case qw_svc_updatepl: - i = MSG_ReadByte(); + i = MSG_ReadByte(&cl_message); if (i >= cl.maxclients) Host_Error("CL_ParseServerMessage: svc_updatepl >= cl.maxclients"); - cl.scores[i].qw_packetloss = MSG_ReadByte(); + cl.scores[i].qw_packetloss = MSG_ReadByte(&cl_message); break; case qw_svc_updateentertime: - i = MSG_ReadByte(); + i = MSG_ReadByte(&cl_message); if (i >= cl.maxclients) Host_Error("CL_ParseServerMessage: svc_updateentertime >= cl.maxclients"); // seconds ago - cl.scores[i].qw_entertime = cl.time - MSG_ReadFloat(); + cl.scores[i].qw_entertime = cl.time - MSG_ReadFloat(&cl_message); break; case qw_svc_spawnbaseline: - i = (unsigned short) MSG_ReadShort(); + i = (unsigned short) MSG_ReadShort(&cl_message); if (i < 0 || i >= MAX_EDICTS) Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i); if (i >= cl.max_entities) @@ -3522,17 +3652,17 @@ void CL_ParseServerMessage(void) break; case qw_svc_updatestat: - i = MSG_ReadByte (); + i = MSG_ReadByte(&cl_message); if (i < 0 || i >= MAX_CL_STATS) Host_Error ("svc_updatestat: %i is invalid", i); - cl.stats[i] = MSG_ReadByte (); + cl.stats[i] = MSG_ReadByte(&cl_message); break; case qw_svc_updatestatlong: - i = MSG_ReadByte (); + i = MSG_ReadByte(&cl_message); if (i < 0 || i >= MAX_CL_STATS) Host_Error ("svc_updatestatlong: %i is invalid", i); - cl.stats[i] = MSG_ReadLong (); + cl.stats[i] = MSG_ReadLong(&cl_message); break; case qw_svc_spawnstaticsound: @@ -3540,7 +3670,7 @@ void CL_ParseServerMessage(void) break; case qw_svc_cdtrack: - cl.cdtrack = cl.looptrack = MSG_ReadByte (); + cl.cdtrack = cl.looptrack = MSG_ReadByte(&cl_message); if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) ) CDAudio_Play ((unsigned char)cls.forcetrack, true); else @@ -3551,20 +3681,20 @@ void CL_ParseServerMessage(void) if(!cl.intermission) cl.completed_time = cl.time; cl.intermission = 1; - MSG_ReadVector(cl.qw_intermission_origin, cls.protocol); + MSG_ReadVector(&cl_message, cl.qw_intermission_origin, cls.protocol); for (i = 0;i < 3;i++) - cl.qw_intermission_angles[i] = MSG_ReadAngle(cls.protocol); + cl.qw_intermission_angles[i] = MSG_ReadAngle(&cl_message, cls.protocol); break; case qw_svc_finale: if(!cl.intermission) cl.completed_time = cl.time; cl.intermission = 2; - SCR_CenterPrint(MSG_ReadString ()); + SCR_CenterPrint(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring))); break; case qw_svc_sellscreen: - Cmd_ExecuteString ("help", src_command); + Cmd_ExecuteString(cmd_local, "help", src_local, true); break; case qw_svc_smallkick: @@ -3575,7 +3705,7 @@ void CL_ParseServerMessage(void) break; case qw_svc_muzzleflash: - i = (unsigned short) MSG_ReadShort(); + i = (unsigned short) MSG_ReadShort(&cl_message); // NOTE: in QW this only worked on clients if (i < 0 || i >= MAX_EDICTS) Host_Error("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i); @@ -3617,7 +3747,7 @@ void CL_ParseServerMessage(void) break; case qw_svc_chokecount: - i = MSG_ReadByte(); + (void) MSG_ReadByte(&cl_message); // FIXME: apply to netgraph //for (j = 0;j < i;j++) // cl.frames[(cls.netcon->qw.incoming_acknowledged-1-j)&QW_UPDATE_MASK].receivedtime = -2; @@ -3652,17 +3782,17 @@ void CL_ParseServerMessage(void) break; case qw_svc_maxspeed: - cl.movevars_maxspeed = MSG_ReadFloat(); + cl.movevars_maxspeed = MSG_ReadFloat(&cl_message); break; case qw_svc_entgravity: - cl.movevars_entgravity = MSG_ReadFloat(); + cl.movevars_entgravity = MSG_ReadFloat(&cl_message); if (!cl.movevars_entgravity) cl.movevars_entgravity = 1.0f; break; case qw_svc_setpause: - cl.paused = MSG_ReadByte () != 0; + cl.paused = MSG_ReadByte(&cl_message) != 0; if (cl.paused) CDAudio_Pause (); else @@ -3684,10 +3814,10 @@ void CL_ParseServerMessage(void) { while (1) { - if (msg_badread) + if (cl_message.badread) Host_Error ("CL_ParseServerMessage: Bad server message"); - cmd = MSG_ReadByte (); + cmd = MSG_ReadByte(&cl_message); if (cmd == -1) { @@ -3703,7 +3833,7 @@ void CL_ParseServerMessage(void) // if the high bit of the command byte is set, it is a fast update if (cmd & 128) { - // LordHavoc: fix for bizarre problem in MSVC that I do not understand (if I assign the string pointer directly it ends up storing a NULL pointer) + // LadyHavoc: fix for bizarre problem in MSVC that I do not understand (if I assign the string pointer directly it ends up storing a NULL pointer) temp = "entity"; cmdlogname[cmdindex] = temp; SHOWNET("fast update"); @@ -3721,9 +3851,9 @@ void CL_ParseServerMessage(void) cmdlogname[cmdindex] = svc_strings[cmd]; if (!cmdlogname[cmdindex]) { - // LordHavoc: fix for bizarre problem in MSVC that I do not understand (if I assign the string pointer directly it ends up storing a NULL pointer) - temp = ""; - cmdlogname[cmdindex] = temp; + // LadyHavoc: fix for bizarre problem in MSVC that I do not understand (if I assign the string pointer directly it ends up storing a NULL pointer) + const char *d = ""; + cmdlogname[cmdindex] = d; } // other commands @@ -3731,7 +3861,7 @@ void CL_ParseServerMessage(void) { default: { - char description[32*64], temp[64]; + char description[32*64], tempdesc[64]; int count; strlcpy (description, "packet dump: ", sizeof(description)); i = cmdcount - 32; @@ -3741,8 +3871,8 @@ void CL_ParseServerMessage(void) i &= 31; while(count > 0) { - dpsnprintf (temp, sizeof (temp), "%3i:%s ", cmdlog[i], cmdlogname[i]); - strlcat (description, temp, sizeof (description)); + dpsnprintf (tempdesc, sizeof (tempdesc), "%3i:%s ", cmdlog[i], cmdlogname[i]); + strlcat (description, tempdesc, sizeof (description)); count--; i++; i &= 31; @@ -3759,7 +3889,7 @@ void CL_ParseServerMessage(void) break; case svc_time: - CL_NetworkTimeReceived(MSG_ReadFloat()); + CL_NetworkTimeReceived(MSG_ReadFloat(&cl_message)); break; case svc_clientdata: @@ -3767,36 +3897,35 @@ void CL_ParseServerMessage(void) break; case svc_version: - i = MSG_ReadLong (); + i = MSG_ReadLong(&cl_message); protocol = Protocol_EnumForNumber(i); 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; case svc_disconnect: - Con_Printf ("Server disconnected\n"); if (cls.demonum != -1) - CL_NextDemo (); + CL_NextDemo(); else - CL_Disconnect (); + CL_DisconnectEx(true, cls.protocol == PROTOCOL_DARKPLACES8 ? MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)) : "Server disconnected"); break; case svc_print: - temp = MSG_ReadString(); + temp = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); if (CL_ExaminePrintString(temp)) // look for anything interesting like player IP addresses or ping reports CSQC_AddPrintText(temp); //[515]: csqc break; case svc_centerprint: - CL_VM_Parse_CenterPrint(MSG_ReadString ()); //[515]: csqc + CL_VM_Parse_CenterPrint(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring))); //[515]: csqc break; case svc_stufftext: - temp = MSG_ReadString(); + temp = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); /* if(utf8_enable.integer) { strip_pqc = true; @@ -3844,7 +3973,7 @@ void CL_ParseServerMessage(void) case svc_setangle: for (i=0 ; i<3 ; i++) - cl.viewangles[i] = MSG_ReadAngle (cls.protocol); + cl.viewangles[i] = MSG_ReadAngle(&cl_message, cls.protocol); if (!cls.demoplayback) { cl.fixangle[0] = true; @@ -3856,12 +3985,12 @@ void CL_ParseServerMessage(void) break; case svc_setview: - cl.viewentity = (unsigned short)MSG_ReadShort (); + cl.viewentity = (unsigned short)MSG_ReadShort(&cl_message); if (cl.viewentity >= MAX_EDICTS) Host_Error("svc_setview >= MAX_EDICTS"); if (cl.viewentity >= cl.max_entities) CL_ExpandEntities(cl.viewentity); - // LordHavoc: assume first setview recieved is the real player entity + // LadyHavoc: assume first setview recieved is the real player entity if (!cl.realplayerentity) cl.realplayerentity = cl.viewentity; // update cl.playerentity to this one if it is a valid player @@ -3870,19 +3999,19 @@ void CL_ParseServerMessage(void) break; case svc_lightstyle: - i = MSG_ReadByte (); + i = MSG_ReadByte(&cl_message); if (i >= cl.max_lightstyle) { Con_Printf ("svc_lightstyle >= MAX_LIGHTSTYLES"); break; } - strlcpy (cl.lightstyle[i].map, MSG_ReadString(), sizeof (cl.lightstyle[i].map)); + strlcpy (cl.lightstyle[i].map, MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof (cl.lightstyle[i].map)); cl.lightstyle[i].map[MAX_STYLESTRING - 1] = 0; cl.lightstyle[i].length = (int)strlen(cl.lightstyle[i].map); break; case svc_sound: - CL_ParseStartSoundPacket(false); + CL_ParseStartSoundPacket(cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3 ? true : false); break; case svc_precache: @@ -3893,13 +4022,14 @@ void CL_ParseServerMessage(void) } else { - int i = (unsigned short)MSG_ReadShort(); - char *s = MSG_ReadString(); + char *s; + i = (unsigned short)MSG_ReadShort(&cl_message); + s = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); if (i < 32768) { if (i >= 1 && i < MAX_MODELS) { - dp_model_t *model = Mod_ForName(s, false, false, s[0] == '*' ? cl.model_name[1] : NULL); + model_t *model = Mod_ForName(s, false, false, s[0] == '*' ? cl.model_name[1] : NULL); if (!model) Con_DPrintf("svc_precache: Mod_ForName(\"%s\") failed\n", s); cl.model_precache[i] = model; @@ -3924,29 +4054,29 @@ void CL_ParseServerMessage(void) break; case svc_stopsound: - i = (unsigned short) MSG_ReadShort(); + i = (unsigned short) MSG_ReadShort(&cl_message); S_StopSound(i>>3, i&7); break; case svc_updatename: - i = MSG_ReadByte (); + i = MSG_ReadByte(&cl_message); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatename >= cl.maxclients"); - strlcpy (cl.scores[i].name, MSG_ReadString (), sizeof (cl.scores[i].name)); + strlcpy (cl.scores[i].name, MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof (cl.scores[i].name)); break; case svc_updatefrags: - i = MSG_ReadByte (); + i = MSG_ReadByte(&cl_message); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients"); - cl.scores[i].frags = (signed short) MSG_ReadShort (); + cl.scores[i].frags = (signed short) MSG_ReadShort(&cl_message); break; case svc_updatecolors: - i = MSG_ReadByte (); + i = MSG_ReadByte(&cl_message); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatecolors >= cl.maxclients"); - cl.scores[i].colors = MSG_ReadByte (); + cl.scores[i].colors = MSG_ReadByte(&cl_message); break; case svc_particle: @@ -3962,7 +4092,7 @@ void CL_ParseServerMessage(void) break; case svc_spawnbaseline: - i = (unsigned short) MSG_ReadShort (); + i = (unsigned short) MSG_ReadShort(&cl_message); if (i < 0 || i >= MAX_EDICTS) Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i); if (i >= cl.max_entities) @@ -3970,7 +4100,7 @@ void CL_ParseServerMessage(void) CL_ParseBaseline (cl.entities + i, false); break; case svc_spawnbaseline2: - i = (unsigned short) MSG_ReadShort (); + i = (unsigned short) MSG_ReadShort(&cl_message); if (i < 0 || i >= MAX_EDICTS) Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i); if (i >= cl.max_entities) @@ -3989,7 +4119,7 @@ void CL_ParseServerMessage(void) break; case svc_setpause: - cl.paused = MSG_ReadByte () != 0; + cl.paused = MSG_ReadByte(&cl_message) != 0; if (cl.paused) CDAudio_Pause (); else @@ -3998,8 +4128,8 @@ void CL_ParseServerMessage(void) break; case svc_signonnum: - i = MSG_ReadByte (); - // LordHavoc: it's rude to kick off the client if they missed the + i = MSG_ReadByte(&cl_message); + // LadyHavoc: it's rude to kick off the client if they missed the // reconnect somehow, so allow signon 1 even if at signon 1 if (i <= cls.signon && i != 1) Host_Error ("Received signon %i when at %i", i, cls.signon); @@ -4016,21 +4146,21 @@ void CL_ParseServerMessage(void) break; case svc_updatestat: - i = MSG_ReadByte (); + i = MSG_ReadByte(&cl_message); if (i < 0 || i >= MAX_CL_STATS) Host_Error ("svc_updatestat: %i is invalid", i); - cl.stats[i] = MSG_ReadLong (); + cl.stats[i] = MSG_ReadLong(&cl_message); break; case svc_updatestatubyte: - i = MSG_ReadByte (); + i = MSG_ReadByte(&cl_message); if (i < 0 || i >= MAX_CL_STATS) Host_Error ("svc_updatestat: %i is invalid", i); - cl.stats[i] = MSG_ReadByte (); + cl.stats[i] = MSG_ReadByte(&cl_message); break; case svc_spawnstaticsound: - CL_ParseStaticSound (false); + CL_ParseStaticSound (cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3 ? true : false); break; case svc_spawnstaticsound2: @@ -4038,8 +4168,8 @@ void CL_ParseServerMessage(void) break; case svc_cdtrack: - cl.cdtrack = MSG_ReadByte (); - cl.looptrack = MSG_ReadByte (); + cl.cdtrack = MSG_ReadByte(&cl_message); + cl.looptrack = MSG_ReadByte(&cl_message); if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) ) CDAudio_Play ((unsigned char)cls.forcetrack, true); else @@ -4058,7 +4188,7 @@ void CL_ParseServerMessage(void) cl.completed_time = cl.time; cl.intermission = 2; CL_VM_UpdateIntermissionState(cl.intermission); - SCR_CenterPrint(MSG_ReadString ()); + SCR_CenterPrint(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring))); break; case svc_cutscene: @@ -4066,26 +4196,26 @@ void CL_ParseServerMessage(void) cl.completed_time = cl.time; cl.intermission = 3; CL_VM_UpdateIntermissionState(cl.intermission); - SCR_CenterPrint(MSG_ReadString ()); + SCR_CenterPrint(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring))); break; case svc_sellscreen: - Cmd_ExecuteString ("help", src_command); + Cmd_ExecuteString(cmd_local, "help", src_local, true); break; case svc_hidelmp: if (gamemode == GAME_TENEBRAE) { // repeating particle effect - MSG_ReadCoord(cls.protocol); - MSG_ReadCoord(cls.protocol); - MSG_ReadCoord(cls.protocol); - MSG_ReadCoord(cls.protocol); - MSG_ReadCoord(cls.protocol); - MSG_ReadCoord(cls.protocol); - MSG_ReadByte(); - MSG_ReadLong(); - MSG_ReadLong(); - MSG_ReadString(); + MSG_ReadCoord(&cl_message, cls.protocol); + MSG_ReadCoord(&cl_message, cls.protocol); + MSG_ReadCoord(&cl_message, cls.protocol); + MSG_ReadCoord(&cl_message, cls.protocol); + MSG_ReadCoord(&cl_message, cls.protocol); + MSG_ReadCoord(&cl_message, cls.protocol); + (void) MSG_ReadByte(&cl_message); + MSG_ReadLong(&cl_message); + MSG_ReadLong(&cl_message); + MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); } else SHOWLMP_decodehide(); @@ -4094,17 +4224,17 @@ void CL_ParseServerMessage(void) if (gamemode == GAME_TENEBRAE) { // particle effect - MSG_ReadCoord(cls.protocol); - MSG_ReadCoord(cls.protocol); - MSG_ReadCoord(cls.protocol); - MSG_ReadByte(); - MSG_ReadString(); + MSG_ReadCoord(&cl_message, cls.protocol); + MSG_ReadCoord(&cl_message, cls.protocol); + MSG_ReadCoord(&cl_message, cls.protocol); + (void) MSG_ReadByte(&cl_message); + MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); } else SHOWLMP_decodeshow(); break; case svc_skybox: - R_SetSkyBox(MSG_ReadString()); + R_SetSkyBox(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring))); break; case svc_entities: if (cls.signon == SIGNONS - 1) @@ -4152,11 +4282,11 @@ void CL_ParseServerMessage(void) parsingerror = false; - // LordHavoc: this was at the start of the function before cl_autodemo was + // LadyHavoc: this was at the start of the function before cl_autodemo was // implemented if (cls.demorecording) { - CL_WriteDemoMessage (&net_message); + CL_WriteDemoMessage (&cl_message); // R_TimeReport("WriteDemo"); } } @@ -4166,14 +4296,14 @@ void CL_Parse_DumpPacket(void) if (!parsingerror) return; Con_Print("Packet dump:\n"); - SZ_HexDumpToConsole(&net_message); + SZ_HexDumpToConsole(&cl_message); parsingerror = false; } void CL_Parse_ErrorCleanUp(void) { CL_StopDownload(0, 0); - QW_CL_StopUpload(); + QW_CL_StopUpload_f(cmd_local); } void CL_Parse_Init(void) @@ -4183,10 +4313,6 @@ void CL_Parse_Init(void) Cvar_RegisterVariable(&cl_worldnamenoextension); Cvar_RegisterVariable(&cl_worldbasename); - // LordHavoc: added demo_nehahra cvar - Cvar_RegisterVariable (&demo_nehahra); - if (gamemode == GAME_NEHAHRA) - Cvar_SetValue("demo_nehahra", 1); Cvar_RegisterVariable(&developer_networkentities); Cvar_RegisterVariable(&cl_gameplayfix_soundsmovewithentities); @@ -4210,15 +4336,15 @@ void CL_Parse_Init(void) Cvar_RegisterVariable(&cl_iplog_name); Cvar_RegisterVariable(&cl_readpicture_force); - Cmd_AddCommand("nextul", QW_CL_NextUpload, "sends next fragment of current upload buffer (screenshot for example)"); - Cmd_AddCommand("stopul", QW_CL_StopUpload, "aborts current upload (screenshot for example)"); - Cmd_AddCommand("skins", QW_CL_Skins_f, "downloads missing qw skins from server"); - Cmd_AddCommand("changing", QW_CL_Changing_f, "sent by qw servers to tell client to wait for level change"); - Cmd_AddCommand("cl_begindownloads", CL_BeginDownloads_f, "used internally by darkplaces client while connecting (causes loading of models and sounds or triggers downloads for missing ones)"); - Cmd_AddCommand("cl_downloadbegin", CL_DownloadBegin_f, "(networking) informs client of download file information, client replies with sv_startsoundload to begin the transfer"); - Cmd_AddCommand("stopdownload", CL_StopDownload_f, "terminates a download"); - Cmd_AddCommand("cl_downloadfinished", CL_DownloadFinished_f, "signals that a download has finished and provides the client with file size and crc to check its integrity"); - Cmd_AddCommand("iplog_list", CL_IPLog_List_f, "lists names of players whose IP address begins with the supplied text (example: iplog_list 123.456.789)"); + Cmd_AddCommand(CF_CLIENT, "nextul", QW_CL_NextUpload_f, "sends next fragment of current upload buffer (screenshot for example)"); + Cmd_AddCommand(CF_CLIENT, "stopul", QW_CL_StopUpload_f, "aborts current upload (screenshot for example)"); + Cmd_AddCommand(CF_CLIENT | CF_CLIENT_FROM_SERVER, "skins", QW_CL_Skins_f, "downloads missing qw skins from server"); + Cmd_AddCommand(CF_CLIENT, "changing", QW_CL_Changing_f, "sent by qw servers to tell client to wait for level change"); + Cmd_AddCommand(CF_CLIENT, "cl_begindownloads", CL_BeginDownloads_f, "used internally by darkplaces client while connecting (causes loading of models and sounds or triggers downloads for missing ones)"); + Cmd_AddCommand(CF_CLIENT | CF_CLIENT_FROM_SERVER, "cl_downloadbegin", CL_DownloadBegin_f, "(networking) informs client of download file information, client replies with sv_startsoundload to begin the transfer"); + Cmd_AddCommand(CF_CLIENT | CF_CLIENT_FROM_SERVER, "stopdownload", CL_StopDownload_f, "terminates a download"); + Cmd_AddCommand(CF_CLIENT | CF_CLIENT_FROM_SERVER, "cl_downloadfinished", CL_DownloadFinished_f, "signals that a download has finished and provides the client with file size and crc to check its integrity"); + Cmd_AddCommand(CF_CLIENT, "iplog_list", CL_IPLog_List_f, "lists names of players whose IP address begins with the supplied text (example: iplog_list 123.456.789)"); } void CL_Parse_Shutdown(void)