diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 04c871477..e3bf2501b 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -2695,8 +2695,47 @@ static void CLDP_ParseDownloadBegin(char *s) if (!dl || strcmp(fname, dl->remotename)) { - Con_Printf("Warning: server started sending a file we did not request. Ignoring.\n"); - return; + if (cls.demoplayback && !dl && cl_dp_csqc_progssize && size == cl_dp_csqc_progssize && !strcmp(fname, cl_dp_csqc_progsname)) + { //its somewhat common for demos to contain a copy of the csprogs, so that the same version is available when trying to play the demo back. + extern cvar_t cl_download_csprogs, cl_nocsqc; + if (!cl_nocsqc.ival && cl_download_csprogs.ival) + { + fname = va("csprogsvers/%x.dat", cl_dp_csqc_progscrc); + if (CL_CheckDLFile(fname)) + return; //we already have this version + + //Begin downloading it... + } + else + return; //silently ignore it + } + else + { + Con_Printf("Warning: server started sending a file we did not request. Ignoring.\n"); + return; + } + } + + if (!dl) + { + dl = Z_Malloc(sizeof(*dl)); + dl->filesequence = 0; + + Q_strncpyz(dl->remotename, fname, sizeof(dl->remotename)); + Q_strncpyz(dl->localname, fname, sizeof(dl->localname)); + Con_TPrintf ("Downloading %s...\n", dl->localname); + + // download to a temp name, and only rename + // to the real name when done, so if interrupted + // a runt file wont be left + COM_StripExtension (dl->localname, dl->tempname, sizeof(dl->tempname)-5); + Q_strncatz (dl->tempname, ".tmp", sizeof(dl->tempname)); + + dl->method = DL_DARKPLACES; + dl->percent = 0; + dl->sizeunknown = true; + dl->flags = DLLF_REQUIRED; + cls.download = dl; } if (dl->method == DL_QWPENDING) diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index bf57aff85..3b1f61d0b 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -961,6 +961,9 @@ void CL_PredictMovePNum (int seat) else VectorCopy(cl.currentpackentities->fixedangles[seat], pv->simangles); + if (cls.demoplayback) + VectorCopy(pv->simangles, pv->viewangles); + if (cl.currentpackentities->fixangles[seat] == 2) lerpangles = (cls.demoplayback == DPB_QUAKEWORLD); } diff --git a/engine/client/zqtp.c b/engine/client/zqtp.c index 2b06e536d..c1c902b15 100644 --- a/engine/client/zqtp.c +++ b/engine/client/zqtp.c @@ -50,7 +50,7 @@ typedef qboolean qbool; extern int cl_spikeindex, cl_playerindex, cl_h_playerindex, cl_flagindex, cl_rocketindex, cl_grenadeindex, cl_gib1index, cl_gib2index, cl_gib3index; -extern cvar_t v_viewheight; +extern cvar_t v_viewheight, dpcompat_console; trace_t PM_TraceLine (vec3_t start, vec3_t end); #define ISDEAD(i) ( (i) >= 41 && (i) <= 102 ) @@ -3855,7 +3855,14 @@ void CL_Say (qboolean team, char *extra) int split = CL_TargettedSplit(true); if (split >= cl.splitclients) return; - CL_SendClientCommand(true, "%s%s \"%s%s\"", split?va("%i ", split+1):"", team ? "say_team" : "say", extra?extra:"", sendtext); + //messagemode always adds quotes. the console command never did. + //the server is expected to use Cmd_Args and to strip first+last chars if the first is a quote. this is annoying and clumsy for mods to parse. +#ifndef NOLEGACY + if (!dpcompat_console.ival) + CL_SendClientCommand(true, "%s%s \"%s%s\"", split?va("%i ", split+1):"", team ? "say_team" : "say", extra?extra:"", sendtext); + else +#endif + CL_SendClientCommand(true, "%s%s %s%s", split?va("%i ", split+1):"", team ? "say_team" : "say", extra?extra:"", sendtext); } } diff --git a/engine/common/cmd.c b/engine/common/cmd.c index cb51d9f01..bae366f23 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -1357,7 +1357,7 @@ void Cmd_ShiftArgs (int ammount, qboolean expandstring) } } -const char *Cmd_ExpandCvar(char *cvarterm, int maxaccesslevel, int *newaccesslevel, int *len) +const char *Cmd_ExpandCvar(char *cvarterm, int maxaccesslevel, int *newaccesslevel, qboolean enclosed, int *len) { const char *ret = NULL; char *fixup = NULL, fixval=0, *t; @@ -1401,7 +1401,7 @@ const char *Cmd_ExpandCvar(char *cvarterm, int maxaccesslevel, int *newaccesslev else { pl = 0; - quotetype = dpcompat_console.ival; //default to escaping. + quotetype = enclosed && dpcompat_console.ival; //default to escaping. } if (pl) { @@ -1412,7 +1412,7 @@ const char *Cmd_ExpandCvar(char *cvarterm, int maxaccesslevel, int *newaccesslev else fixup = NULL; if (*cvarterm == '$') - cvarname = Cmd_ExpandCvar(cvarterm+1, maxaccesslevel, newaccesslevel, &pl); + cvarname = Cmd_ExpandCvar(cvarterm+1, maxaccesslevel, newaccesslevel, false, &pl); else cvarname = cvarterm; @@ -1532,7 +1532,7 @@ char *Cmd_ExpandString (const char *data, char *dest, int destlen, int *accessle } buf[i] = 0; bestvar = NULL; - if (expandcvars && (str = Cmd_ExpandCvar(buf+1+striptrailing, maxaccesslevel, accesslevel, &var_length))) + if (expandcvars && (str = Cmd_ExpandCvar(buf+1+striptrailing, maxaccesslevel, accesslevel, true, &var_length))) bestvar = str; if (expandmacros && (str = TP_MacroString (buf+1+striptrailing, accesslevel, &var_length))) bestvar = str; @@ -1564,7 +1564,7 @@ char *Cmd_ExpandString (const char *data, char *dest, int destlen, int *accessle data++; buf[i++] = c; buf[i] = 0; - if (expandcvars && (str = Cmd_ExpandCvar(buf+striptrailing, maxaccesslevel, accesslevel, &var_length))) + if (expandcvars && (str = Cmd_ExpandCvar(buf+striptrailing, maxaccesslevel, accesslevel, false, &var_length))) bestvar = str; if (expandmacros && (str = TP_MacroString (buf+striptrailing, accesslevel, &var_length))) bestvar = str; @@ -2249,7 +2249,7 @@ char *Cmd_CompleteCommand (const char *partial, qboolean fullonly, qboolean case } for (a=cmd_alias ; a ; a=a->next) if (!Q_strncasecmp (partial, a->name, len) && (matchnum == -1 || !partial[len] || strlen(a->name) == len)) - Cmd_CompleteCheck(a->name, &match, ""); + Cmd_CompleteCheck(a->name, &match, a->value); for (grp=cvar_groups ; grp ; grp=grp->next) for (cvar=grp->cvars ; cvar ; cvar=cvar->next) { diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 9aa8600ed..dedfae9e7 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -17,6 +17,9 @@ static char *cvargroup_progs = "Progs variables"; cvar_t sv_gameplayfix_nolinknonsolid = CVARD("sv_gameplayfix_nolinknonsolid", "1", "When 0, setorigin et al will not link the entity into the collision nodes (which is faster, especially if you have a lot of non-solid entities. When 1, allows entities to freely switch between .solid values (except for SOLID_BSP) without relinking. A lot of DP mods assume a value of 1 and will bug out otherwise, while 0 will restore a bugs present in various mods."); cvar_t sv_gameplayfix_blowupfallenzombies = CVARD("sv_gameplayfix_blowupfallenzombies", "0", "Allow findradius to find non-solid entities. This may break certain mods."); cvar_t dpcompat_findradiusarealinks = CVARD("dpcompat_findradiusarealinks", "0", "Use the world collision info to accelerate findradius instead of looping through every single entity. May actually be slower for large radiuses, or fail to find entities which have not been linked properly with setorigin."); +#ifndef NOLEGACY +cvar_t dpcompat_strcatlimitation = CVARD("dpcompat_crippledstrcat", "", "When set, cripples strcat (and related function) string lengths to the value specified.\nSet to 16383 to replicate DP's limit, otherwise leave as 0 to avoid limits."); +#endif cvar_t pr_droptofloorunits = CVARD("pr_droptofloorunits", "256", "Distance that droptofloor is allowed to drop to be considered successul."); cvar_t pr_brokenfloatconvert = CVAR("pr_brokenfloatconvert", "0"); cvar_t pr_fixbrokenqccarrays = CVARFD("pr_fixbrokenqccarrays", "0", CVAR_LATCH, "As part of its nq/qw/h2/csqc support, FTE remaps QC fields to match an internal order. This is a faster way to handle extended fields. However, some QCCs are buggy and don't report all field defs.\n0: do nothing. QCC must be well behaved.\n1: Duplicate engine fields, remap the ones we can to known offsets. This is sufficient for QCCX/FrikQCC mods that use hardcoded or even occasional calculated offsets (fixes ktpro).\n2: Scan the mod for field accessing instructions, and assume those are the fields (and that they don't alias non-fields). This can be used to work around gmqcc's WTFs (fixes xonotic)."); @@ -47,6 +50,9 @@ void PF_Common_RegisterCvars(void) Cvar_Register (&sv_gameplayfix_blowupfallenzombies, cvargroup_progs); Cvar_Register (&sv_gameplayfix_nolinknonsolid, cvargroup_progs); Cvar_Register (&dpcompat_findradiusarealinks, cvargroup_progs); +#ifndef NOLEGACY + Cvar_Register (&dpcompat_strcatlimitation, cvargroup_progs); +#endif Cvar_Register (&pr_droptofloorunits, cvargroup_progs); Cvar_Register (&pr_brokenfloatconvert, cvargroup_progs); Cvar_Register (&pr_tempstringcount, cvargroup_progs); @@ -3592,6 +3598,14 @@ void QCBUILTIN PF_strcat (pubprogfuncs_t *prinst, struct globalvars_s *pr_global s[i] = PR_GetStringOfs(prinst, OFS_PARM0+i*3); l[i] = strlen(s[i]); len += l[i]; + +#ifndef NOLEGACY + if (dpcompat_strcatlimitation.ival && len > dpcompat_strcatlimitation.ival) + { + l[i] -= len-dpcompat_strcatlimitation.ival; + len -= len-dpcompat_strcatlimitation.ival; + } +#endif } len++; /*for the null*/ ((int *)pr_globals)[OFS_RETURN] = prinst->AllocTempString(prinst, &buf, len);