Fix ignore command.

Add cl_lerp_driftbias and cl_lerp_driftfrac cvars, to tweak drifting. changed defaults to try to reduce clamping.
Implement ladders with nq player physics.
Fix submodel contents with nq player physics.
Implemented drawrotpic_dp for compat (incompatible with fte's earlier implementation)
Added con_textfont cvar to set fonts without uglifying menuqc/csqc drawstrings that don't specify explicit fonts.
Enemycolor and teamcolor are now true cvars, which means they now work with seta.
Move the homedir from CSIDL_PERSONAL to CSIDL_LOCAL_APPDATA, because microsoft apparently scrape all CSIDL_PERSONAL data for upload to their servers, because they don't understand 'personal'. Will still use the old homedir if it exists.
Pack signon data without wasting so much, primarily to allow abusive mods to spew larger individual signon messages (hurrah for packet fragmentation).


git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5546 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2019-09-17 19:49:39 +00:00
parent 40b7193cef
commit 131a6be4bc
27 changed files with 523 additions and 165 deletions

View File

@ -89,12 +89,12 @@ char *Player_MyName (void)
cvar_t ignore_spec = CVAR("ignore_spec", "0");
cvar_t ignore_spec = CVARD("ignore_spec", "0", "0: Never ignore spectators.\n1: Ignore spectators only when playing.\n2: Always ignore spectators even when spectating.");
cvar_t ignore_qizmo_spec = CVAR("ignore_qizmo_spec", "0");
cvar_t ignore_mode = CVAR("ignore_mode", "0");
cvar_t ignore_flood_duration = CVARD("ignore_flood_duration", "4", "Time limit for inbound messages to be considered duplicates.");
cvar_t ignore_flood = CVARD("ignore_flood", "0", "Provides a way to reduce inbound spam from flooding out your chat (dupe messages are ignored).\n0: No inbound flood protection.\n1: Duplicate non-team messages will be filtered.\n2: ALL duplicate messages will be filtered");
cvar_t ignore_opponents = CVAR("ignore_opponents", "0");
cvar_t ignore_opponents = CVARD("ignore_opponents", "0", "0: Don't ignore chat from enemies.\n1: Always ignore chat from opponents (note: can also ignore f_ruleset checks).\n2: Ignore chat from opponents only during a match (requires servers that actually reports match state).\n");
char ignoreteamlist[MAX_TEAMIGNORELIST][16 + 1];
@ -597,7 +597,7 @@ qboolean Ignore_Message(const char *sendername, const char *s, int flags)
if (ignore_opponents.ival && (
(int) ignore_opponents.ival == 1 ||
(cls.state >= ca_connected && /*!cl.standby &&*/ !cls.demoplayback && !pv->spectator) // match?
(cls.state >= ca_connected && cl.matchstate == MATCH_INPROGRESS && !cls.demoplayback && !pv->spectator) // match?
) &&
flags == 1 && !pv->spectator && slot != pv->playernum &&
(!cl.teamplay || strcmp(cl.players[slot].team, cl.players[pv->playernum].team))

View File

@ -5770,6 +5770,9 @@ static char *CL_ParseChat(char *text, player_info_t **player, int *msgflags)
if (!cls.demoplayback)
Sys_ServerActivity(); //chat always flashes the screen..
if (Ignore_Message((*player)->name, s, flags))
return NULL;
//check f_ stuff
if (*player && (!strncmp(s, "f_", 2)|| !strncmp(s, "q_", 2)))
{

View File

@ -21,10 +21,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "winquake.h"
cvar_t cl_predict_extrapolate = CVARD("cl_predict_extrapolate", "", "If 1, enables prediction based upon partial input frames which can change over time resulting in a swimmy feel but does not need to interpolate. If 0, prediction will stay in the past and thus use only completed frames. Interpolation will then be used to smooth movement.\nThis cvar only applies when video and input frames are independant (ie: cl_netfps is set).");
cvar_t cl_predict_timenudge = CVARD("cl_predict_timenudge", "0", "A debug feature. You should normally leave this as 0. Nudges local player prediction into the future if positive (resulting in extrapolation), or into the past if negative (resulting in laggy interpolation). Value is in seconds, so small decimals are required. This cvar applies even if input frames are tied to video frames.");
cvar_t cl_predict_smooth = CVARD("cl_lerp_smooth", "2", "If 2, will act as 1 when playing demos/singleplayer and otherwise act as if set to 0 (ie: deathmatch).\nIf 1, interpolation will run in the past, resulting in really smooth movement at the cost of latency (even on bunchy german ISDNs).\nIf 0, interpolation will be based upon packet arrival times and may judder due to packet loss.");
static cvar_t cl_predict_timenudge = CVARD("cl_predict_timenudge", "0", "A debug feature. You should normally leave this as 0. Nudges local player prediction into the future if positive (resulting in extrapolation), or into the past if negative (resulting in laggy interpolation). Value is in seconds, so small decimals are required. This cvar applies even if input frames are tied to video frames.");
cvar_t cl_lerp_smooth = CVARD("cl_lerp_smooth", "2", "If 2, will act as 1 when playing demos/singleplayer and otherwise act as if set to 0 (ie: deathmatch).\nIf 1, interpolation will run in the past, resulting in really smooth movement at the cost of latency (even on bunchy german ISDNs).\nIf 0, interpolation will be based upon packet arrival times and may judder due to packet loss.");
static cvar_t cl_lerp_driftbias = CVARD("cl_lerp_driftbias", "0", "Additional bias, can be set to a negative value to hold interpolation in the past.");
static cvar_t cl_lerp_driftfrac = CVARD("cl_lerp_driftfrac", "0", "Proportion of the latest time vs the older time to favour drifting towards.");
cvar_t cl_nopred = CVARD("cl_nopred","0", "Disables clientside movement prediction.");
cvar_t cl_pushlatency = CVAR("pushlatency","-999");
static cvar_t cl_pushlatency = CVAR("pushlatency","-999");
extern float pm_airaccelerate;
@ -632,7 +634,7 @@ void CL_CalcClientTime(void)
//q3 always drifts.
//nq+qw code can drift
//default is to drift in demos+SP but not live (oh noes! added latency!)
if (cls.protocol == CP_QUAKE2 || (cls.protocol != CP_QUAKE3 && (!cl_predict_smooth.ival || (cl_predict_smooth.ival == 2 && !(cls.demoplayback || cl.allocated_client_slots == 1 || cl.playerview[0].spectator))) && cls.demoplayback != DPB_MVD))
if (cls.protocol == CP_QUAKE2 || (cls.protocol != CP_QUAKE3 && (!cl_lerp_smooth.ival || (cl_lerp_smooth.ival == 2 && !(cls.demoplayback || cl.allocated_client_slots == 1 || cl.playerview[0].spectator))) && cls.demoplayback != DPB_MVD))
{ //no drift logic
float f;
f = cl.gametime - cl.oldgametime;
@ -650,6 +652,8 @@ void CL_CalcClientTime(void)
max = cl.gametime;
min = cl.oldgametime;
FloatInterpolate(min, cl_lerp_driftfrac.value, max, min);
min += cl_lerp_driftbias.value;
if (max < min)
max = min;
@ -664,7 +668,7 @@ void CL_CalcClientTime(void)
else
cl.servertime = 0;
if (cl.servertime > max)
if (cl.servertime > min)
{
if (cl.servertime > max)
{
@ -1445,5 +1449,8 @@ void CL_InitPrediction (void)
Cvar_Register (&cl_nopred, cl_predictiongroup);
Cvar_Register (&cl_predict_extrapolate, cl_predictiongroup);
Cvar_Register (&cl_predict_timenudge, cl_predictiongroup);
Cvar_Register (&cl_predict_smooth, cl_predictiongroup);
Cvar_Register (&cl_lerp_smooth, cl_predictiongroup);
Cvar_Register (&cl_lerp_driftbias, cl_predictiongroup);
Cvar_Register (&cl_lerp_driftfrac, cl_predictiongroup);
}

View File

@ -1010,7 +1010,7 @@ void M_Menu_Network_f (void)
};
static const char *smoothingvalues[] = {"0", "1", "2", NULL};
extern cvar_t cl_download_csprogs, cl_download_redirection, requiredownloads, cl_solid_players;
extern cvar_t cl_predict_players, cl_predict_smooth, cl_predict_extrapolate;
extern cvar_t cl_predict_players, cl_lerp_smooth, cl_predict_extrapolate;
static menuresel_t resel;
int y;
menubulk_t bulk[] =
@ -1025,7 +1025,7 @@ void M_Menu_Network_f (void)
MB_CHECKBOXCVARTIP("Redirect Download", cl_download_redirection, 0, "Whether the client will ignore download redirection from servers"),
MB_CHECKBOXCVARTIP("Download CSQC", cl_download_csprogs, 0, "Whether to allow the client to download CSQC (client-side QuakeC) progs from servers"),
MB_SPACING(4),
MB_COMBOCVAR("Network Smoothing", cl_predict_smooth, smoothingopts, smoothingvalues, "Smoother gameplay comes at the cost of higher latency. Which do you favour?"),
MB_COMBOCVAR("Network Smoothing", cl_lerp_smooth, smoothingopts, smoothingvalues, "Smoother gameplay comes at the cost of higher latency. Which do you favour?"),
MB_CHECKBOXCVARTIP("Extrapolate Prediction", cl_predict_extrapolate, 0, "Extrapolate local player movement beyond the frames already sent to the server"),
MB_CHECKBOXCVARTIP("Predict Other Players", cl_predict_players, 0, "Toggle player prediction"),
MB_CHECKBOXCVARTIP("Solid Players", cl_solid_players, 0, "When running/clipping into other players, ON make it appear they are solid, OFF will make it appear like running into a marshmellon."),

View File

@ -2768,7 +2768,7 @@ static void QCBUILTIN PF_cs_pointcontents(pubprogfuncs_t *prinst, struct globalv
v = G_VECTOR(OFS_PARM0);
cont = cl.worldmodel?World_PointContents(w, v):FTECONTENTS_EMPTY;
cont = cl.worldmodel?World_PointContentsWorldOnly(w, v):FTECONTENTS_EMPTY;
if (cont & FTECONTENTS_SOLID)
G_FLOAT(OFS_RETURN) = Q1CONTENTS_SOLID;
else if (cont & FTECONTENTS_SKY)
@ -2786,13 +2786,14 @@ static void QCBUILTIN PF_cs_pointcontents(pubprogfuncs_t *prinst, struct globalv
static int CS_FindModel(const char *name, int *free)
{
int i;
const char *fixedname;
*free = 0;
if (!name || !*name)
return 0;
name = Mod_FixName(name, csqc_world.worldmodel->name);
fixedname = Mod_FixName(name, csqc_world.worldmodel->publicname);
for (i = 1; i < MAX_CSMODELS; i++)
{
@ -2801,7 +2802,7 @@ static int CS_FindModel(const char *name, int *free)
*free = -i;
break;
}
if (!strcmp(cl.model_csqcname[i], name))
if (!strcmp(cl.model_csqcname[i], fixedname))
return -i;
}
for (i = 1; i < MAX_PRECACHE_MODELS; i++)
@ -2908,16 +2909,14 @@ static int PF_cs_PrecacheModel_Internal(pubprogfuncs_t *prinst, const char *mode
if (!*modelname)
return 0;
fixedname = Mod_FixName(modelname, csqc_world.worldmodel->publicname);
for (i = 1; i < MAX_PRECACHE_MODELS; i++) //Make sure that the server specified model is loaded..
{
if (!*cl.model_name[i])
break;
if (!strcmp(cl.model_name[i], fixedname))
if (!strcmp(cl.model_name[i], modelname))
{
if (!cl.model_precache[i])
cl.model_precache[i] = Mod_ForName(cl.model_name[i], MLV_WARN);
cl.model_precache[i] = Mod_ForName(Mod_FixName(modelname, csqc_world.worldmodel->publicname), MLV_WARN);
break;
}
}
@ -6481,7 +6480,9 @@ static struct {
{"stringwidth", PF_CL_stringwidth, 327}, // #327 EXT_CSQC_'DARKPLACES'
{"drawsubpic", PF_CL_drawsubpic, 328}, // #328 EXT_CSQC_'DARKPLACES'
{"drawrotsubpic", PF_CL_drawrotsubpic, 0},
// {"?", PF_Fixme, 329}, // #329 EXT_CSQC_'DARKPLACES'
#ifdef HAVE_LEGACY
{"drawrotpic_dp", PF_CL_drawrotpic_dp, 329},
#endif
//330
{"getstati", PF_cs_getstati, 330}, // #330 float(float stnum) getstati (EXT_CSQC)

View File

@ -689,6 +689,57 @@ void QCBUILTIN PF_CL_drawrotsubpic (pubprogfuncs_t *prinst, struct globalvars_s
G_FLOAT(OFS_RETURN) = 1;
}
#ifdef HAVE_LEGACY
/*fuck sake, why does no one give a shit about existing extension?!? seriously this stuff is pissing me off*/
void QCBUILTIN PF_CL_drawrotpic_dp (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
float *pivot = G_VECTOR(OFS_PARM0);
const char *picname = PR_GetStringOfs(prinst, OFS_PARM1);
float *size = G_VECTOR(OFS_PARM2);
float *mins = G_VECTOR(OFS_PARM3);
float angle = (G_FLOAT(OFS_PARM4) * M_PI)/180;
float *rgb = G_VECTOR(OFS_PARM5);
float alpha = G_FLOAT(OFS_PARM6);
int flag = prinst->callargc >= 8?(int) G_FLOAT(OFS_PARM7):0;
vec3_t maxs;
vec2_t points[4];
vec2_t tcoords[4];
vec2_t saxis;
vec2_t taxis;
mpic_t *p;
VectorSubtract(size, mins, maxs);
p = R2D_SafeCachePic(picname);
if (!p)
p = R2D_SafePicFromWad(picname);
saxis[0] = cos(angle);
saxis[1] = sin(angle);
taxis[0] = -sin(angle);
taxis[1] = cos(angle);
Vector2MA(pivot, mins[0], saxis, points[0]); Vector2MA(points[0], mins[1], taxis, points[0]);
Vector2MA(pivot, maxs[0], saxis, points[1]); Vector2MA(points[1], mins[1], taxis, points[1]);
Vector2MA(pivot, maxs[0], saxis, points[2]); Vector2MA(points[2], maxs[1], taxis, points[2]);
Vector2MA(pivot, mins[0], saxis, points[3]); Vector2MA(points[3], maxs[1], taxis, points[3]);
Vector2Set(tcoords[0], 0, 0);
Vector2Set(tcoords[1], 1, 0);
Vector2Set(tcoords[2], 1, 1);
Vector2Set(tcoords[3], 0, 1);
r2d_be_flags = PF_SelectDPDrawFlag(prinst, flag);
R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
R2D_Image2dQuad((const vec2_t*)points, (const vec2_t*)tcoords, NULL, p);
r2d_be_flags = 0;
G_FLOAT(OFS_RETURN) = 1;
}
#endif
void QCBUILTIN PF_CL_is_cached_pic (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -1417,7 +1468,11 @@ void QCBUILTIN PF_clientstate (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
if (isDedicated)
G_FLOAT(OFS_RETURN) = 0;
else
G_FLOAT(OFS_RETURN) = cls.state >= ca_connected ? 2 : 1; //fit in with netquake (we never run a menu.dat dedicated)
{
//fit in with netquake (we never run a menu.dat dedicated)
//we return 2 for trying to connect, to avoid bugs with certain menuqc mods
G_FLOAT(OFS_RETURN) = (cls.state >= ca_connected||CL_TryingToConnect()) ? 2 : 1;
}
}
//too specific to the prinst's builtins.
@ -2312,7 +2367,10 @@ static struct {
{"drawsubpic", PF_CL_drawsubpic, 469},
{"drawrotsubpic", PF_CL_drawrotsubpic, 0},
{"drawtextfield", PF_CL_DrawTextField, 0},
//470
#ifdef HAVE_LEGACY
{"drawrotpic_dp", PF_CL_drawrotpic_dp, 470},
#endif
//MERGES WITH CLIENT+SERVER BUILTIN MAPPINGS BELOW
{"asin", PF_asin, 471},
{"acos", PF_acos, 472},
@ -2612,6 +2670,7 @@ void MP_Shutdown (void)
if (!menu_world.progs)
return;
menuqc.release = NULL; //don't notify
Menu_Unlink(&menuqc);
/*
{
@ -2798,6 +2857,7 @@ qboolean MP_Init (void)
menuqc.keyevent = MP_KeyEvent;
menuqc.joyaxis = MP_JoystickAxis;
menuqc.release = MP_TryRelease;
menuqc.persist = true; //don't bother trying to kill it...
menutime = Sys_DoubleTime();
if (!menu_world.progs)

View File

@ -55,7 +55,7 @@ struct
extern cvar_t scr_conalpha;
extern cvar_t gl_conback;
extern cvar_t gl_font;
extern cvar_t gl_font, con_textfont;
extern cvar_t gl_screenangle;
extern cvar_t vid_conautoscale;
extern cvar_t vid_conheight;
@ -135,6 +135,7 @@ qbyte GetPaletteIndexNoFB(int red, int green, int blue)
void R2D_Shutdown(void)
{
Cvar_Unhook(&con_textfont);
Cvar_Unhook(&gl_font);
Cvar_Unhook(&vid_conautoscale);
Cvar_Unhook(&gl_screenangle);
@ -393,6 +394,7 @@ void R2D_Init(void)
);
Cvar_Hook(&con_textfont, R2D_Font_Callback);
Cvar_Hook(&gl_font, R2D_Font_Callback);
Cvar_Hook(&vid_conautoscale, R2D_Conautoscale_Callback);
Cvar_Hook(&gl_screenangle, R2D_ScreenAngle_Callback);
@ -1057,14 +1059,17 @@ int R2D_Font_ListSystemFonts(const char *fname, qofs_t fsize, time_t modtime, vo
void R2D_Font_Changed(void)
{
float tsize;
const char *con_font_name = con_textfont.string;
if (!con_textsize.modified)
return;
if (!*con_font_name)
con_font_name = gl_font.string;
con_textsize.modified = false;
if (con_textsize.value < 0)
tsize = (-con_textsize.value * vid.height) / vid.pixelheight;
tsize = (-con_textsize.value * vid.height) / vid.pixelheight; //size defined in physical pixels
else
tsize = con_textsize.value;
tsize = con_textsize.value; //size defined in virtual pixels.
if (!tsize)
tsize = 8;
@ -1151,9 +1156,9 @@ void R2D_Font_Changed(void)
if (!font_default && *gl_font.string)
font_default = Font_LoadFont("", 8);
if (tsize != 8)
if (tsize != 8 || strcmp(gl_font.string, con_font_name))
{
font_console = Font_LoadFont(gl_font.string, tsize);
font_console = Font_LoadFont(con_font_name, tsize);
if (!font_console)
font_console = Font_LoadFont("", tsize);
}

View File

@ -367,7 +367,12 @@ cvar_t gl_conback = CVARFCD ("gl_conback", "",
//cvar_t gl_detail = CVARF ("gl_detail", "0",
// CVAR_ARCHIVE);
//cvar_t gl_detailscale = CVAR ("gl_detailscale", "5");
cvar_t gl_font = CVARAFD ("gl_font", "", "gl_consolefont",
cvar_t gl_font = CVARFD ("gl_font", "",
CVAR_RENDERERCALLBACK|CVAR_ARCHIVE, ("Specifies the font file to use. a value such as FONT:ALTFONT specifies an alternative font to be used when ^^a is used.\n"
"When using TTF fonts, you will likely need to scale text to at least 150% - vid_conautoscale 1.5 will do this.\n"
"TTF fonts may be loaded from your windows directory. \'gl_font cour?col=1,1,1:couri?col=0,1,0\' loads eg: c:\\windows\\fonts\\cour.ttf, and uses the italic version of courier for alternative text, with specific colour tints."
));
cvar_t con_textfont = CVARAFD ("con_textfont", "", "gl_consolefont",
CVAR_RENDERERCALLBACK|CVAR_ARCHIVE, ("Specifies the font file to use. a value such as FONT:ALTFONT specifies an alternative font to be used when ^^a is used.\n"
"When using TTF fonts, you will likely need to scale text to at least 150% - vid_conautoscale 1.5 will do this.\n"
"TTF fonts may be loaded from your windows directory. \'gl_font cour?col=1,1,1:couri?col=0,1,0\' loads eg: c:\\windows\\fonts\\cour.ttf, and uses the italic version of courier for alternative text, with specific colour tints."
@ -925,6 +930,7 @@ void Renderer_Init(void)
//screen
Cvar_Register (&con_textfont, GRAPHICALNICETIES);
Cvar_Register (&gl_font, GRAPHICALNICETIES);
Cvar_Register (&scr_conspeed, SCREENOPTIONS);
Cvar_Register (&scr_conalpha, SCREENOPTIONS);

View File

@ -66,11 +66,25 @@ qboolean suppress;
#define Q_rint(f) ((int)((f)+0.5))
// callbacks used for TP cvars
#ifdef QWSKINS
static void QDECL TP_SkinCvar_Callback(struct cvar_s *var, char *oldvalue);
static void QDECL TP_TeamColor_CB (struct cvar_s *var, char *oldvalue);
static void QDECL TP_EnemyColor_CB (struct cvar_s *var, char *oldvalue);
#define TP_SKIN_CVARS \
TP_CVARAC(cl_teamskin, "", teamskin, TP_SkinCvar_Callback); \
TP_CVARAC(cl_enemyskin, "", enemyskin, TP_SkinCvar_Callback); \
TP_CVARC(enemycolor, "off", TP_EnemyColor_CB); \
TP_CVARC(teamcolor, "off", TP_TeamColor_CB);
#else
#define TP_SKIN_CVARS
#endif
//a list of all the cvars
//this is down to the fact that I keep defining them but forgetting to register. :/
#define TP_CVARS \
TP_SKIN_CVARS \
TP_CVAR(cl_fakename, ""); \
TP_CVAR(cl_parseSay, "1"); \
TP_CVAR(cl_parseFunChars, "1"); \
@ -78,8 +92,6 @@ static void QDECL TP_SkinCvar_Callback(struct cvar_s *var, char *oldvalue);
TP_CVAR(tp_autostatus, ""); /* things which will not always change, but are useful */ \
TP_CVAR(tp_forceTriggers, "0"); \
TP_CVAR(tp_loadlocs, "1"); \
TP_CVARAC(cl_teamskin, "", teamskin, TP_SkinCvar_Callback); \
TP_CVARAC(cl_enemyskin, "", enemyskin, TP_SkinCvar_Callback); \
TP_CVAR(tp_soundtrigger, "~"); \
\
TP_CVAR(tp_name_none, ""); \
@ -2050,88 +2062,54 @@ static void TP_Colourise_f (void)
}
}
static void TP_TeamColor_f (void)
static void TP_TeamColor_CB (struct cvar_s *var, char *oldvalue)
{
unsigned int top, bottom;
int i;
if (Cmd_Argc() == 1)
{
Com_Printf ("\"teamcolor\" is \"");
if (cl_teamtopcolor == ~0)
Com_Printf ("off");
else
Com_Printf (cl_teamtopcolor>=16?"0x%06x":"%i", cl_teamtopcolor&0x00ffffff);
if (cl_teamtopcolor != cl_teambottomcolor)
{
if (cl_teambottomcolor == ~0)
Com_Printf (" off");
else
Com_Printf (cl_teambottomcolor>=16?" 0x%06x":" %i", cl_teambottomcolor&0x00ffffff);
}
Com_Printf ("\"\n");
return;
}
top = TP_ForceColour(Cmd_Argv(1));
if (Cmd_Argc() == 2)
char *n = COM_Parse(var->string);
top = TP_ForceColour(com_token);
COM_Parse(n);
if (!*com_token)
bottom = top;
else {
bottom = TP_ForceColour(Cmd_Argv(2));
bottom = TP_ForceColour(com_token);
}
// if (top != cl_teamtopcolor || bottom != cl_teambottomcolor)
{
cl_teamtopcolor = top;
cl_teambottomcolor = bottom;
cl_teamtopcolor = top;
cl_teambottomcolor = bottom;
if (qrenderer != QR_NONE) //make sure we have the renderer initialised...
for (i = 0; i < cl.allocated_client_slots; i++)
CL_NewTranslation(i);
}
if (qrenderer != QR_NONE) //make sure we have the renderer initialised...
for (i = 0; i < cl.allocated_client_slots; i++)
CL_NewTranslation(i);
}
static void TP_EnemyColor_f (void)
static void TP_EnemyColor_CB (struct cvar_s *var, char *oldvalue)
{
unsigned int top, bottom;
int i;
if (Cmd_Argc() == 1)
{
Com_Printf ("\"enemycolor\" is \"");
if (cl_enemytopcolor == ~0)
Com_Printf ("off");
else
Com_Printf (cl_enemytopcolor>=16?"0x%06x":"%i", cl_enemytopcolor&0x00ffffff);
if (cl_enemytopcolor != cl_enemybottomcolor)
{
if (cl_enemybottomcolor == ~0)
Com_Printf (" off");
else
Com_Printf (cl_enemybottomcolor>=16?" 0x%06x":" %i", cl_enemybottomcolor&0x00ffffff);
}
Com_Printf ("\"\n");
return;
}
top = TP_ForceColour(Cmd_Argv(1));
if (Cmd_Argc() == 2)
char *n = COM_Parse(var->string);
top = TP_ForceColour(com_token);
COM_Parse(n);
if (!*com_token)
bottom = top;
else {
bottom = TP_ForceColour(Cmd_Argv(2));
bottom = TP_ForceColour(com_token);
}
// if (top != cl_enemytopcolor || bottom != cl_enemybottomcolor)
{
cl_enemytopcolor = top;
cl_enemybottomcolor = bottom;
cl_enemytopcolor = top;
cl_enemybottomcolor = bottom;
if (qrenderer != QR_NONE) //make sure we have the renderer initialised...
for (i = 0; i < cl.allocated_client_slots; i++)
CL_NewTranslation(i);
}
if (qrenderer != QR_NONE) //make sure we have the renderer initialised...
for (i = 0; i < cl.allocated_client_slots; i++)
CL_NewTranslation(i);
}
static void QDECL TP_SkinCvar_Callback(struct cvar_s *var, char *oldvalue)
{
Skin_FlushPlayers();
}
#endif
//===================================================================
@ -3681,11 +3659,6 @@ static void TP_MsgFilter_f (void)
}
}
static void QDECL TP_SkinCvar_Callback(struct cvar_s *var, char *oldvalue)
{
Skin_FlushPlayers();
}
void TP_Init (void)
{
#define TEAMPLAYVARS "Teamplay Variables"
@ -3703,8 +3676,6 @@ void TP_Init (void)
Cmd_AddCommand ("filter", TP_MsgFilter_f);
Cmd_AddCommand ("msg_trigger", TP_MsgTrigger_f);
#ifdef QWSKINS
Cmd_AddCommand ("teamcolor", TP_TeamColor_f);
Cmd_AddCommand ("enemycolor", TP_EnemyColor_f);
Cmd_AddCommand ("colourise", TP_Colourise_f); //uk
Cmd_AddCommand ("colorize", TP_Colourise_f); //us
//Cmd_AddCommand ("colorise", TP_Colourise_f); //piss off both.

View File

@ -9287,7 +9287,7 @@ static qboolean QDECL Mod_LoadObjModel(model_t *mod, void *buffer, size_t fsize)
size_t numverts = 0;
size_t maxverts = 0;
struct objvert *vert = NULL, defaultvert={{-1,-1,-1}};
struct objvert *vert = NULL, defaultvert={{-1,-1,-2}};
size_t numelems = 0;
size_t maxelems = 0;
@ -9351,11 +9351,10 @@ static qboolean QDECL Mod_LoadObjModel(model_t *mod, void *buffer, size_t fsize)
if(!isspace(c[1])) continue;
while(isalpha(*c)) c++;
while(isspace(*c)) c++;
int key = strtol(c, &c, 10);
//make sure that these verts are not merged, ensuring that they get smoothed.
//different texture coords will still have discontinuities though.
defaultvert.attrib[2] = -2-key;
defaultvert.attrib[2] = -1-strtol(c, &c, 10);
break;
}
case 'f':
@ -9425,7 +9424,7 @@ static qboolean QDECL Mod_LoadObjModel(model_t *mod, void *buffer, size_t fsize)
{
if (vert[cur].attrib[0] == vkey.attrib[0] &&
vert[cur].attrib[1] == vkey.attrib[1] &&
vert[cur].attrib[2] == vkey.attrib[2])
vert[cur].attrib[2] == vkey.attrib[2] && vkey.attrib[2]!=-1)
break;
}
if (cur == numverts)

View File

@ -556,6 +556,10 @@ static qboolean FS_Manifest_ParseTokens(ftemanifest_t *man)
Z_Free(man->defaultexec);
man->defaultexec = Z_StrDup(Cmd_Argv(1));
}
else if (!Q_strcasecmp(cmd, "-bind") || !Q_strcasecmp(cmd, "-set") || !Q_strcasecmp(cmd, "-seta") || !Q_strcasecmp(cmd, "-alias"))
{
Z_StrCat(&man->defaultexec, va("%s %s\n", Cmd_Argv(0)+1, Cmd_Args()));
}
else if (!Q_strcasecmp(cmd, "bind") || !Q_strcasecmp(cmd, "set") || !Q_strcasecmp(cmd, "seta") || !Q_strcasecmp(cmd, "alias"))
{
Z_StrCat(&man->defaultoverrides, va("%s %s\n", Cmd_Argv(0), Cmd_Args()));
@ -810,7 +814,7 @@ static int QDECL COM_Dir_List(const char *name, qofs_t size, time_t mtime, void
}
else if (!Q_strcasecmp(link, "bsp") || !Q_strcasecmp(link, "spr") || !Q_strcasecmp(link, "mdl") || !Q_strcasecmp(link, "md3") || !Q_strcasecmp(link, "iqm") ||
!Q_strcasecmp(link, "vvm") || !Q_strcasecmp(link, "psk") || !Q_strcasecmp(link, "dpm") || !Q_strcasecmp(link, "zym") || !Q_strcasecmp(link, "md5mesh") ||
!Q_strcasecmp(link, "mdx") || !Q_strcasecmp(link, "md2") ||
!Q_strcasecmp(link, "mdx") || !Q_strcasecmp(link, "md2") || !Q_strcasecmp(link, "obj") ||
!Q_strcasecmp(link, "md5anim") || !Q_strcasecmp(link, "gltf") || !Q_strcasecmp(link, "glb") || !Q_strcasecmp(link, "ase") || !Q_strcasecmp(link, "lwo"))
Q_snprintfz(link, sizeof(link), "\\tip\\Open in Model Viewer\\modelviewer\\%s", name);
else if (!Q_strcasecmp(link, "qc") || !Q_strcasecmp(link, "src") || !Q_strcasecmp(link, "qh") || !Q_strcasecmp(link, "h") || !Q_strcasecmp(link, "c")
@ -6405,12 +6409,18 @@ static void COM_InitHomedir(ftemanifest_t *man)
{
wchar_t wfolder[MAX_PATH];
char folder[MAX_OSPATH];
// 0x5 == CSIDL_PERSONAL
if (dSHGetFolderPathW(NULL, 0x5, NULL, 0, wfolder) == S_OK)
if (dSHGetFolderPathW(NULL, 0x5/*CSIDL_PERSONAL*/, NULL, 0, wfolder) == S_OK)
{
narrowen(folder, sizeof(folder), wfolder);
Q_snprintfz(com_homepath, sizeof(com_homepath), "%s/My Games/%s/", folder, HOMESUBDIR);
}
//at some point, microsoft (in their infinitesimal wisdom) decided that 'CSIDL_PERSONAL' should mean 'CSIDL_GIVEITALLTOMICROSOFT'
//so use the old/CSIDL_NOTACTUALLYPERSONAL path by default for compat, but if there's nothing there then switch to CSIDL_LOCAL_APPDATA instead
if ((!*com_homepath||!GetFileAttributesU(com_homepath)) && dSHGetFolderPathW(NULL, 0x1c/*CSIDL_LOCAL_APPDATA*/, NULL, 0, wfolder) == S_OK)
{
narrowen(folder, sizeof(folder), wfolder);
Q_snprintfz(com_homepath, sizeof(com_homepath), "%s/%s/", folder, HOMESUBDIR);
}
}
// if (shfolder)
// FreeLibrary(shfolder);

View File

@ -2904,6 +2904,8 @@ void QCBUILTIN PF_WasFreed (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
{
wedict_t *ent;
ent = G_WEDICT(prinst, OFS_PARM0);
if (!ent)
PR_BIError(prinst, "PF_WasFreed: invalid entity");
G_FLOAT(OFS_RETURN) = ED_ISFREE(ent);
}
@ -2920,7 +2922,12 @@ void QCBUILTIN PF_edict_for_num(pubprogfuncs_t *prinst, struct globalvars_s *pr_
unsigned int num = G_FLOAT(OFS_PARM0);
if (num >= w->num_edicts)
RETURN_EDICT(prinst, w->edicts);
G_INT(OFS_RETURN) = num; //just directly store it. if its not spawned yet we'll need to catch that elsewhere anyway.
else
{
G_INT(OFS_RETURN) = num; //just directly store it. if its not spawned yet we'll need to catch that elsewhere anyway.
if (G_WEDICT(prinst, OFS_RETURN))
RETURN_EDICT(prinst, w->edicts); //hoi! it wasn't valid!
}
}
/*

View File

@ -404,6 +404,9 @@ void QCBUILTIN PF_CL_stringwidth (pubprogfuncs_t *prinst, struct globalvars_s *p
void QCBUILTIN PF_CL_drawsubpic (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_CL_drawrotpic (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_CL_drawrotsubpic (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
#ifdef HAVE_LEGACY
void QCBUILTIN PF_CL_drawrotpic_dp (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
#endif
void QCBUILTIN PF_CL_findfont (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_CL_loadfont (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
#if defined(CSQC_DAT) && !defined(SERVERONLY)

View File

@ -331,7 +331,8 @@ void World_TouchLinks (world_t *w, wedict_t *ent, areanode_t *node);
#define World_TouchAllLinks(w,e) World_TouchLinks(w,e,(w)->areanodes)
#endif
int World_PointContents (world_t *w, vec3_t p);
int World_PointContentsWorldOnly (world_t *w, vec3_t p);
int World_PointContentsAllBSPs (world_t *w, vec3_t p);
// returns the CONTENTS_* value from the world at the given point.
// does not check any entities at all

View File

@ -311,14 +311,14 @@ void R_BloomBlend (texid_t source, int x, int y, int w, int h)
return;
/*update textures if we need to resize them*/
R_SetupBloomTextures(w, h);
R_SetupBloomTextures(r_refdef.pxrect.width, r_refdef.pxrect.height);
/*filter the screen into a downscaled image*/
if (!TEXVALID(pingtex[0][0]))
{
sprintf(name, "***bloom*%c*%i***", 'a'+0, 0);
TEXASSIGN(pingtex[0][0], Image_CreateTexture(name, NULL, IF_CLAMP|IF_NOMIPMAP|IF_NOPICMIP|IF_LINEAR));
Image_Upload(pingtex[0][0], TF_RGBA32, NULL, NULL, texwidth[0], texheight[0], IF_CLAMP|IF_NOMIPMAP|IF_NOPICMIP|IF_LINEAR);
Image_Upload(pingtex[0][0], PTI_RGBA8, NULL, NULL, texwidth[0], texheight[0], IF_CLAMP|IF_NOMIPMAP|IF_NOPICMIP|IF_LINEAR|IF_NOSRGB);
}
if (R2D_Flush)
@ -341,13 +341,13 @@ void R_BloomBlend (texid_t source, int x, int y, int w, int h)
{
sprintf(name, "***bloom*%c*%i***", 'a'+0, i);
TEXASSIGN(pingtex[0][i], Image_CreateTexture(name, NULL, IF_CLAMP|IF_NOMIPMAP|IF_NOPICMIP|IF_LINEAR));
Image_Upload(pingtex[0][i], TF_RGBA32, NULL, NULL, texwidth[i], texheight[i], IF_CLAMP|IF_NOMIPMAP|IF_NOPICMIP|IF_LINEAR);
Image_Upload(pingtex[0][i], PTI_RGBA8, NULL, NULL, texwidth[i], texheight[i], IF_CLAMP|IF_NOMIPMAP|IF_NOPICMIP|IF_LINEAR|IF_NOSRGB);
}
if (!TEXVALID(pingtex[1][i]))
{
sprintf(name, "***bloom*%c*%i***", 'a'+1, i);
TEXASSIGN(pingtex[1][i], Image_CreateTexture(name, NULL, IF_CLAMP|IF_NOMIPMAP|IF_NOPICMIP|IF_LINEAR));
Image_Upload(pingtex[1][i], TF_RGBA32, NULL, NULL, texwidth[i], texheight[i], IF_CLAMP|IF_NOMIPMAP|IF_NOPICMIP|IF_LINEAR);
Image_Upload(pingtex[1][i], PTI_RGBA8, NULL, NULL, texwidth[i], texheight[i], IF_CLAMP|IF_NOMIPMAP|IF_NOPICMIP|IF_LINEAR|IF_NOSRGB);
}
if (R2D_Flush)

View File

@ -4863,7 +4863,12 @@ void Shader_Programify (parsestate_t *ps)
{
pass = &s->passes[i];
if (pass->rgbgen == RGB_GEN_LIGHTING_DIFFUSE || pass->rgbgen == RGB_GEN_ENTITY_LIGHTING_DIFFUSE)
modellighting = pass;
{
if (s->usageflags & SUF_LIGHTMAP)
lightmap = pass;
else
modellighting = pass;
}
else if (pass->rgbgen == RGB_GEN_ENTITY)
modellighting = pass;
else if (pass->rgbgen == RGB_GEN_VERTEX_LIGHTING || pass->rgbgen == RGB_GEN_VERTEX_EXACT)

View File

@ -4828,7 +4828,7 @@ static void QCBUILTIN PF_pointcontents (pubprogfuncs_t *prinst, struct globalvar
v = G_VECTOR(OFS_PARM0);
cont = World_PointContents(w, v);
cont = World_PointContentsWorldOnly(w, v);
if (cont & FTECONTENTS_SOLID)
G_FLOAT(OFS_RETURN) = Q1CONTENTS_SOLID;
else if (cont & FTECONTENTS_SKY)

View File

@ -1176,7 +1176,7 @@ static qintptr_t QVM_WriteEntity (void *offset, quintptr_t mask, const qintptr_t
}
static qintptr_t QVM_FlushSignon (void *offset, quintptr_t mask, const qintptr_t *arg)
{
SV_FlushSignon ();
SV_FlushSignon (false);
return 0;
}
static qintptr_t QVM_memset (void *offset, quintptr_t mask, const qintptr_t *arg)

View File

@ -21,8 +21,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define QW_SERVER
#define MAX_SIGNON_BUFFERS 16
typedef enum {
ss_dead, // no map loaded
ss_clustermode,
@ -229,9 +227,8 @@ typedef struct
// multiple signon messages are kept
// fte only stores writebyted stuff in here. everything else is regenerated based upon the client's extensions.
sizebuf_t signon;
int num_signon_buffers;
int signon_buffer_size[MAX_SIGNON_BUFFERS];
qbyte signon_buffers[MAX_SIGNON_BUFFERS][MAX_DATAGRAM];
int used_signon_space;
qbyte signon_buffer[MAX_OVERALLMSGLEN]; //flushed after every 512 bytes (two leading bytes says the size of the buffer).
qboolean gamedirchanged;
@ -1261,7 +1258,7 @@ void MSV_OpenUserDatabase(void);
//
void SV_SpawnServer (const char *server, const char *startspot, qboolean noents, qboolean usecinematic);
void SV_UnspawnServer (void);
void SV_FlushSignon (void);
void SV_FlushSignon (qboolean force);
void SV_UpdateMaxPlayers(int newmax);
void SV_FilterImpulseInit(void);

View File

@ -118,19 +118,26 @@ int SV_SafeModelIndex (char *name)
SV_FlushSignon
Moves to the next signon buffer if needed
This stops any chunk from getting too large, hopefully, but if the worst happens then hopefully network fragmentation will work.
================
*/
void SV_FlushSignon (void)
{
if (sv.signon.cursize < sv.signon.maxsize - 512)
return;
void SV_FlushSignon (qboolean force)
{ //flush only when it gets too big.
if (sv.signon.cursize < MAX_DATAGRAM - 512)
{
if (!force || !sv.signon.cursize)
return;
}
if (sv.num_signon_buffers == MAX_SIGNON_BUFFERS-1)
SV_Error ("sv.num_signon_buffers == MAX_SIGNON_BUFFERS-1");
if (sv.signon.cursize)
{
sv.signon.data[-2] = (sv.signon.cursize>>0)&0xff;
sv.signon.data[-1] = (sv.signon.cursize>>8)&0xff;
sv.used_signon_space += 2+sv.signon.cursize;
}
sv.signon_buffer_size[sv.num_signon_buffers-1] = sv.signon.cursize;
sv.signon.data = sv.signon_buffers[sv.num_signon_buffers];
sv.num_signon_buffers++;
sv.signon.data = sv.signon_buffer + sv.used_signon_space+2;
sv.signon.maxsize = sizeof(sv.signon_buffer) - (sv.used_signon_space+2);
sv.signon.cursize = 0;
sv.signon.prim = svs.netprim;
}
@ -784,10 +791,10 @@ void SV_SetupNetworkBuffers(qboolean bigcoords)
sv.master.data = sv.master_buf;
sv.master.prim = msg_nullnetprim;
sv.signon.maxsize = sizeof(sv.signon_buffers[0]);
sv.signon.data = sv.signon_buffers[0];
sv.signon.data = sv.signon_buffer+2;
sv.used_signon_space = 0;
sv.signon.prim = svs.netprim;
sv.num_signon_buffers = 1;
sv.signon.maxsize = sizeof(sv.signon_buffer)-sv.used_signon_space;
}
void SV_WipeServerState(void)
@ -1612,7 +1619,8 @@ MSV_OpenUserDatabase();
#ifdef Q2SERVER
SVQ2_BuildBaselines();
#endif
sv.signon_buffer_size[sv.num_signon_buffers-1] = sv.signon.cursize;
SV_FlushSignon(true);
// all spawning is completed, any further precache statements
// or prog writes to the signon message are errors
@ -1679,7 +1687,7 @@ MSV_OpenUserDatabase();
#endif
)
{
if (sv.num_signon_buffers > 1 || sv.signon.cursize)
if (sv.used_signon_space || sv.signon.cursize)
Con_Printf("Cannot auto-enable extended coords as the init buffer was used\n");
else
{

View File

@ -88,7 +88,7 @@ qboolean World_CheckBottom (world_t *world, wedict_t *ent, vec3_t up)
{
start[a0] = x ? maxs[a0] : mins[a0];
start[a1] = y ? maxs[a1] : mins[a1];
if (!(World_PointContents (world, start) & FTECONTENTS_SOLID))
if (!(World_PointContentsWorldOnly (world, start) & FTECONTENTS_SOLID))
goto realcheck;
}
@ -195,7 +195,7 @@ qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, vec3_t axis
if (trace.fraction == 1)
{
if ( (eflags & FL_SWIM) && !(World_PointContents(world, trace.endpos) & FTECONTENTS_FLUID))
if ( (eflags & FL_SWIM) && !(World_PointContentsWorldOnly(world, trace.endpos) & FTECONTENTS_FLUID))
continue; // swim monster left water
VectorCopy (trace.endpos, ent->v->origin);

View File

@ -1261,7 +1261,7 @@ static void WPhys_CheckWaterTransition (world_t *w, wedict_t *ent)
{
int cont;
cont = World_PointContents (w, ent->v->origin);
cont = World_PointContentsWorldOnly (w, ent->v->origin);
//needs to be q1 progs compatible
if (cont & FTECONTENTS_LAVA)
@ -1602,11 +1602,38 @@ static void WPhys_CheckStuck (world_t *w, wedict_t *ent)
=============
SV_CheckWater
=============
for players
*/
static qboolean WPhys_CheckWater (world_t *w, wedict_t *ent)
{
vec3_t point;
int cont;
int hc;
trace_t tr;
//check if we're on a ladder, and if so fire a trace forwards to ensure its a valid ladder instead of a random volume
hc = ent->xv->hitcontentsmaski; //lame
ent->xv->hitcontentsmaski = ~0;
tr = World_Move(w, ent->v->origin, ent->v->mins, ent->v->maxs, ent->v->origin, 0, ent);
ent->xv->hitcontentsmaski = hc;
if (tr.contents & FTECONTENTS_LADDER)
{
vec3_t flatforward;
flatforward[0] = cos((M_PI/180)*ent->v->angles[1]);
flatforward[1] = sin((M_PI/180)*ent->v->angles[1]);
flatforward[2] = 0;
VectorMA (ent->v->origin, 24, flatforward, point);
tr = World_Move(w, ent->v->origin, ent->v->mins, ent->v->maxs, point, 0, ent);
if (tr.fraction < 1)
ent->xv->pmove_flags = (int)ent->xv->pmove_flags|PMF_LADDER;
else if ((int)ent->xv->pmove_flags & PMF_LADDER)
ent->xv->pmove_flags -= PMF_LADDER;
}
else if ((int)ent->xv->pmove_flags & PMF_LADDER)
ent->xv->pmove_flags -= PMF_LADDER;
point[0] = ent->v->origin[0];
point[1] = ent->v->origin[1];
@ -1614,7 +1641,7 @@ static qboolean WPhys_CheckWater (world_t *w, wedict_t *ent)
ent->v->waterlevel = 0;
ent->v->watertype = Q1CONTENTS_EMPTY;
cont = World_PointContents (w, point);
cont = World_PointContentsAllBSPs (w, point);
if (cont & FTECONTENTS_FLUID)
{
if (cont & FTECONTENTS_LAVA)
@ -1627,12 +1654,12 @@ static qboolean WPhys_CheckWater (world_t *w, wedict_t *ent)
ent->v->watertype = Q1CONTENTS_SKY;
ent->v->waterlevel = 1;
point[2] = ent->v->origin[2] + (ent->v->mins[2] + ent->v->maxs[2])*0.5;
cont = World_PointContents (w, point);
cont = World_PointContentsAllBSPs (w, point);
if (cont & FTECONTENTS_FLUID)
{
ent->v->waterlevel = 2;
point[2] = ent->v->origin[2] + ent->v->view_ofs[2];
cont = World_PointContents (w, point);
cont = World_PointContentsAllBSPs (w, point);
if (cont & FTECONTENTS_FLUID)
ent->v->waterlevel = 3;
}
@ -2242,7 +2269,8 @@ void WPhys_RunEntity (world_t *w, wedict_t *ent)
gravitydir = w->g.defaultgravitydir;
if (!WPhys_CheckWater (w, ent) && ! ((int)ent->v->flags & FL_WATERJUMP) ) //Vanilla Bug: the QC checks waterlevel inside PlayerPreThink, with waterlevel from a different position from the origin.
WPhys_AddGravity (w, ent, gravitydir);
if (!((int)ent->xv->pmove_flags & PMF_LADDER))
WPhys_AddGravity (w, ent, gravitydir);
WPhys_CheckStuck (w, ent);
WPhys_WalkMove (w, ent, gravitydir);

View File

@ -541,7 +541,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
if (to == MULTICAST_INIT)
{
//we only have one signon buffer. make sure you don't put non-identical protocols in the buffer
SV_FlushSignon();
SV_FlushSignon(false);
SZ_Write (&sv.signon, sv.multicast.data, sv.multicast.cursize);
//and send to players that are already on

View File

@ -1461,24 +1461,32 @@ void SV_SendClientPrespawnInfo(client_t *client)
if (client->prespawn_stage == PRESPAWN_SIGNON_BUF)
{
int nextsize;
while (client->netchan.message.cursize < maxsize)
{
if (client->prespawn_idx >= sv.num_signon_buffers)
if (client->prespawn_idx >= sv.used_signon_space)
{
client->prespawn_stage++;
client->prespawn_idx = 0;
break;
}
if (client->netchan.message.cursize+sv.signon_buffer_size[client->prespawn_idx]+30 < client->netchan.message.maxsize)
nextsize = sv.signon_buffer[client->prespawn_idx] | (sv.signon_buffer[client->prespawn_idx+1]<<8);
if (client->netchan.message.cursize+nextsize+30 <= client->netchan.message.maxsize)
{
SZ_Write (&client->netchan.message,
sv.signon_buffers[client->prespawn_idx],
sv.signon_buffer_size[client->prespawn_idx]);
SZ_Write (&client->netchan.message, sv.signon_buffer+client->prespawn_idx+2, nextsize);
client->prespawn_idx+=2+nextsize;
}
else if (!client->netchan.message.cursize && nextsize+30 > client->netchan.message.maxsize)
{ //signon data is meant to be split up into smallish chunks to avoid network fragmentation.
//but sometimes a single blob is too large (eg: gamecode not using MSG_MULTICAST and just writing 16k in one splurge)
//fteqw and nq protocols can cope, vanilla qw cannot, so we do need to warn. the alternative is to kick.
SV_PrintToClient(client, PRINT_HIGH, va("\x01" "Dropping %i bytes of signon data\n", nextsize));
client->prespawn_idx+=2+nextsize;
break;
}
else
break;
client->prespawn_idx++;
}
}
@ -8996,6 +9004,80 @@ static void SV_WaterMove (void)
velocity[i] += accelspeed * wishvel[i];
}
static void SV_LadderMove (void)
{
int i;
vec3_t wishvel;
float speed, newspeed, wishspeed, addspeed, accelspeed;
float scale;
float maxspeed;
//
// user intentions
//
AngleVectors (sv_player->v->v_angle, forward, right, up);
for (i=0 ; i<3 ; i++)
wishvel[i] = forward[i]*cmd.forwardmove + right[i]*cmd.sidemove;
wishvel[2] += cmd.upmove;
wishspeed = Length(wishvel);
// val = GetEdictFieldValue(sv_player, "scale", &scalecache);
// if (!val || !val->_float)
scale = 1;
// else
// scale = val->_float;
// val = GetEdictFieldValue(sv_player, "maxspeed", &maxspeedcache);
// if (val && val->_float)
// maxspeed = sv_maxspeed.value*val->_float;
// else
maxspeed = host_client->maxspeed;
if (wishspeed > maxspeed*scale)
{
VectorScale (wishvel, maxspeed/wishspeed, wishvel);
wishspeed = maxspeed*scale;
}
wishspeed *= 0.7;
//
// water friction
//
speed = Length (velocity);
if (speed)
{
// val = GetEdictFieldValue(sv_player, "friction", &frictioncache);
// if (val&&val->_float)
// newspeed = speed - host_frametime * speed * sv_friction.value*val->_float;
// else
newspeed = speed - host_frametime * speed * sv_friction.value;
if (newspeed < 0)
newspeed = 0;
VectorScale (velocity, newspeed/speed, velocity);
}
else
newspeed = 0;
//
// water acceleration
//
if (!wishspeed)
return;
addspeed = wishspeed - newspeed;
if (addspeed <= 0)
return;
VectorNormalize (wishvel);
accelspeed = sv_accelerate.value * wishspeed * host_frametime;
if (accelspeed > addspeed)
accelspeed = addspeed;
for (i=0 ; i<3 ; i++)
velocity[i] += accelspeed * wishvel[i];
}
static void SV_WaterJump (void)
{
if (sv.time > sv_player->v->teleport_time
@ -9087,14 +9169,12 @@ void SV_ClientThink (void)
//
// walk
//
if ( (sv_player->v->waterlevel >= 2)
&& (sv_player->v->movetype != MOVETYPE_NOCLIP) )
{
if ( (sv_player->v->waterlevel >= 2) && (sv_player->v->movetype != MOVETYPE_NOCLIP) )
SV_WaterMove ();
return;
}
SV_AirMove ();
else if (((int)sv_player->xv->pmove_flags&PMF_LADDER) && (sv_player->v->movetype != MOVETYPE_NOCLIP) )
SV_LadderMove();
else
SV_AirMove ();
}
#endif

View File

@ -53,6 +53,7 @@ typedef struct
qboolean capsule;
} moveclip_t;
static unsigned int World_ContentsOfAllLinks (world_t *w, vec3_t pos);
/*
===============================================================================
@ -123,7 +124,7 @@ hull_t *World_HullForBox (vec3_t mins, vec3_t maxs)
return &box_hull;
}
model_t mod_capsule;
static model_t mod_capsule;
qboolean World_BoxTrace(struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, unsigned int against, struct trace_s *trace)
{
hull_t *hull = &box_hull;
@ -1151,11 +1152,18 @@ SV_PointContents
==================
*/
int World_PointContents (world_t *w, vec3_t p)
int World_PointContentsWorldOnly (world_t *w, vec3_t p)
{
return w->worldmodel->funcs.PointContents(w->worldmodel, NULL, p);
}
int World_PointContentsAllBSPs (world_t *w, vec3_t p)
{
int c = w->worldmodel->funcs.PointContents(w->worldmodel, NULL, p);
c |= World_ContentsOfAllLinks(w, p);
return c;
}
//===========================================================================
/*
@ -1326,7 +1334,7 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v
{
memset (&trace, 0, sizeof(trace_t));
trace.fraction = 1;
trace.allsolid = true;
trace.allsolid = false;
trace.startsolid = false;
trace.inopen = true; //probably wrong...
VectorCopy (end, trace.endpos);
@ -1460,13 +1468,13 @@ int World_AreaEdicts (world_t *w, vec3_t mins, vec3_t maxs, wedict_t **list, int
}
#else
float *area_mins, *area_maxs;
wedict_t **area_list;
static float *area_mins, *area_maxs;
static wedict_t **area_list;
#ifdef Q2SERVER
q2edict_t **area_q2list;
static q2edict_t **area_q2list;
#endif
int area_count, area_maxcount;
int area_type;
static int area_count, area_maxcount;
static int area_type;
static void World_AreaEdicts_r (areanode_t *node)
{
link_t *l, *next, *start;
@ -2088,6 +2096,95 @@ static void World_ClipToAllLinks (world_t *w, moveclip_t *clip)
World_ClipToLinks(w, &w->gridareas[g[0] + g[1]*w->gridsize[0]], clip);
}
}
static unsigned int World_ContentsOfLinks (world_t *w, areagridlink_t *node, vec3_t pos)
{
link_t *l, *next;
wedict_t *touch;
model_t *model;
int mdlidx;
vec3_t pos_l, axis[3];
unsigned int ret = 0, c;
// touch linked edicts
for (l = node->l.next ; l != &node->l ; l = next)
{
next = l->next;
touch = ((areagridlink_t*)l)->ed;
if (touch->gridareasequence == areagridsequence)
continue;
touch->gridareasequence = areagridsequence;
if (touch->v->solid != SOLID_BSP)
continue;
if ( pos[0] > touch->v->absmax[0]
|| pos[1] > touch->v->absmax[1]
|| pos[2] > touch->v->absmax[2]
|| pos[0] < touch->v->absmin[0]
|| pos[1] < touch->v->absmin[1]
|| pos[2] < touch->v->absmin[2] )
continue;
// if (touch->v->solid == SOLID_PORTAL)
// //FIXME: recurse!
mdlidx = touch->v->modelindex;
if (!mdlidx)
continue;
model = w->Get_CModel(w, mdlidx);
if (!model || (model->type != mod_brush && model->type != mod_heightmap) || model->loadstate != MLS_LOADED)
continue;
VectorSubtract (pos, touch->v->origin, pos_l);
if (touch->v->angles[0] || touch->v->angles[1] || touch->v->angles[2])
{
AngleVectors (touch->v->angles, axis[0], axis[1], axis[2]);
VectorNegate(axis[1], axis[1]);
c = model->funcs.PointContents(model, axis, pos_l);
}
else
c = model->funcs.PointContents(model, NULL, pos_l);
if (c && touch->v->skin < 0)
{ //if forcedcontents is set, then ALL brushes in this model are forced to the specified contents value.
//we achive this by tracing against ALL then forcing it after.
unsigned int forcedcontents;
switch((int)touch->v->skin)
{
case Q1CONTENTS_EMPTY: forcedcontents = FTECONTENTS_EMPTY; break;
case Q1CONTENTS_SOLID: forcedcontents = FTECONTENTS_SOLID; break;
case Q1CONTENTS_WATER: forcedcontents = FTECONTENTS_WATER; break;
case Q1CONTENTS_SLIME: forcedcontents = FTECONTENTS_SLIME; break;
case Q1CONTENTS_LAVA: forcedcontents = FTECONTENTS_LAVA; break;
case Q1CONTENTS_SKY: forcedcontents = FTECONTENTS_SKY; break;
case Q1CONTENTS_LADDER: forcedcontents = FTECONTENTS_LADDER;break;
default: forcedcontents = 0; break;
}
c = forcedcontents;
}
ret |= c;
}
return ret;
}
static unsigned int World_ContentsOfAllLinks (world_t *w, vec3_t pos)
{
int ming[2], maxg[2], g[2];
unsigned int ret;
areagridsequence++;
ret = World_ContentsOfLinks(w, &w->jumboarea, pos);
CALCAREAGRIDBOUNDS(w, pos, pos);
for ( g[0] = ming[0]; g[0] < maxg[0]; g[0]++)
for (g[1] = ming[1]; g[1] < maxg[1]; g[1]++)
{
ret |= World_ContentsOfLinks(w, &w->gridareas[g[0] + g[1]*w->gridsize[0]], pos);
}
return ret;
}
#else
/*
====================
@ -2227,6 +2324,62 @@ static void World_ClipToLinks (world_t *w, areanode_t *node, moveclip_t *clip)
if ( clip->boxmins[node->axis] < node->dist )
World_ClipToLinks (w, node->children[1], clip );
}
static unsigned int World_ContentsOfLinks (world_t *w, areanode_t *node, vec3_t pos)
{
unsigned int c = 0;
link_t *l, *next;
wedict_t *touch;
trace_t trace;
// touch linked edicts
for (l = node->edicts.next ; l != &node->edicts ; l = next)
{
next = l->next;
touch = EDICT_FROM_AREA(l);
if (touch->v->solid == SOLID_NOT)
continue;
/*if its a trigger, we only clip against it if the flags are aligned*/
if (touch->v->solid == SOLID_TRIGGER)
continue;
if (pos[0] > touch->v->absmax[0]
|| pos[1] > touch->v->absmax[1]
|| pos[2] > touch->v->absmax[2]
|| pos[0] < touch->v->absmin[0]
|| pos[1] < touch->v->absmin[1]
|| pos[2] < touch->v->absmin[2] )
continue;
/*if (touch->v->solid == SOLID_PORTAL)
{
//make sure we don't hit the world if we're inside the portal
World_PortalCSG(touch, vec3_origin, vec3_origin, pos, pos, &clip->trace);
}*/
trace = World_ClipMoveToEntity (w, touch, touch->v->origin, touch->v->angles, pos, vec3_origin, vec3_origin, pos, 0, false, false, ~0u);
if (trace.startsolid)
c |= trace.contents;
}
// recurse down both sides
if (node->axis == -1)
return c;
if ( pos[node->axis] > node->dist )
c |= World_ContentsOfLinks (w, node->children[0], pos );
if ( pos[node->axis] < node->dist )
c |= World_ContentsOfLinks (w, node->children[1], pos );
return c;
}
static unsigned int World_ContentsOfAllLinks (world_t *w, vec3_t pos)
{
return World_ContentsOfLinks(w, w->areanodes, pos);
}
#endif
#if defined(HAVE_CLIENT) && defined(CSQC_DAT)
@ -2329,6 +2482,9 @@ static void World_ClipToNetwork (world_t *w, moveclip_t *clip)
}*/
}
if (model && touchcontents != ~0)
trace.contents = touchcontents;
if (trace.fraction < clip->trace.fraction)
{
//trace traveled less, but don't forget if we started in a solid.

View File

@ -541,8 +541,10 @@ void Mod_ExportIQM(char *fname, int flags, galiasinfo_t *mesh)
if (m->ofs_skel_xyz)
ivert = m->ofs_skel_xyz;
#ifdef NONSKELETALMODELS
else if (m->numanimations && m->ofsanimations->numposes)
ivert = m->ofsanimations->poseofs->ofsverts;
#endif
else
ivert = NULL;
if (ivert)
@ -588,12 +590,14 @@ void Mod_ExportIQM(char *fname, int flags, galiasinfo_t *mesh)
isdir = m->ofs_skel_svect;
itdir = m->ofs_skel_tvect;
}
#ifdef NONSKELETALMODELS
else if (m->numanimations && m->ofsanimations->numposes)
{
inorm = m->ofsanimations->poseofs->ofsnormals;
isdir = m->ofsanimations->poseofs->ofssvector;
itdir = m->ofsanimations->poseofs->ofstvector;
}
#endif
else
{
inorm = NULL;

View File

@ -11,6 +11,7 @@ FIXME: no way to speciffy which gen plugin to use for a particular map
#include "com_mesh.h"
#include "gl_terrain.h"
#ifdef TERRAIN
#define GENHIGHTSCALE 1024.0
static plugterrainfuncs_t *terr;
@ -276,4 +277,10 @@ qboolean Plug_Init(void)
terr->AutogenerateSection = TerrorGen_GenerateBlock;
return true;
}
}
#else
qboolean Plug_Init(void)
{
return false;
}
#endif