try to fix entertimes.
try to fix gameclock (when joining mid-game on servers that don't support stat_matchstarttime). fix iqm loader issue using the same skin for every surface. modelviewer now allows displaying per-surface info. fix qcc ptr->foo bug. console commands with a leading space are considered to be say messages git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4917 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
0ced7ec194
commit
f35aa1d123
25 changed files with 528 additions and 120 deletions
|
@ -136,6 +136,20 @@ static float CL_TrackScore(player_info_t *pl, char *rule)
|
||||||
}
|
}
|
||||||
return score;
|
return score;
|
||||||
}
|
}
|
||||||
|
static qboolean CL_MayTrack(int seat, int player)
|
||||||
|
{
|
||||||
|
if (player < 0)
|
||||||
|
return false;
|
||||||
|
if (!cl.players[player].userid || !cl.players[player].name[0] || cl.players[player].spectator)
|
||||||
|
return false;
|
||||||
|
for (seat--; seat >= 0; seat--)
|
||||||
|
{
|
||||||
|
//not valid if an earlier view is tracking it.
|
||||||
|
if (Cam_TrackNum(&cl.playerview[seat]) == player)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
//returns the player with the highest frags
|
//returns the player with the highest frags
|
||||||
static int CL_FindHighTrack(int seat, char *rule)
|
static int CL_FindHighTrack(int seat, char *rule)
|
||||||
{
|
{
|
||||||
|
@ -146,7 +160,7 @@ static int CL_FindHighTrack(int seat, char *rule)
|
||||||
|
|
||||||
//set a default to the currently tracked player, to reuse the current player we're tracking if someone lower equalises.
|
//set a default to the currently tracked player, to reuse the current player we're tracking if someone lower equalises.
|
||||||
j = cl.playerview[seat].cam_spec_track;
|
j = cl.playerview[seat].cam_spec_track;
|
||||||
if (j >= 0 && cl.players[j].userid && cl.players[j].name[0] && !cl.players[j].spectator)
|
if (CL_MayTrack(seat, j))
|
||||||
max = CL_TrackScore(&cl.players[j], rule);
|
max = CL_TrackScore(&cl.players[j], rule);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -158,25 +172,18 @@ static int CL_FindHighTrack(int seat, char *rule)
|
||||||
{
|
{
|
||||||
s = &cl.players[i];
|
s = &cl.players[i];
|
||||||
score = CL_TrackScore(s, rule);
|
score = CL_TrackScore(s, rule);
|
||||||
if (s->userid && s->name[0] && !s->spectator && score > max)
|
if (score > max)
|
||||||
{
|
{
|
||||||
if (j == i) //this was our default.
|
if (j == i) //this was our default.
|
||||||
continue;
|
continue;
|
||||||
//skip it if an earlier seat is watching it already
|
if (!CL_MayTrack(seat, i))
|
||||||
for (k = 0; k < seat; k++)
|
continue;
|
||||||
{
|
|
||||||
if (Cam_TrackNum(&cl.playerview[k]) == i)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (cl.teamplay && seat && cl.playerview[0].cam_spec_track >= 0 && strcmp(cl.players[cl.playerview[0].cam_spec_track].team, s->team))
|
if (cl.teamplay && seat && cl.playerview[0].cam_spec_track >= 0 && strcmp(cl.players[cl.playerview[0].cam_spec_track].team, s->team))
|
||||||
continue; //when using multiview, keep tracking the team
|
continue; //when using multiview, keep tracking the team
|
||||||
if (k == seat)
|
|
||||||
{
|
|
||||||
max = CL_TrackScore(s, rule);
|
max = CL_TrackScore(s, rule);
|
||||||
j = i;
|
j = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,7 +231,7 @@ qboolean Cam_DrawViewModel(playerview_t *pv)
|
||||||
|
|
||||||
int Cam_TrackNum(playerview_t *pv)
|
int Cam_TrackNum(playerview_t *pv)
|
||||||
{
|
{
|
||||||
if (pv->cam_state == CAM_EYECAM)
|
if (cl.spectator && pv->cam_state == CAM_EYECAM)
|
||||||
return pv->cam_spec_track;
|
return pv->cam_spec_track;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1419,7 +1419,7 @@ void CL_Record_f (void)
|
||||||
{
|
{
|
||||||
MSG_WriteByte (&buf, svc_updateentertime);
|
MSG_WriteByte (&buf, svc_updateentertime);
|
||||||
MSG_WriteByte (&buf, i);
|
MSG_WriteByte (&buf, i);
|
||||||
MSG_WriteFloat (&buf, player->entertime);
|
MSG_WriteFloat (&buf, realtime - player->realentertime); //seconds since
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*player->userinfo)
|
if (*player->userinfo)
|
||||||
|
|
|
@ -59,6 +59,14 @@ int CL_TargettedSplit(qboolean nowrap)
|
||||||
char *c;
|
char *c;
|
||||||
int pnum;
|
int pnum;
|
||||||
int mod;
|
int mod;
|
||||||
|
|
||||||
|
//explicitly targetted at some seat number from the server
|
||||||
|
if (Cmd_ExecLevel > RESTRICT_SERVER)
|
||||||
|
return Cmd_ExecLevel - RESTRICT_SERVER-1;
|
||||||
|
if (Cmd_ExecLevel == RESTRICT_SERVER)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
//locally executed command.
|
||||||
if (nowrap)
|
if (nowrap)
|
||||||
mod = MAX_SPLITS;
|
mod = MAX_SPLITS;
|
||||||
else
|
else
|
||||||
|
@ -1579,6 +1587,23 @@ qboolean CLQW_SendCmd (sizebuf_t *buf)
|
||||||
|
|
||||||
if (cl.sendprespawn)
|
if (cl.sendprespawn)
|
||||||
buf->cursize = st; //don't send movement commands while we're still supposedly downloading. mvdsv does not like that.
|
buf->cursize = st; //don't send movement commands while we're still supposedly downloading. mvdsv does not like that.
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//FIXME: user a timer.
|
||||||
|
if (!cls.netchan.message.cursize && cl.allocated_client_slots > 1 && cl.splitclients && (cls.fteprotocolextensions & PEXT_SPLITSCREEN))
|
||||||
|
{
|
||||||
|
int targ = cl_splitscreen.ival+1;
|
||||||
|
if (targ > MAX_SPLITS)
|
||||||
|
targ = MAX_SPLITS;
|
||||||
|
if (cl.splitclients < targ)
|
||||||
|
{
|
||||||
|
char buffer[2048];
|
||||||
|
CL_SendClientCommand(true, "addseat %i %s", cl.splitclients, COM_QuotedString(cls.userinfo[cl.splitclients], buffer, sizeof(buffer), false));
|
||||||
|
}
|
||||||
|
else if (cl.splitclients > targ)
|
||||||
|
CL_SendClientCommand(true, "addseat %i", targ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return dontdrop;
|
return dontdrop;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6099,6 +6099,24 @@ void CLQW_ParseServerMessage (void)
|
||||||
Cbuf_Execute (); // make sure any stuffed commands are done
|
Cbuf_Execute (); // make sure any stuffed commands are done
|
||||||
CLQW_ParseServerData ();
|
CLQW_ParseServerData ();
|
||||||
break;
|
break;
|
||||||
|
case svc_signonnum:
|
||||||
|
cl.splitclients = MSG_ReadByte();
|
||||||
|
for (i = 0; i < cl.splitclients && i < 4; i++)
|
||||||
|
{
|
||||||
|
cl.playerview[i].playernum = MSG_ReadByte();
|
||||||
|
cl.playerview[i].viewentity = cl.playerview[i].playernum+1;
|
||||||
|
}
|
||||||
|
if (i < cl.splitclients)
|
||||||
|
{
|
||||||
|
Con_Printf("Server sent us too many seats!\n");
|
||||||
|
for (; i < cl.splitclients; i++)
|
||||||
|
{ //svcfte_choosesplitclient has a modulo that is also broken, but at least there's no parse errors this way
|
||||||
|
MSG_ReadByte();
|
||||||
|
// CL_SendClientCommand(true, va("%i drop", i+1));
|
||||||
|
}
|
||||||
|
cl.splitclients = MAX_SPLITS;
|
||||||
|
}
|
||||||
|
break;
|
||||||
#ifdef PEXT_SETVIEW
|
#ifdef PEXT_SETVIEW
|
||||||
case svc_setview:
|
case svc_setview:
|
||||||
if (!(cls.fteprotocolextensions & PEXT_SETVIEW))
|
if (!(cls.fteprotocolextensions & PEXT_SETVIEW))
|
||||||
|
@ -6224,7 +6242,7 @@ void CLQW_ParseServerMessage (void)
|
||||||
i = MSG_ReadByte ();
|
i = MSG_ReadByte ();
|
||||||
if (i >= MAX_CLIENTS)
|
if (i >= MAX_CLIENTS)
|
||||||
Host_EndGame ("CL_ParseServerMessage: svc_updateentertime > MAX_SCOREBOARD");
|
Host_EndGame ("CL_ParseServerMessage: svc_updateentertime > MAX_SCOREBOARD");
|
||||||
cl.players[i].entertime = cl.servertime - MSG_ReadFloat ();
|
cl.players[i].realentertime = realtime - MSG_ReadFloat ();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case svc_spawnbaseline:
|
case svc_spawnbaseline:
|
||||||
|
|
|
@ -464,7 +464,7 @@ typedef struct {
|
||||||
char name[PLUGMAX_SCOREBOARDNAME];
|
char name[PLUGMAX_SCOREBOARDNAME];
|
||||||
int ping;
|
int ping;
|
||||||
int pl;
|
int pl;
|
||||||
int starttime;
|
float activetime;
|
||||||
int userid;
|
int userid;
|
||||||
int spectator;
|
int spectator;
|
||||||
char userinfo[1024];
|
char userinfo[1024];
|
||||||
|
@ -501,7 +501,7 @@ static qintptr_t VARGS Plug_GetPlayerInfo(void *offset, quintptr_t mask, const q
|
||||||
Q_strncpyz(out->name, cl.players[i].name, PLUGMAX_SCOREBOARDNAME);
|
Q_strncpyz(out->name, cl.players[i].name, PLUGMAX_SCOREBOARDNAME);
|
||||||
out->ping = cl.players[i].ping;
|
out->ping = cl.players[i].ping;
|
||||||
out->pl = cl.players[i].pl;
|
out->pl = cl.players[i].pl;
|
||||||
out->starttime = cl.players[i].entertime;
|
out->activetime = realtime - cl.players[i].realentertime;
|
||||||
out->userid = cl.players[i].userid;
|
out->userid = cl.players[i].userid;
|
||||||
out->spectator = cl.players[i].spectator;
|
out->spectator = cl.players[i].spectator;
|
||||||
Q_strncpyz(out->userinfo, cl.players[i].userinfo, sizeof(out->userinfo));
|
Q_strncpyz(out->userinfo, cl.players[i].userinfo, sizeof(out->userinfo));
|
||||||
|
|
|
@ -552,7 +552,7 @@ void CL_CalcClientTime(void)
|
||||||
}
|
}
|
||||||
else// if (cls.protocol != CP_QUAKE3)
|
else// if (cls.protocol != CP_QUAKE3)
|
||||||
{
|
{
|
||||||
float oldst = realtime;
|
// float oldst = realtime;
|
||||||
|
|
||||||
if (cls.demoplayback && cls.timedemo)
|
if (cls.demoplayback && cls.timedemo)
|
||||||
{ //more deterministic. one frame is drawn per demo packet parsed. so sync to it as closely as possible.
|
{ //more deterministic. one frame is drawn per demo packet parsed. so sync to it as closely as possible.
|
||||||
|
@ -574,7 +574,7 @@ void CL_CalcClientTime(void)
|
||||||
{
|
{
|
||||||
float min, max;
|
float min, max;
|
||||||
|
|
||||||
oldst = cl.servertime;
|
// oldst = cl.servertime;
|
||||||
|
|
||||||
max = cl.gametime;
|
max = cl.gametime;
|
||||||
min = cl.oldgametime;
|
min = cl.oldgametime;
|
||||||
|
@ -624,7 +624,7 @@ void CL_CalcClientTime(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cl.time = cl.servertime;
|
cl.time = cl.servertime;
|
||||||
if (oldst == 0)
|
/* if (oldst == 0)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < cl.allocated_client_slots; i++)
|
for (i = 0; i < cl.allocated_client_slots; i++)
|
||||||
|
@ -632,9 +632,11 @@ void CL_CalcClientTime(void)
|
||||||
cl.players[i].entertime += cl.servertime;
|
cl.players[i].entertime += cl.servertime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
if (cls.protocol == CP_NETQUAKE || (cls.demoplayback && cls.demoplayback != DPB_MVD && cls.demoplayback != DPB_EZTV))
|
if (cls.protocol == CP_NETQUAKE || (cls.demoplayback && cls.demoplayback != DPB_MVD && cls.demoplayback != DPB_EZTV))
|
||||||
{
|
{
|
||||||
float want;
|
float want;
|
||||||
|
@ -669,6 +671,7 @@ void CL_CalcClientTime(void)
|
||||||
if (cl.time > realtime)
|
if (cl.time > realtime)
|
||||||
cl.time = realtime;
|
cl.time = realtime;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CL_DecodeStateSize(unsigned short solid, int modelindex, vec3_t mins, vec3_t maxs)
|
static void CL_DecodeStateSize(unsigned short solid, int modelindex, vec3_t mins, vec3_t maxs)
|
||||||
|
@ -894,7 +897,10 @@ void CL_PredictMovePNum (int seat)
|
||||||
pv->nolocalplayer = !!(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) || (cls.protocol != CP_QUAKEWORLD);
|
pv->nolocalplayer = !!(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) || (cls.protocol != CP_QUAKEWORLD);
|
||||||
|
|
||||||
if (!cl.spectator) //just in case
|
if (!cl.spectator) //just in case
|
||||||
|
{
|
||||||
pv->cam_state = CAM_FREECAM;
|
pv->cam_state = CAM_FREECAM;
|
||||||
|
pv->cam_spec_track = -1;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef Q2CLIENT
|
#ifdef Q2CLIENT
|
||||||
if (cls.protocol == CP_QUAKE2)
|
if (cls.protocol == CP_QUAKE2)
|
||||||
|
|
|
@ -159,7 +159,7 @@ typedef struct player_info_s
|
||||||
// scoreboard information
|
// scoreboard information
|
||||||
char name[MAX_SCOREBOARDNAME];
|
char name[MAX_SCOREBOARDNAME];
|
||||||
char team[MAX_INFO_KEY];
|
char team[MAX_INFO_KEY];
|
||||||
float entertime;
|
float realentertime; //pegged against realtime, to cope with potentially not knowing the server's time when we first receive this message
|
||||||
int frags;
|
int frags;
|
||||||
int ping;
|
int ping;
|
||||||
qbyte pl;
|
qbyte pl;
|
||||||
|
@ -826,7 +826,7 @@ typedef struct
|
||||||
|
|
||||||
double matchgametimestart;
|
double matchgametimestart;
|
||||||
enum {
|
enum {
|
||||||
MATCH_DONTKNOW,
|
MATCH_DONTKNOW, //assumed to be in progress.
|
||||||
MATCH_COUNTDOWN,
|
MATCH_COUNTDOWN,
|
||||||
MATCH_STANDBY,
|
MATCH_STANDBY,
|
||||||
MATCH_INPROGRESS
|
MATCH_INPROGRESS
|
||||||
|
|
|
@ -419,7 +419,7 @@ int Con_ExecuteLine(console_t *con, char *line)
|
||||||
waschat = true;
|
waschat = true;
|
||||||
if (keydown[K_CTRL])
|
if (keydown[K_CTRL])
|
||||||
Cbuf_AddText ("say_team ", RESTRICT_LOCAL);
|
Cbuf_AddText ("say_team ", RESTRICT_LOCAL);
|
||||||
else if (keydown[K_SHIFT])
|
else if (keydown[K_SHIFT] || *line == ' ')
|
||||||
Cbuf_AddText ("say ", RESTRICT_LOCAL);
|
Cbuf_AddText ("say ", RESTRICT_LOCAL);
|
||||||
else
|
else
|
||||||
waschat = false;
|
waschat = false;
|
||||||
|
|
|
@ -2581,6 +2581,7 @@ typedef struct
|
||||||
MV_BONES,
|
MV_BONES,
|
||||||
MV_SHADER
|
MV_SHADER
|
||||||
} mode;
|
} mode;
|
||||||
|
int surfaceidx;
|
||||||
int skingroup;
|
int skingroup;
|
||||||
int framegroup;
|
int framegroup;
|
||||||
double framechangetime;
|
double framechangetime;
|
||||||
|
@ -2619,9 +2620,7 @@ static unsigned int genhsv(float h_, float s, float v)
|
||||||
((int)(r*255)<<16) |
|
((int)(r*255)<<16) |
|
||||||
((int)(g*255)<<8) |
|
((int)(g*255)<<8) |
|
||||||
((int)(b*255)<<0);
|
((int)(b*255)<<0);
|
||||||
};
|
}
|
||||||
const char *Mod_FrameNameForNum(model_t *model, int num);
|
|
||||||
const char *Mod_SkinNameForNum(model_t *model, int num);
|
|
||||||
|
|
||||||
#include "com_mesh.h"
|
#include "com_mesh.h"
|
||||||
#ifdef SKELETALMODELS
|
#ifdef SKELETALMODELS
|
||||||
|
@ -2650,6 +2649,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_
|
||||||
entity_t ent;
|
entity_t ent;
|
||||||
vec3_t fwd, rgt, up;
|
vec3_t fwd, rgt, up;
|
||||||
const char *fname;
|
const char *fname;
|
||||||
|
shader_t *shader;
|
||||||
vec2_t fs = {8,8};
|
vec2_t fs = {8,8};
|
||||||
|
|
||||||
modelview_t *mods = c->dptr;
|
modelview_t *mods = c->dptr;
|
||||||
|
@ -2713,15 +2713,27 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_
|
||||||
|
|
||||||
y = 0;
|
y = 0;
|
||||||
|
|
||||||
fname = Mod_FrameNameForNum(ent.model, mods->framegroup);
|
fname = Mod_SurfaceNameForNum(ent.model, mods->surfaceidx);
|
||||||
if (!fname)
|
if (!fname)
|
||||||
fname = "Unknown Frame";
|
fname = "Unknown Surface";
|
||||||
Draw_FunString(0, y, va("%i: %s", mods->framegroup, fname));
|
Draw_FunString(0, y, va("Surf %i: %s", mods->surfaceidx, fname));
|
||||||
y+=8;
|
y+=8;
|
||||||
fname = Mod_SkinNameForNum(ent.model, mods->skingroup);
|
|
||||||
|
{
|
||||||
|
char *fname;
|
||||||
|
int numframes = 0;
|
||||||
|
float duration = 0;
|
||||||
|
qboolean loop = false;
|
||||||
|
if (!Mod_FrameInfoForNum(ent.model, mods->surfaceidx, mods->framegroup, &fname, &numframes, &duration, &loop))
|
||||||
|
fname = "Unknown Frame";
|
||||||
|
Draw_FunString(0, y, va("Frame%i: %s (%i poses, %f secs, %s)", mods->framegroup, fname, numframes, duration, loop?"looped":"unlooped"));
|
||||||
|
y+=8;
|
||||||
|
}
|
||||||
|
fname = Mod_SkinNameForNum(ent.model, mods->surfaceidx, mods->skingroup);
|
||||||
if (!fname)
|
if (!fname)
|
||||||
fname = "Unknown Skin";
|
fname = "Unknown Skin";
|
||||||
Draw_FunString(0, y, va("%i: %s", mods->skingroup, fname));
|
shader = Mod_ShaderForSkin(ent.model, mods->surfaceidx, mods->skingroup);
|
||||||
|
Draw_FunString(0, y, va("Skin %i: (%s) %s", mods->skingroup, fname, shader?shader->name:"NO SHADER"));
|
||||||
y+=8;
|
y+=8;
|
||||||
|
|
||||||
switch(mods->mode)
|
switch(mods->mode)
|
||||||
|
@ -2759,7 +2771,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_
|
||||||
{
|
{
|
||||||
if (!mods->shadertext)
|
if (!mods->shadertext)
|
||||||
{
|
{
|
||||||
char *body = Shader_GetShaderBody(Mod_ShaderForSkin(ent.model, mods->skingroup));
|
char *body = Shader_GetShaderBody(Mod_ShaderForSkin(ent.model, mods->surfaceidx, mods->skingroup));
|
||||||
mods->shadertext = Z_StrDup(body);
|
mods->shadertext = Z_StrDup(body);
|
||||||
}
|
}
|
||||||
R_DrawTextField(r_refdef.grect.x, r_refdef.grect.y+16, r_refdef.grect.width, r_refdef.grect.height-16, mods->shadertext, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, fs);
|
R_DrawTextField(r_refdef.grect.x, r_refdef.grect.y+16, r_refdef.grect.width, r_refdef.grect.height-16, mods->shadertext, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, fs);
|
||||||
|
@ -2814,17 +2826,33 @@ static qboolean M_ModelViewerKey(struct menucustom_s *c, struct menu_s *m, int k
|
||||||
{
|
{
|
||||||
mods->skingroup += 1;
|
mods->skingroup += 1;
|
||||||
mods->skinchangetime = realtime;
|
mods->skinchangetime = realtime;
|
||||||
|
Z_Free(mods->shadertext);
|
||||||
|
mods->shadertext = NULL;
|
||||||
}
|
}
|
||||||
else if (key == K_PGDN)
|
else if (key == K_PGDN)
|
||||||
{
|
{
|
||||||
mods->framegroup = max(0, mods->framegroup-1);
|
mods->framegroup = max(0, mods->framegroup-1);
|
||||||
mods->framechangetime = realtime;
|
mods->framechangetime = realtime;
|
||||||
|
Z_Free(mods->shadertext);
|
||||||
|
mods->shadertext = NULL;
|
||||||
}
|
}
|
||||||
else if (key == K_PGUP)
|
else if (key == K_PGUP)
|
||||||
{
|
{
|
||||||
mods->framegroup += 1;
|
mods->framegroup += 1;
|
||||||
mods->framechangetime = realtime;
|
mods->framechangetime = realtime;
|
||||||
}
|
}
|
||||||
|
else if (key == K_INS)
|
||||||
|
{
|
||||||
|
mods->surfaceidx = max(0, mods->surfaceidx-1);
|
||||||
|
Z_Free(mods->shadertext);
|
||||||
|
mods->shadertext = NULL;
|
||||||
|
}
|
||||||
|
else if (key == K_DEL)
|
||||||
|
{
|
||||||
|
mods->surfaceidx += 1;
|
||||||
|
Z_Free(mods->shadertext);
|
||||||
|
mods->shadertext = NULL;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -147,9 +147,9 @@ extern const char *Mod_FixName (const char *modname, const char *worldname);
|
||||||
char *Mod_ParseWorldspawnKey (const char *ents, const char *key, char *buffer, size_t sizeofbuffer);
|
char *Mod_ParseWorldspawnKey (const char *ents, const char *key, char *buffer, size_t sizeofbuffer);
|
||||||
|
|
||||||
extern void Mod_Think (void);
|
extern void Mod_Think (void);
|
||||||
extern int Mod_SkinNumForName (struct model_s *model, const char *name);
|
extern int Mod_SkinNumForName (struct model_s *model, int surfaceidx, const char *name);
|
||||||
extern int Mod_FrameNumForName (struct model_s *model, const char *name);
|
extern int Mod_FrameNumForName (struct model_s *model, int surfaceidx, const char *name);
|
||||||
extern float Mod_GetFrameDuration (struct model_s *model, int framenum);
|
extern float Mod_GetFrameDuration (struct model_s *model, int surfaceidx, int framenum);
|
||||||
|
|
||||||
#undef FNC
|
#undef FNC
|
||||||
|
|
||||||
|
|
|
@ -3090,11 +3090,16 @@ static void QCBUILTIN PF_cs_getplayerkey (pubprogfuncs_t *prinst, struct globalv
|
||||||
ret = buffer;
|
ret = buffer;
|
||||||
sprintf(ret, "%i", cl.players[pnum].pl);
|
sprintf(ret, "%i", cl.players[pnum].pl);
|
||||||
}
|
}
|
||||||
else if (!strcmp(keyname, "entertime")) //packet loss
|
else if (!strcmp(keyname, "activetime")) //packet loss
|
||||||
{
|
{
|
||||||
ret = buffer;
|
ret = buffer;
|
||||||
sprintf(ret, "%i", (int)cl.players[pnum].entertime);
|
sprintf(ret, "%f", realtime - cl.players[pnum].realentertime);
|
||||||
}
|
}
|
||||||
|
// else if (!strcmp(keyname, "entertime")) //packet loss
|
||||||
|
// {
|
||||||
|
// ret = buffer;
|
||||||
|
// sprintf(ret, "%i", (int)cl.players[pnum].entertime);
|
||||||
|
// }
|
||||||
else if (!strcmp(keyname, "topcolor_rgb")) //packet loss
|
else if (!strcmp(keyname, "topcolor_rgb")) //packet loss
|
||||||
{
|
{
|
||||||
unsigned int col = cl.players[pnum].ttopcolor;
|
unsigned int col = cl.players[pnum].ttopcolor;
|
||||||
|
|
|
@ -35,9 +35,6 @@ qc must build the skeletal object still, which fills the skeletal object from th
|
||||||
|
|
||||||
#include "quakedef.h"
|
#include "quakedef.h"
|
||||||
|
|
||||||
qboolean Mod_FrameInfoForNum(model_t *model, int num, char **name, int *numframes, float *duration, qboolean *loop);
|
|
||||||
const char *Mod_SkinNameForNum(model_t *model, int num);
|
|
||||||
|
|
||||||
#if defined(RAGDOLL) || defined(SKELETALOBJECTS)
|
#if defined(RAGDOLL) || defined(SKELETALOBJECTS)
|
||||||
|
|
||||||
#include "pr_common.h"
|
#include "pr_common.h"
|
||||||
|
@ -870,7 +867,7 @@ void skel_generateragdoll_f(void)
|
||||||
int numframes;
|
int numframes;
|
||||||
float duration;
|
float duration;
|
||||||
qboolean loop;
|
qboolean loop;
|
||||||
if (!Mod_FrameInfoForNum(mod, i, &fname, &numframes, &duration, &loop))
|
if (!Mod_FrameInfoForNum(mod, 0, i, &fname, &numframes, &duration, &loop))
|
||||||
break;
|
break;
|
||||||
VFS_PUTS(f, va("//%i %s (%i frames) (%f secs)%s", i, fname, numframes, duration, loop?" (loop)":""));
|
VFS_PUTS(f, va("//%i %s (%i frames) (%f secs)%s", i, fname, numframes, duration, loop?" (loop)":""));
|
||||||
}
|
}
|
||||||
|
@ -882,7 +879,7 @@ void skel_generateragdoll_f(void)
|
||||||
for (i = 0; i < 32768; i++)
|
for (i = 0; i < 32768; i++)
|
||||||
{
|
{
|
||||||
const char *sname;
|
const char *sname;
|
||||||
sname = Mod_SkinNameForNum(mod, i);
|
sname = Mod_SkinNameForNum(mod, 0, i);
|
||||||
if (!sname)
|
if (!sname)
|
||||||
break;
|
break;
|
||||||
VFS_PUTS(f, va("//%i %s", i, sname));
|
VFS_PUTS(f, va("//%i %s", i, sname));
|
||||||
|
@ -2193,17 +2190,15 @@ void QCBUILTIN PF_gettagindex (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
|
||||||
G_FLOAT(OFS_RETURN) = 0;
|
G_FLOAT(OFS_RETURN) = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *Mod_FrameNameForNum(model_t *model, int num);
|
|
||||||
const char *Mod_SkinNameForNum(model_t *model, int num);
|
|
||||||
|
|
||||||
//string(float modidx, float framenum) frametoname
|
//string(float modidx, float framenum) frametoname
|
||||||
void QCBUILTIN PF_frametoname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
void QCBUILTIN PF_frametoname (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||||
{
|
{
|
||||||
world_t *w = prinst->parms->user;
|
world_t *w = prinst->parms->user;
|
||||||
unsigned int modelindex = G_FLOAT(OFS_PARM0);
|
unsigned int modelindex = G_FLOAT(OFS_PARM0);
|
||||||
unsigned int skinnum = G_FLOAT(OFS_PARM1);
|
unsigned int skinnum = G_FLOAT(OFS_PARM1);
|
||||||
|
int surfaceidx = 0;
|
||||||
model_t *mod = w->Get_CModel(w, modelindex);
|
model_t *mod = w->Get_CModel(w, modelindex);
|
||||||
const char *n = Mod_FrameNameForNum(mod, skinnum);
|
const char *n = Mod_FrameNameForNum(mod, surfaceidx, skinnum);
|
||||||
|
|
||||||
if (n)
|
if (n)
|
||||||
RETURN_TSTRING(n);
|
RETURN_TSTRING(n);
|
||||||
|
@ -2215,11 +2210,12 @@ void QCBUILTIN PF_frameforname (pubprogfuncs_t *prinst, struct globalvars_s *pr_
|
||||||
{
|
{
|
||||||
world_t *w = prinst->parms->user;
|
world_t *w = prinst->parms->user;
|
||||||
unsigned int modelindex = G_FLOAT(OFS_PARM0);
|
unsigned int modelindex = G_FLOAT(OFS_PARM0);
|
||||||
|
int surfaceidx = 0;
|
||||||
char *str = PF_VarString(prinst, 1, pr_globals);
|
char *str = PF_VarString(prinst, 1, pr_globals);
|
||||||
model_t *mod = w->Get_CModel(w, modelindex);
|
model_t *mod = w->Get_CModel(w, modelindex);
|
||||||
|
|
||||||
if (mod)
|
if (mod)
|
||||||
G_FLOAT(OFS_RETURN) = Mod_FrameNumForName(mod, str);
|
G_FLOAT(OFS_RETURN) = Mod_FrameNumForName(mod, surfaceidx, str);
|
||||||
else
|
else
|
||||||
G_FLOAT(OFS_RETURN) = -1;
|
G_FLOAT(OFS_RETURN) = -1;
|
||||||
}
|
}
|
||||||
|
@ -2228,10 +2224,11 @@ void QCBUILTIN PF_frameduration (pubprogfuncs_t *prinst, struct globalvars_s *pr
|
||||||
world_t *w = prinst->parms->user;
|
world_t *w = prinst->parms->user;
|
||||||
unsigned int modelindex = G_FLOAT(OFS_PARM0);
|
unsigned int modelindex = G_FLOAT(OFS_PARM0);
|
||||||
unsigned int framenum = G_FLOAT(OFS_PARM1);
|
unsigned int framenum = G_FLOAT(OFS_PARM1);
|
||||||
|
int surfaceidx = 0;
|
||||||
model_t *mod = w->Get_CModel(w, modelindex);
|
model_t *mod = w->Get_CModel(w, modelindex);
|
||||||
|
|
||||||
if (mod)
|
if (mod)
|
||||||
G_FLOAT(OFS_RETURN) = Mod_GetFrameDuration(mod, framenum);
|
G_FLOAT(OFS_RETURN) = Mod_GetFrameDuration(mod, surfaceidx, framenum);
|
||||||
else
|
else
|
||||||
G_FLOAT(OFS_RETURN) = 0;
|
G_FLOAT(OFS_RETURN) = 0;
|
||||||
}
|
}
|
||||||
|
@ -2242,8 +2239,9 @@ void QCBUILTIN PF_skintoname (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
|
||||||
world_t *w = prinst->parms->user;
|
world_t *w = prinst->parms->user;
|
||||||
unsigned int modelindex = G_FLOAT(OFS_PARM0);
|
unsigned int modelindex = G_FLOAT(OFS_PARM0);
|
||||||
unsigned int skinnum = G_FLOAT(OFS_PARM1);
|
unsigned int skinnum = G_FLOAT(OFS_PARM1);
|
||||||
|
int surfaceidx = 0;
|
||||||
model_t *mod = w->Get_CModel(w, modelindex);
|
model_t *mod = w->Get_CModel(w, modelindex);
|
||||||
const char *n = Mod_SkinNameForNum(mod, skinnum);
|
const char *n = Mod_SkinNameForNum(mod, surfaceidx, skinnum);
|
||||||
|
|
||||||
if (n)
|
if (n)
|
||||||
RETURN_TSTRING(n);
|
RETURN_TSTRING(n);
|
||||||
|
@ -2256,10 +2254,11 @@ void QCBUILTIN PF_skinforname (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
|
||||||
world_t *w = prinst->parms->user;
|
world_t *w = prinst->parms->user;
|
||||||
unsigned int modelindex = G_FLOAT(OFS_PARM0);
|
unsigned int modelindex = G_FLOAT(OFS_PARM0);
|
||||||
char *str = PF_VarString(prinst, 1, pr_globals);
|
char *str = PF_VarString(prinst, 1, pr_globals);
|
||||||
|
int surfaceidx = 0;
|
||||||
model_t *mod = w->Get_CModel(w, modelindex);
|
model_t *mod = w->Get_CModel(w, modelindex);
|
||||||
|
|
||||||
if (mod)
|
if (mod)
|
||||||
G_FLOAT(OFS_RETURN) = Mod_SkinNumForName(mod, str);
|
G_FLOAT(OFS_RETURN) = Mod_SkinNumForName(mod, surfaceidx, str);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
G_FLOAT(OFS_RETURN) = -1;
|
G_FLOAT(OFS_RETURN) = -1;
|
||||||
|
|
|
@ -432,9 +432,9 @@ skinfile_t *Mod_LookupSkin(skinid_t id);
|
||||||
void Mod_Init (qboolean initial);
|
void Mod_Init (qboolean initial);
|
||||||
void Mod_Shutdown (qboolean final);
|
void Mod_Shutdown (qboolean final);
|
||||||
int Mod_TagNumForName(struct model_s *model, const char *name);
|
int Mod_TagNumForName(struct model_s *model, const char *name);
|
||||||
int Mod_SkinNumForName(struct model_s *model, const char *name);
|
int Mod_SkinNumForName(struct model_s *model, int surfaceidx, const char *name);
|
||||||
int Mod_FrameNumForName(struct model_s *model, const char *name);
|
int Mod_FrameNumForName(struct model_s *model, int surfaceidx, const char *name);
|
||||||
float Mod_GetFrameDuration(struct model_s *model, int frameno);
|
float Mod_GetFrameDuration(struct model_s *model, int surfaceidx, int frameno);
|
||||||
|
|
||||||
void Mod_ResortShaders(void);
|
void Mod_ResortShaders(void);
|
||||||
void Mod_ClearAll (void);
|
void Mod_ClearAll (void);
|
||||||
|
|
|
@ -3113,10 +3113,7 @@ ping time frags name
|
||||||
})
|
})
|
||||||
#define COLUMN_TIME COLUMN(time, 4*8, \
|
#define COLUMN_TIME COLUMN(time, 4*8, \
|
||||||
{ \
|
{ \
|
||||||
if (cl.intermission) \
|
total = realtime - s->realentertime; \
|
||||||
total = cl.completed_time - s->entertime; \
|
|
||||||
else \
|
|
||||||
total = cl.servertime - s->entertime; \
|
|
||||||
minutes = (int)total/60; \
|
minutes = (int)total/60; \
|
||||||
sprintf (num, "%4i", minutes); \
|
sprintf (num, "%4i", minutes); \
|
||||||
Draw_FunStringWidth(x, y, num, 4*8, false, false); \
|
Draw_FunStringWidth(x, y, num, 4*8, false, false); \
|
||||||
|
|
|
@ -4169,7 +4169,7 @@ int Mod_TagNumForName(model_t *model, const char *name)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Mod_FrameNumForName(model_t *model, const char *name)
|
int Mod_FrameNumForName(model_t *model, int surfaceidx, const char *name)
|
||||||
{
|
{
|
||||||
galiasanimation_t *group;
|
galiasanimation_t *group;
|
||||||
galiasinfo_t *inf;
|
galiasinfo_t *inf;
|
||||||
|
@ -4186,17 +4186,22 @@ int Mod_FrameNumForName(model_t *model, const char *name)
|
||||||
|
|
||||||
inf = Mod_Extradata(model);
|
inf = Mod_Extradata(model);
|
||||||
|
|
||||||
|
while(surfaceidx-->0 && inf)
|
||||||
|
inf = inf->nextsurf;
|
||||||
|
if (inf)
|
||||||
|
{
|
||||||
group = inf->ofsanimations;
|
group = inf->ofsanimations;
|
||||||
for (i = 0; i < inf->numanimations; i++, group++)
|
for (i = 0; i < inf->numanimations; i++, group++)
|
||||||
{
|
{
|
||||||
if (!strcmp(group->name, name))
|
if (!strcmp(group->name, name))
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SERVERONLY
|
#ifndef SERVERONLY
|
||||||
int Mod_SkinNumForName(model_t *model, const char *name)
|
int Mod_SkinNumForName(model_t *model, int surfaceidx, const char *name)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
galiasinfo_t *inf;
|
galiasinfo_t *inf;
|
||||||
|
@ -4206,18 +4211,22 @@ int Mod_SkinNumForName(model_t *model, const char *name)
|
||||||
return -1;
|
return -1;
|
||||||
inf = Mod_Extradata(model);
|
inf = Mod_Extradata(model);
|
||||||
|
|
||||||
|
while(surfaceidx-->0 && inf)
|
||||||
|
inf = inf->nextsurf;
|
||||||
|
if (inf)
|
||||||
|
{
|
||||||
skin = inf->ofsskins;
|
skin = inf->ofsskins;
|
||||||
for (i = 0; i < inf->numskins; i++, skin++)
|
for (i = 0; i < inf->numskins; i++, skin++)
|
||||||
{
|
{
|
||||||
if (!strcmp(skin->name, name))
|
if (!strcmp(skin->name, name))
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const char *Mod_FrameNameForNum(model_t *model, int num)
|
const char *Mod_FrameNameForNum(model_t *model, int surfaceidx, int num)
|
||||||
{
|
{
|
||||||
galiasanimation_t *group;
|
galiasanimation_t *group;
|
||||||
galiasinfo_t *inf;
|
galiasinfo_t *inf;
|
||||||
|
@ -4229,13 +4238,16 @@ const char *Mod_FrameNameForNum(model_t *model, int num)
|
||||||
|
|
||||||
inf = Mod_Extradata(model);
|
inf = Mod_Extradata(model);
|
||||||
|
|
||||||
if (num >= inf->numanimations)
|
while(surfaceidx-->0 && inf)
|
||||||
|
inf = inf->nextsurf;
|
||||||
|
|
||||||
|
if (!inf || num >= inf->numanimations)
|
||||||
return NULL;
|
return NULL;
|
||||||
group = inf->ofsanimations;
|
group = inf->ofsanimations;
|
||||||
return group[num].name;
|
return group[num].name;
|
||||||
}
|
}
|
||||||
|
|
||||||
qboolean Mod_FrameInfoForNum(model_t *model, int num, char **name, int *numframes, float *duration, qboolean *loop)
|
qboolean Mod_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **name, int *numframes, float *duration, qboolean *loop)
|
||||||
{
|
{
|
||||||
galiasanimation_t *group;
|
galiasanimation_t *group;
|
||||||
galiasinfo_t *inf;
|
galiasinfo_t *inf;
|
||||||
|
@ -4247,7 +4259,10 @@ qboolean Mod_FrameInfoForNum(model_t *model, int num, char **name, int *numframe
|
||||||
|
|
||||||
inf = Mod_Extradata(model);
|
inf = Mod_Extradata(model);
|
||||||
|
|
||||||
if (num >= inf->numanimations)
|
while(surfaceidx-->0 && inf)
|
||||||
|
inf = inf->nextsurf;
|
||||||
|
|
||||||
|
if (!inf || num >= inf->numanimations)
|
||||||
return false;
|
return false;
|
||||||
group = inf->ofsanimations;
|
group = inf->ofsanimations;
|
||||||
|
|
||||||
|
@ -4259,7 +4274,7 @@ qboolean Mod_FrameInfoForNum(model_t *model, int num, char **name, int *numframe
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SERVERONLY
|
#ifndef SERVERONLY
|
||||||
shader_t *Mod_ShaderForSkin(model_t *model, int num)
|
shader_t *Mod_ShaderForSkin(model_t *model, int surfaceidx, int num)
|
||||||
{
|
{
|
||||||
galiasinfo_t *inf;
|
galiasinfo_t *inf;
|
||||||
galiasskin_t *skin;
|
galiasskin_t *skin;
|
||||||
|
@ -4268,13 +4283,16 @@ shader_t *Mod_ShaderForSkin(model_t *model, int num)
|
||||||
return NULL;
|
return NULL;
|
||||||
inf = Mod_Extradata(model);
|
inf = Mod_Extradata(model);
|
||||||
|
|
||||||
if (num >= inf->numskins)
|
while(surfaceidx-->0 && inf)
|
||||||
|
inf = inf->nextsurf;
|
||||||
|
|
||||||
|
if (!inf || num >= inf->numskins)
|
||||||
return NULL;
|
return NULL;
|
||||||
skin = inf->ofsskins;
|
skin = inf->ofsskins;
|
||||||
return skin[num].frame[0].shader;
|
return skin[num].frame[0].shader;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
const char *Mod_SkinNameForNum(model_t *model, int num)
|
const char *Mod_SkinNameForNum(model_t *model, int surfaceidx, int num)
|
||||||
{
|
{
|
||||||
#ifdef SERVERONLY
|
#ifdef SERVERONLY
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -4286,17 +4304,39 @@ const char *Mod_SkinNameForNum(model_t *model, int num)
|
||||||
return NULL;
|
return NULL;
|
||||||
inf = Mod_Extradata(model);
|
inf = Mod_Extradata(model);
|
||||||
|
|
||||||
if (num >= inf->numskins)
|
while(surfaceidx-->0 && inf)
|
||||||
|
inf = inf->nextsurf;
|
||||||
|
if (!inf || num >= inf->numskins)
|
||||||
return NULL;
|
return NULL;
|
||||||
skin = inf->ofsskins;
|
skin = inf->ofsskins;
|
||||||
if (!*skin[num].name)
|
// if (!*skin[num].name)
|
||||||
return skin[num].frame[0].shadername;
|
// return skin[num].frame[0].shadername;
|
||||||
else
|
// else
|
||||||
return skin[num].name;
|
return skin[num].name;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
float Mod_GetFrameDuration(model_t *model, int frameno)
|
const char *Mod_SurfaceNameForNum(model_t *model, int num)
|
||||||
|
{
|
||||||
|
#ifdef SERVERONLY
|
||||||
|
return NULL;
|
||||||
|
#else
|
||||||
|
galiasinfo_t *inf;
|
||||||
|
|
||||||
|
if (!model || model->type != mod_alias)
|
||||||
|
return NULL;
|
||||||
|
inf = Mod_Extradata(model);
|
||||||
|
|
||||||
|
while(num-->0 && inf)
|
||||||
|
inf = inf->nextsurf;
|
||||||
|
if (inf)
|
||||||
|
return inf->surfacename;
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
float Mod_GetFrameDuration(model_t *model, int surfaceidx, int frameno)
|
||||||
{
|
{
|
||||||
galiasinfo_t *inf;
|
galiasinfo_t *inf;
|
||||||
galiasanimation_t *group;
|
galiasanimation_t *group;
|
||||||
|
@ -4305,11 +4345,19 @@ float Mod_GetFrameDuration(model_t *model, int frameno)
|
||||||
return 0;
|
return 0;
|
||||||
inf = Mod_Extradata(model);
|
inf = Mod_Extradata(model);
|
||||||
|
|
||||||
|
while(surfaceidx-->0 && inf)
|
||||||
|
inf = inf->nextsurf;
|
||||||
|
|
||||||
|
if (inf)
|
||||||
|
{
|
||||||
group = inf->ofsanimations;
|
group = inf->ofsanimations;
|
||||||
if (frameno < 0 || frameno >= inf->numanimations)
|
if (frameno >= 0 && frameno < inf->numanimations)
|
||||||
return 0;
|
{
|
||||||
group += frameno;
|
group += frameno;
|
||||||
return group->numposes/group->rate;
|
return group->numposes/group->rate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -6476,6 +6524,7 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, char *buffer, size_t fsize)
|
||||||
skin++;
|
skin++;
|
||||||
|
|
||||||
Q_strncpyz(skinframe[j].shadername, strings+mesh[i].material, sizeof(skinframe[j].shadername));
|
Q_strncpyz(skinframe[j].shadername, strings+mesh[i].material, sizeof(skinframe[j].shadername));
|
||||||
|
skinframe++;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -209,8 +209,12 @@ void Mod_DestroyMesh(galiasinfo_t *galias);
|
||||||
void Alias_FlushCache(void);
|
void Alias_FlushCache(void);
|
||||||
void Alias_Shutdown(void);
|
void Alias_Shutdown(void);
|
||||||
void Alias_Register(void);
|
void Alias_Register(void);
|
||||||
shader_t *Mod_ShaderForSkin(model_t *model, int num);
|
shader_t *Mod_ShaderForSkin(model_t *model, int surfaceidx, int num);
|
||||||
const char *Mod_SkinNameForNum(model_t *model, int num);
|
const char *Mod_SkinNameForNum(model_t *model, int surfaceidx, int num);
|
||||||
|
const char *Mod_SurfaceNameForNum(model_t *model, int num);
|
||||||
|
const char *Mod_FrameNameForNum(model_t *model, int surfaceidx, int num);
|
||||||
|
const char *Mod_SkinNameForNum(model_t *model, int surfaceidx, int num);
|
||||||
|
qboolean Mod_FrameInfoForNum(model_t *model, int surfaceidx, int num, char **name, int *numframes, float *duration, qboolean *loop);
|
||||||
|
|
||||||
void Mod_DoCRC(model_t *mod, char *buffer, int buffersize);
|
void Mod_DoCRC(model_t *mod, char *buffer, int buffersize);
|
||||||
|
|
||||||
|
|
|
@ -1226,6 +1226,7 @@ qboolean Cvar_Command (int level)
|
||||||
char *str;
|
char *str;
|
||||||
char buffer[65536];
|
char buffer[65536];
|
||||||
int olev;
|
int olev;
|
||||||
|
int seat;
|
||||||
|
|
||||||
// check variables
|
// check variables
|
||||||
v = Cvar_FindVar (Cmd_Argv(0));
|
v = Cvar_FindVar (Cmd_Argv(0));
|
||||||
|
@ -1243,6 +1244,7 @@ qboolean Cvar_Command (int level)
|
||||||
Con_Printf ("Server tried setting %s cvar\n", v->name);
|
Con_Printf ("Server tried setting %s cvar\n", v->name);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// perform a variable print or set
|
// perform a variable print or set
|
||||||
if (Cmd_Argc() == 1)
|
if (Cmd_Argc() == 1)
|
||||||
{
|
{
|
||||||
|
@ -1291,10 +1293,21 @@ qboolean Cvar_Command (int level)
|
||||||
Con_Printf ("Cvar %s may not be set via the console\n", v->name);
|
Con_Printf ("Cvar %s may not be set via the console\n", v->name);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SERVERONLY
|
#ifndef SERVERONLY
|
||||||
if (level > RESTRICT_SERVER)
|
seat = CL_TargettedSplit(true);
|
||||||
{ //directed at a secondary player.
|
if (v->flags & CVAR_USERINFO)
|
||||||
CL_SendClientCommand(true, "%i setinfo %s %s", level - RESTRICT_SERVER-1, v->name, COM_QuotedString(str, buffer, sizeof(buffer), false));
|
{
|
||||||
|
if (Cmd_FromGamecode() && cls.protocol == CP_QUAKEWORLD)
|
||||||
|
{ //don't bother even changing the cvar locally, just update the server's version.
|
||||||
|
//fixme: quake2/quake3 latching.
|
||||||
|
if (seat)
|
||||||
|
CL_SendClientCommand(true, "%i setinfo %s \"%s\"", seat+1, v->name, str);
|
||||||
|
else
|
||||||
|
CL_SendClientCommand(true, "setinfo %s \"%s\"", v->name, str);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
CL_SetInfo(seat, v->name, str);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ struct wedict_s
|
||||||
/*the above is shared with qclib*/
|
/*the above is shared with qclib*/
|
||||||
link_t area;
|
link_t area;
|
||||||
pvscache_t pvsinfo;
|
pvscache_t pvsinfo;
|
||||||
|
int lastruntime;
|
||||||
|
|
||||||
#ifdef USERBE
|
#ifdef USERBE
|
||||||
entityode_t ode;
|
entityode_t ode;
|
||||||
|
|
|
@ -6008,7 +6008,10 @@ QCC_ref_t *QCC_PR_ParseRefArrayPointer (QCC_ref_t *retbuf, QCC_ref_t *r, pbool a
|
||||||
char *tname;
|
char *tname;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
if (!idx.cast && t->type == ev_pointer && !arraysize)
|
if (!idx.cast && t->type == ev_pointer && !arraysize)
|
||||||
|
{
|
||||||
t = t->aux_type;
|
t = t->aux_type;
|
||||||
|
dereference = true;
|
||||||
|
}
|
||||||
tname = t->name;
|
tname = t->name;
|
||||||
|
|
||||||
if (t->type == ev_struct || t->type == ev_union)
|
if (t->type == ev_struct || t->type == ev_union)
|
||||||
|
@ -10072,6 +10075,10 @@ pbool QCC_CheckUninitialised(int firststatement, int laststatement)
|
||||||
QCC_type_t *type = pr_scope->type;
|
QCC_type_t *type = pr_scope->type;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
//assume all, because we don't care for optimisations once we know we're not going to compile anything (removes warning about uninitialised unknown variables/typos).
|
||||||
|
if (pr_error_count)
|
||||||
|
return true;
|
||||||
|
|
||||||
for (i = 0; i < type->num_parms; i++)
|
for (i = 0; i < type->num_parms; i++)
|
||||||
{
|
{
|
||||||
paramend += type->params[i].type->size;
|
paramend += type->params[i].type->size;
|
||||||
|
|
|
@ -3512,6 +3512,8 @@ static void QCBUILTIN PF_spawnclient (pubprogfuncs_t *prinst, struct globalvars_
|
||||||
svs.clients[i].datagram.allowoverflow = true;
|
svs.clients[i].datagram.allowoverflow = true;
|
||||||
svs.clients[i].datagram.maxsize = 0;
|
svs.clients[i].datagram.maxsize = 0;
|
||||||
|
|
||||||
|
svs.clients[i].edict = EDICT_NUM(prinst, i+1);
|
||||||
|
|
||||||
SV_SetUpClientEdict (&svs.clients[i], svs.clients[i].edict);
|
SV_SetUpClientEdict (&svs.clients[i], svs.clients[i].edict);
|
||||||
|
|
||||||
RETURN_EDICT(prinst, svs.clients[i].edict);
|
RETURN_EDICT(prinst, svs.clients[i].edict);
|
||||||
|
|
|
@ -1021,6 +1021,7 @@ int SV_ModelIndex (const char *name);
|
||||||
void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg);
|
void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg);
|
||||||
void SVQW_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qboolean force, unsigned int protext);
|
void SVQW_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qboolean force, unsigned int protext);
|
||||||
|
|
||||||
|
client_t *SV_AddSplit(client_t *controller, char *info, int id);
|
||||||
void SV_GetNewSpawnParms(client_t *cl);
|
void SV_GetNewSpawnParms(client_t *cl);
|
||||||
void SV_SaveSpawnparms (void);
|
void SV_SaveSpawnparms (void);
|
||||||
void SV_SaveSpawnparmsClient(client_t *client, float *transferparms); //if transferparms, calls SetTransferParms instead, and does not modify the player.
|
void SV_SaveSpawnparmsClient(client_t *client, float *transferparms); //if transferparms, calls SetTransferParms instead, and does not modify the player.
|
||||||
|
|
|
@ -94,6 +94,8 @@ cvar_t allow_download_configs = CVARD("allow_download_configs", "0", "1 allows
|
||||||
cvar_t allow_download_copyrighted = CVARD("allow_download_copyrighted", "0", "0 blocks download of packages that are considered copyrighted. Specifically, this means packages with a leading 'pak' prefix on the filename.\nIf you take your copyrights seriously, you should also set allow_download_pakmaps 0 and allow_download_pakcontents 0.");
|
cvar_t allow_download_copyrighted = CVARD("allow_download_copyrighted", "0", "0 blocks download of packages that are considered copyrighted. Specifically, this means packages with a leading 'pak' prefix on the filename.\nIf you take your copyrights seriously, you should also set allow_download_pakmaps 0 and allow_download_pakcontents 0.");
|
||||||
cvar_t allow_download_other = CVARD("allow_download_other", "0", "0 blocks downloading of any file that was not covered by any of the directory download blocks.");
|
cvar_t allow_download_other = CVARD("allow_download_other", "0", "0 blocks downloading of any file that was not covered by any of the directory download blocks.");
|
||||||
|
|
||||||
|
extern cvar_t sv_allow_splitscreen;
|
||||||
|
|
||||||
cvar_t sv_serverip = CVARD("sv_serverip", "", "Set this cvar to the server's public ip address if the server is behind a firewall and cannot detect its own public address. Providing a port is required if the firewall/nat remaps it, but is otherwise optional.");
|
cvar_t sv_serverip = CVARD("sv_serverip", "", "Set this cvar to the server's public ip address if the server is behind a firewall and cannot detect its own public address. Providing a port is required if the firewall/nat remaps it, but is otherwise optional.");
|
||||||
cvar_t sv_public = CVAR("sv_public", "0");
|
cvar_t sv_public = CVAR("sv_public", "0");
|
||||||
cvar_t sv_listen_qw = CVARAF("sv_listen_qw", "1", "sv_listen", 0);
|
cvar_t sv_listen_qw = CVARAF("sv_listen_qw", "1", "sv_listen", 0);
|
||||||
|
@ -1891,6 +1893,101 @@ void SV_UserDNSResolved(void *ctx, void *data, size_t idx, size_t uid)
|
||||||
Z_Free(data);
|
Z_Free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client_t *SV_AddSplit(client_t *controller, char *info, int id)
|
||||||
|
{
|
||||||
|
client_t *cl, *prev;
|
||||||
|
int i;
|
||||||
|
int curclients;
|
||||||
|
|
||||||
|
if (!(controller->fteprotocolextensions & PEXT_SPLITSCREEN))
|
||||||
|
{
|
||||||
|
SV_PrintToClient(controller, PRINT_HIGH, "Your client doesn't support splitscreen\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (curclients = 0, prev = cl = controller; cl; cl = cl->controlled)
|
||||||
|
{
|
||||||
|
prev = cl;
|
||||||
|
curclients++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id && curclients != id)
|
||||||
|
return NULL; //this would be weird.
|
||||||
|
|
||||||
|
if (curclients >= 16)
|
||||||
|
return NULL; //protocol limit on stats.
|
||||||
|
if (curclients >= MAX_SPLITS)
|
||||||
|
return NULL;
|
||||||
|
//only allow splitscreen if its explicitly allowed. unless its the local client in which case its always allowed.
|
||||||
|
//wouldn't it be awesome if we could always allow it for spectators? the join command makes that awkward, though I suppose we could just drop the extras in that case.
|
||||||
|
if (!sv_allow_splitscreen.ival && controller->netchan.remote_address.type != NA_LOOPBACK)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (i=0,cl=svs.clients ; i<sv.allocated_client_slots ; i++,cl++)
|
||||||
|
{
|
||||||
|
if (cl->state == cs_free)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == sv.allocated_client_slots)
|
||||||
|
{
|
||||||
|
SV_PrintToClient(controller, PRINT_HIGH, "not enough free player slots\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cl->spectator = controller->spectator;
|
||||||
|
cl->netchan.remote_address = controller->netchan.remote_address;
|
||||||
|
cl->zquake_extensions = controller->zquake_extensions;
|
||||||
|
cl->fteprotocolextensions = controller->fteprotocolextensions;
|
||||||
|
cl->fteprotocolextensions2 = controller->fteprotocolextensions2;
|
||||||
|
cl->penalties = controller->penalties;
|
||||||
|
cl->protocol = controller->protocol;
|
||||||
|
|
||||||
|
|
||||||
|
Q_strncatz(cl->guid, va("%s:%i", controller->guid, curclients), sizeof(cl->guid));
|
||||||
|
cl->name = cl->namebuf;
|
||||||
|
cl->team = cl->teambuf;
|
||||||
|
|
||||||
|
nextuserid++; // so every client gets a unique id
|
||||||
|
cl->userid = nextuserid;
|
||||||
|
|
||||||
|
cl->playerclass = 0;
|
||||||
|
cl->pendingentbits = NULL;
|
||||||
|
cl->edict = EDICT_NUM(svprogfuncs, i+1);
|
||||||
|
|
||||||
|
prev->controlled = cl;
|
||||||
|
prev = cl;
|
||||||
|
cl->controller = prev->controller?prev->controller:host_client;
|
||||||
|
cl->controlled = NULL;
|
||||||
|
|
||||||
|
Q_strncpyS (cl->userinfo, info, sizeof(cl->userinfo)-1);
|
||||||
|
cl->userinfo[sizeof(cl->userinfo)-1] = '\0';
|
||||||
|
|
||||||
|
if (controller->spectator)
|
||||||
|
{
|
||||||
|
Info_RemoveKey (cl->userinfo, "spectator");
|
||||||
|
//this is a hint rather than a game breaker should it fail.
|
||||||
|
Info_SetValueForStarKey (cl->userinfo, "*spectator", "1", sizeof(cl->userinfo));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Info_RemoveKey (cl->userinfo, "*spectator");
|
||||||
|
|
||||||
|
SV_ExtractFromUserinfo (cl, true);
|
||||||
|
SV_GetNewSpawnParms(cl);
|
||||||
|
|
||||||
|
cl->state = controller->state;
|
||||||
|
|
||||||
|
if (cl->state >= cs_connected)
|
||||||
|
{
|
||||||
|
cl->sendinfo = true;
|
||||||
|
SV_SetUpClientEdict(cl, cl->edict);
|
||||||
|
}
|
||||||
|
if (cl->state >= cs_spawned)
|
||||||
|
SV_Begin_Core(cl);
|
||||||
|
return cl;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==================
|
==================
|
||||||
SVC_DirectConnect
|
SVC_DirectConnect
|
||||||
|
@ -2806,7 +2903,13 @@ client_t *SVC_DirectConnect(void)
|
||||||
Info_SetValueForStarKey (cl->userinfo, "*spectator", "1", sizeof(cl->userinfo));
|
Info_SetValueForStarKey (cl->userinfo, "*spectator", "1", sizeof(cl->userinfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//only advertise PEXT_SPLITSCREEN when splitscreen is allowed, to avoid spam. this might mean people need to reconnect after its enabled. oh well.
|
||||||
|
if (!sv_allow_splitscreen.ival)
|
||||||
newcl->fteprotocolextensions &= ~PEXT_SPLITSCREEN;
|
newcl->fteprotocolextensions &= ~PEXT_SPLITSCREEN;
|
||||||
|
|
||||||
|
for (clients = 1; clients < numssclients; clients++)
|
||||||
|
SV_AddSplit(newcl, userinfo[clients], clients);
|
||||||
|
#if 0
|
||||||
for (clients = 1; clients < numssclients; clients++)
|
for (clients = 1; clients < numssclients; clients++)
|
||||||
{
|
{
|
||||||
for (i=0,cl=svs.clients ; i<sv.allocated_client_slots ; i++,cl++)
|
for (i=0,cl=svs.clients ; i<sv.allocated_client_slots ; i++,cl++)
|
||||||
|
@ -2819,8 +2922,6 @@ client_t *SVC_DirectConnect(void)
|
||||||
if (i == sv.allocated_client_slots)
|
if (i == sv.allocated_client_slots)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
newcl->fteprotocolextensions |= PEXT_SPLITSCREEN;
|
|
||||||
|
|
||||||
temp.frameunion.frames = cl->frameunion.frames; //don't touch these.
|
temp.frameunion.frames = cl->frameunion.frames; //don't touch these.
|
||||||
temp.edict = cl->edict;
|
temp.edict = cl->edict;
|
||||||
memcpy(cl, newcl, sizeof(client_t));
|
memcpy(cl, newcl, sizeof(client_t));
|
||||||
|
@ -2869,6 +2970,7 @@ client_t *SVC_DirectConnect(void)
|
||||||
|
|
||||||
SV_EvaluatePenalties(cl);
|
SV_EvaluatePenalties(cl);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
newcl->controller = NULL;
|
newcl->controller = NULL;
|
||||||
|
|
||||||
if (!redirect)
|
if (!redirect)
|
||||||
|
|
|
@ -2083,9 +2083,10 @@ void WPhys_RunEntity (world_t *w, wedict_t *ent)
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if ((unsigned int)ent->v->lastruntime == w->framenum)
|
if (ent->lastruntime == w->framenum)
|
||||||
return;
|
return;
|
||||||
ent->v->lastruntime = w->framenum;
|
ent->lastruntime = w->framenum;
|
||||||
|
ent->v->lastruntime = w->physicstime;
|
||||||
#ifndef CLIENTONLY
|
#ifndef CLIENTONLY
|
||||||
svent = NULL;
|
svent = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
@ -2439,7 +2440,7 @@ qboolean SV_Physics (void)
|
||||||
old_bot_time = newbottime;
|
old_bot_time = newbottime;
|
||||||
for (i = 1; i <= sv.allocated_client_slots; i++)
|
for (i = 1; i <= sv.allocated_client_slots; i++)
|
||||||
{
|
{
|
||||||
if (svs.clients[i-1].state && svs.clients[i-1].protocol == SCP_BAD)
|
if (svs.clients[i-1].state > cs_zombie && svs.clients[i-1].protocol == SCP_BAD)
|
||||||
{ //then this is a bot
|
{ //then this is a bot
|
||||||
oldhost = host_client;
|
oldhost = host_client;
|
||||||
oldplayer = sv_player;
|
oldplayer = sv_player;
|
||||||
|
|
|
@ -837,6 +837,9 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (client->penalties & BAN_BLIND)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (pnum >= 0)
|
if (pnum >= 0)
|
||||||
{
|
{
|
||||||
if (pnum != j)
|
if (pnum != j)
|
||||||
|
@ -844,26 +847,26 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
|
||||||
}
|
}
|
||||||
else if (svprogfuncs)
|
else if (svprogfuncs)
|
||||||
{
|
{
|
||||||
if (!((int)client->edict->xv->dimension_see & dimension_mask))
|
client_t *seat = client;
|
||||||
|
for(seat = client; seat; seat = seat->controlled)
|
||||||
|
{
|
||||||
|
if (!((int)seat->edict->xv->dimension_see & dimension_mask))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!mask) //no pvs? broadcast.
|
if (!mask) //no pvs? broadcast.
|
||||||
goto inrange;
|
goto inrange;
|
||||||
|
|
||||||
if (client->penalties & BAN_BLIND)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (to == MULTICAST_PHS_R || to == MULTICAST_PHS)
|
if (to == MULTICAST_PHS_R || to == MULTICAST_PHS)
|
||||||
{
|
{
|
||||||
vec3_t delta;
|
vec3_t delta;
|
||||||
VectorSubtract(origin, client->edict->v->origin, delta);
|
VectorSubtract(origin, seat->edict->v->origin, delta);
|
||||||
if (DotProduct(delta, delta) <= 1024*1024)
|
if (DotProduct(delta, delta) <= 1024*1024)
|
||||||
goto inrange;
|
goto inrange;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
vec3_t pos;
|
vec3_t pos;
|
||||||
VectorAdd(client->edict->v->origin, client->edict->v->view_ofs, pos);
|
VectorAdd(seat->edict->v->origin, seat->edict->v->view_ofs, pos);
|
||||||
cluster = sv.world.worldmodel->funcs.ClusterForPoint (sv.world.worldmodel, pos);
|
cluster = sv.world.worldmodel->funcs.ClusterForPoint (sv.world.worldmodel, pos);
|
||||||
if (cluster>= 0 && !(mask[cluster>>3] & (1<<(cluster&7)) ) )
|
if (cluster>= 0 && !(mask[cluster>>3] & (1<<(cluster&7)) ) )
|
||||||
{
|
{
|
||||||
|
@ -872,6 +875,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inrange:
|
inrange:
|
||||||
switch (client->protocol)
|
switch (client->protocol)
|
||||||
|
|
|
@ -3655,6 +3655,48 @@ void SV_Pause_f (void)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void SV_UpdateSeats(client_t *controller)
|
||||||
|
{
|
||||||
|
client_t *cl, *prev;
|
||||||
|
int curclients;
|
||||||
|
|
||||||
|
for (curclients = 0, cl = controller; cl; cl = cl->controlled)
|
||||||
|
{
|
||||||
|
prev = cl;
|
||||||
|
curclients++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientReliableWrite_Begin(controller, svc_signonnum, 2+curclients);
|
||||||
|
ClientReliableWrite_Byte(controller, curclients);
|
||||||
|
for (curclients = 0, cl = controller; cl; cl = cl->controlled, curclients++)
|
||||||
|
{
|
||||||
|
ClientReliableWrite_Byte(controller, cl - svs.clients);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (curclients = 0, cl = controller; cl; cl = cl->controlled, curclients++)
|
||||||
|
{
|
||||||
|
// send a fixangle over the reliable channel to make sure it gets there
|
||||||
|
// Never send a roll angle, because savegames can catch the server
|
||||||
|
// in a state where it is expecting the client to correct the angle
|
||||||
|
// and it won't happen if the game was just loaded, so you wind up
|
||||||
|
// with a permanent head tilt
|
||||||
|
ClientReliableWrite_Begin(controller, svcfte_choosesplitclient, 2+curclients);
|
||||||
|
ClientReliableWrite_Byte (controller, curclients);
|
||||||
|
ClientReliableWrite_Byte (controller, svc_setangle);
|
||||||
|
if (cl->edict->v->fixangle)
|
||||||
|
{
|
||||||
|
ClientReliableWrite_Angle(controller, cl->edict->v->angles[0]);
|
||||||
|
ClientReliableWrite_Angle(controller, cl->edict->v->angles[1]);
|
||||||
|
ClientReliableWrite_Angle(controller, 0);//cl->edict->v->angles[2]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ClientReliableWrite_Angle(controller, cl->edict->v->v_angle[0]);
|
||||||
|
ClientReliableWrite_Angle(controller, cl->edict->v->v_angle[1]);
|
||||||
|
ClientReliableWrite_Angle(controller, 0);//cl->edict->v->v_angle[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
|
@ -3666,6 +3708,7 @@ The client is going to disconnect, so remove the connection immediately
|
||||||
void SV_Drop_f (void)
|
void SV_Drop_f (void)
|
||||||
{
|
{
|
||||||
extern cvar_t sv_fullredirect;
|
extern cvar_t sv_fullredirect;
|
||||||
|
client_t *prev;
|
||||||
|
|
||||||
SV_EndRedirect ();
|
SV_EndRedirect ();
|
||||||
if (!host_client->drop)
|
if (!host_client->drop)
|
||||||
|
@ -3681,6 +3724,26 @@ void SV_Drop_f (void)
|
||||||
}
|
}
|
||||||
host_client->drop = true;
|
host_client->drop = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//if splitscreen, orphan the dropper
|
||||||
|
if (host_client->controller)
|
||||||
|
{
|
||||||
|
for (prev = host_client->controller; prev; prev = prev->controlled)
|
||||||
|
{
|
||||||
|
if (prev->controlled == host_client)
|
||||||
|
{
|
||||||
|
prev->controlled = host_client->controlled;
|
||||||
|
host_client->netchan.remote_address.type = NA_INVALID; //so the remaining client doesn't get the kick too.
|
||||||
|
host_client->protocol = SCP_BAD; //make it a bit like a bot, so we don't try sending any datagrams/reliables at someone that isn't able to receive anything.
|
||||||
|
|
||||||
|
SV_UpdateSeats(host_client->controller);
|
||||||
|
host_client->controller->joinobservelockeduntil = realtime + 3;
|
||||||
|
host_client->controlled = NULL;
|
||||||
|
host_client->controller = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -4494,6 +4557,78 @@ void SV_SetUpClientEdict (client_t *cl, edict_t *ent)
|
||||||
ent->v->frags = 0;
|
ent->v->frags = 0;
|
||||||
cl->connection_started = realtime;
|
cl->connection_started = realtime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//dynamically add/remove a splitscreen client
|
||||||
|
static void Cmd_AddSeat_f(void)
|
||||||
|
{
|
||||||
|
client_t *cl, *prev;
|
||||||
|
qboolean changed = false;
|
||||||
|
//don't allow an altseat to add. paranoia.
|
||||||
|
if (host_client->controller)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (host_client->state != cs_spawned)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!(host_client->fteprotocolextensions & PEXT_SPLITSCREEN))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Cmd_Argc()>1)
|
||||||
|
{
|
||||||
|
int num = atoi(Cmd_Argv(1));
|
||||||
|
int count;
|
||||||
|
|
||||||
|
if (!num || host_client->joinobservelockeduntil > realtime)
|
||||||
|
return;
|
||||||
|
host_client->joinobservelockeduntil = realtime + 2;
|
||||||
|
|
||||||
|
for (count = 1, prev = host_client, cl = host_client->controlled; cl; cl = cl->controlled)
|
||||||
|
{
|
||||||
|
if (count >= num)
|
||||||
|
{
|
||||||
|
for(; cl; cl = prev->controlled)
|
||||||
|
{
|
||||||
|
//unlink it
|
||||||
|
prev->controlled = cl->controlled;
|
||||||
|
cl->controller = NULL;
|
||||||
|
cl->controlled = NULL;
|
||||||
|
|
||||||
|
//make it into a pseudo-bot
|
||||||
|
cl->netchan.remote_address.type = NA_INVALID; //so the remaining client doesn't get the kick too.
|
||||||
|
cl->protocol = SCP_BAD; //make it a bit like a bot, so we don't try sending any datagrams/reliables at someone that isn't able to receive anything.
|
||||||
|
|
||||||
|
//okay, it can get lost now.
|
||||||
|
cl->drop = true;
|
||||||
|
}
|
||||||
|
host_client->controller->joinobservelockeduntil = realtime + 3;
|
||||||
|
changed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prev = cl;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!changed && count <= num)
|
||||||
|
changed = !!SV_AddSplit(host_client, Cmd_Argv(2), num);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cl = NULL;
|
||||||
|
/* if (host_client->joinobservelockeduntil > realtime)
|
||||||
|
{
|
||||||
|
SV_TPrintToClient(host_client, PRINT_HIGH, va("Please wait %.1g more seconds\n", host_client->joinobservelockeduntil-realtime));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
host_client->joinobservelockeduntil = realtime + 2;
|
||||||
|
|
||||||
|
cl = SV_AddSplit(host_client, host_client->userinfo, 0);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cl || changed)
|
||||||
|
SV_UpdateSeats(host_client);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==================
|
==================
|
||||||
Cmd_Join_f
|
Cmd_Join_f
|
||||||
|
@ -4825,6 +4960,9 @@ void Cmd_FPSList_f(void)
|
||||||
|
|
||||||
void SV_EnableClientsCSQC(void)
|
void SV_EnableClientsCSQC(void)
|
||||||
{
|
{
|
||||||
|
if (host_client->controller)
|
||||||
|
return;
|
||||||
|
|
||||||
#ifdef PEXT_CSQC
|
#ifdef PEXT_CSQC
|
||||||
// if ((host_client->fteprotocolextensions & PEXT_CSQC) || atoi(Cmd_Argv(1)))
|
// if ((host_client->fteprotocolextensions & PEXT_CSQC) || atoi(Cmd_Argv(1)))
|
||||||
{
|
{
|
||||||
|
@ -5314,6 +5452,7 @@ ucmd_t ucmds[] =
|
||||||
{"nextdl", SV_NextDownload_f, true},
|
{"nextdl", SV_NextDownload_f, true},
|
||||||
|
|
||||||
/*quakeworld specific things*/
|
/*quakeworld specific things*/
|
||||||
|
{"addseat", Cmd_AddSeat_f},
|
||||||
{"join", Cmd_Join_f},
|
{"join", Cmd_Join_f},
|
||||||
{"observe", Cmd_Observe_f},
|
{"observe", Cmd_Observe_f},
|
||||||
{"snap", SV_NoSnap_f},
|
{"snap", SV_NoSnap_f},
|
||||||
|
|
Loading…
Reference in a new issue