rewrote cam tracking code. should make cl_chasecam 0 more robust and avoid spam about invalid clients to track (and the associated ptrack spam).

smoothed out cl_chasecam 0 angles.
server browser no longer counts spectators as players. also sorts players by frags.
fix ezhud r_tracking_frame issue, by making it technically 0 height when not tracking.
r_showfields is now a separate cvar, instead of being rolled into r_showbboxes. now shows only a single entity.
fix qport issue.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4915 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2015-06-22 11:49:15 +00:00
parent 6853a4fd1e
commit 59cbcfe355
26 changed files with 377 additions and 229 deletions

View file

@ -146,7 +146,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.
j = cl.playerview[seat].cam_spec_track;
if (j >= 0 && cl.players[j].name[0] && !cl.players[j].spectator)
if (j >= 0 && cl.players[j].userid && cl.players[j].name[0] && !cl.players[j].spectator)
max = CL_TrackScore(&cl.players[j], rule);
else
{
@ -158,7 +158,7 @@ static int CL_FindHighTrack(int seat, char *rule)
{
s = &cl.players[i];
score = CL_TrackScore(s, rule);
if (s->name[0] && !s->spectator && score > max)
if (s->userid && s->name[0] && !s->spectator && score > max)
{
if (j == i) //this was our default.
continue;
@ -210,7 +210,7 @@ qboolean Cam_DrawViewModel(playerview_t *pv)
{
if (cl.spectator)
{
if (pv->cam_auto && pv->cam_locked && cl_chasecam.ival)
if (pv->cam_state == CAM_EYECAM && cl_chasecam.ival)
return true;
return false;
}
@ -224,18 +224,17 @@ qboolean Cam_DrawViewModel(playerview_t *pv)
int Cam_TrackNum(playerview_t *pv)
{
if (!pv->cam_auto)
return -1;
return pv->cam_spec_track;
if (pv->cam_state == CAM_EYECAM)
return pv->cam_spec_track;
return -1;
}
void Cam_Unlock(playerview_t *pv)
{
if (pv->cam_auto)
if (pv->cam_state)
{
CL_SendClientCommand(true, "ptrack");
pv->cam_auto = CAM_NONE;
pv->cam_locked = false;
pv->cam_state = CAM_FREECAM;
pv->viewentity = (cls.demoplayback)?0:(pv->playernum+1); //free floating
Sbar_Changed();
}
@ -245,12 +244,12 @@ void Cam_Lock(playerview_t *pv, int playernum)
{
int i;
pv->cam_lastviewtime = -1000;
pv->cam_lastviewtime = -1000; //allow the wallcam to re-snap as soon as it can
CL_SendClientCommand(true, "ptrack %i", playernum);
pv->cam_spec_track = playernum;
pv->cam_locked = false;
pv->cam_state = CAM_PENDING;
pv->viewentity = (cls.demoplayback)?0:(pv->playernum+1); //free floating until actually locked
@ -259,10 +258,16 @@ void Cam_Lock(playerview_t *pv, int playernum)
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
{
memcpy(&pv->stats, cl.players[playernum].stats, sizeof(pv->stats));
pv->cam_locked = true; //instantly lock if the player is valid.
// pv->cam_state = CAM_;
// pv->viewentity = playernum+1;
/*
pv->cam_state = cl_chasecam.ival?CAM_EYECAM:CAM_PENDING; //instantly lock if the player is valid.
pv->viewentity = playernum+1;
*/
if (cls.z_ext & Z_EXT_VIEWHEIGHT)
pv->viewheight = cl.players[playernum].statsf[STAT_VIEWHEIGHT];
}
Sbar_Changed();
@ -389,7 +394,7 @@ static qboolean InitFlyby(playerview_t *pv, vec3_t selforigin, vec3_t playerorig
return false;
}
pv->cam_locked = true;
pv->cam_state = CAM_WALLCAM;
pv->viewentity = pv->playernum+1;//pv->cam_spec_track+1;
VectorCopy(vec, pv->cam_desired_position);
return true;
@ -403,19 +408,18 @@ static void Cam_CheckHighTarget(playerview_t *pv)
j = CL_AutoTrack_Choose(pv - cl.playerview);
if (j >= 0)
{
if (pv->cam_spec_track != j || !pv->cam_locked)
if (pv->cam_spec_track != j || pv->cam_state == CAM_FREECAM)
{
if (cl.teamplay)
Stats_Message("Now tracking:\n%s\n%s", cl.players[j].name, cl.players[j].team);
else
Stats_Message("Now tracking:\n%s", cl.players[j].name);
pv->cam_auto++;
Cam_Lock(pv, j);
//un-lock any higher seats watching our new target. this keeps things ordered.
for (spv = pv+1; spv >= cl.playerview && spv < &cl.playerview[cl.splitclients]; spv++)
{
if (Cam_TrackNum(spv) == j)
spv->cam_locked = false;
spv->cam_state = CAM_FREECAM;
}
}
}
@ -445,9 +449,9 @@ void Cam_SelfTrack(playerview_t *pv)
}
else
{ //view from a random wall
if (!pv->cam_locked || !Cam_IsVisible(pv->simorg, pv->cam_desired_position))
if (pv->cam_state != CAM_WALLCAM || !Cam_IsVisible(pv->simorg, pv->cam_desired_position))
{
if (!pv->cam_locked || realtime - pv->cam_lastviewtime > 0.1)
if (pv->cam_state != CAM_WALLCAM || realtime - pv->cam_lastviewtime > 0.1)
{
if (!InitFlyby(pv, pv->cam_desired_position, pv->simorg, pv->simangles, true))
InitFlyby(pv, pv->cam_desired_position, pv->simorg, pv->simangles, false);
@ -460,7 +464,7 @@ void Cam_SelfTrack(playerview_t *pv)
}
//tracking failed.
if (!pv->cam_locked)
if (pv->cam_state != CAM_WALLCAM)
return;
}
@ -474,6 +478,23 @@ void Cam_SelfTrack(playerview_t *pv)
}
}
//player entity became visible, lock on to them (now that we know where they are etc)
void Cam_NowLocked(playerview_t *pv)
{
pv->cam_lastviewtime = realtime;
if (!cl_chasecam.ival)
{
if (pv->cam_state != CAM_WALLCAM || !Cam_IsVisible(pv->simorg, pv->cam_desired_position))
{
if (pv->cam_state != CAM_WALLCAM || realtime - pv->cam_lastviewtime > 0.1)
{
if (!InitFlyby(pv, pv->cam_desired_position, pv->simorg, pv->simangles, true))
InitFlyby(pv, pv->cam_desired_position, pv->simorg, pv->simangles, false);
}
}
}
}
// ZOID
//
// Take over the user controls and track a player.
@ -488,15 +509,15 @@ void Cam_Track(playerview_t *pv, usercmd_t *cmd)
if (!cl.spectator || !cl.worldmodel) //can happen when the server changes level
return;
if (autotrackmode != TM_USER && !pv->cam_locked)
if (autotrackmode != TM_USER && pv->cam_state == CAM_FREECAM)
Cam_CheckHighTarget(pv);
if (!pv->cam_auto || cls.state != ca_active || cl.worldmodel->loadstate != MLS_LOADED)
if (pv->cam_state == CAM_FREECAM || cls.state != ca_active || cl.worldmodel->loadstate != MLS_LOADED)
return;
if (pv->cam_locked && (!cl.players[pv->cam_spec_track].name[0] || cl.players[pv->cam_spec_track].spectator))
if (CAM_ISLOCKED(pv) && (!cl.players[pv->cam_spec_track].name[0] || cl.players[pv->cam_spec_track].spectator))
{
pv->cam_locked = false;
pv->cam_state = CAM_FREECAM;
if (autotrackmode != TM_USER)
Cam_CheckHighTarget(pv);
else
@ -508,22 +529,24 @@ void Cam_Track(playerview_t *pv, usercmd_t *cmd)
player = frame->playerstate + pv->cam_spec_track;
self = frame->playerstate + pv->playernum;
if (!cl_chasecam.value && (!pv->cam_locked || !Cam_IsVisible(player->origin, pv->cam_desired_position)))
if (!cl_chasecam.value && (pv->cam_state != CAM_WALLCAM || !Cam_IsVisible(player->origin, pv->cam_desired_position)))
{
if (!pv->cam_locked || realtime - pv->cam_lastviewtime > 0.1)
if (pv->cam_state != CAM_WALLCAM || realtime - pv->cam_lastviewtime > 0.1)
{
if (!InitFlyby(pv, self->origin, player->origin, player->viewangles, true))
InitFlyby(pv, self->origin, player->origin, player->viewangles, false);
pv->cam_lastviewtime = realtime;
}
}
else if (cl_chasecam.value && pv->cam_state == CAM_WALLCAM)
pv->cam_state = CAM_PENDING;
else
{
pv->cam_lastviewtime = realtime;
}
//tracking failed.
if (!pv->cam_locked || !pv->cam_auto)
if (pv->cam_state == CAM_FREECAM || pv->cam_state == CAM_PENDING)
return;
@ -574,12 +597,12 @@ void Cam_Track(playerview_t *pv, usercmd_t *cmd)
// move there locally immediately
VectorCopy(pv->cam_desired_position, self->origin);
VectorSubtract(player->origin, pv->cam_desired_position, vec);
VectorAngles(vec, NULL, pv->viewangles);
pv->viewangles[0] = -pv->viewangles[0];
// VectorSubtract(player->origin, pv->cam_desired_position, vec);
// VectorAngles(vec, NULL, pv->viewangles);
// pv->viewangles[0] = -pv->viewangles[0];
}
void Cam_SetAutoTrack(int userid)
void Cam_SetModAutoTrack(int userid)
{ //this is a hint from the server about who to track
int slot;
playerview_t *pv = &cl.playerview[0];
@ -624,7 +647,6 @@ void Cam_TrackCrosshairedPlayer(playerview_t *pv)
// Con_Printf("Track %i? %f\n", best, bestdot);
if (best != -1) //did we actually get someone?
{
pv->cam_auto++;
Cam_Lock(pv, best);
}
}
@ -719,9 +741,8 @@ void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd)
if (!(pv->cam_oldbuttons & BUTTON_ATTACK))
{
pv->cam_oldbuttons |= BUTTON_ATTACK;
pv->cam_auto++;
if (pv->cam_auto > CAM_TRACK)
if (pv->cam_state != CAM_FREECAM)
{
Cam_Unlock(pv);
VectorCopy(pv->viewangles, cmd->angles);
@ -735,7 +756,7 @@ void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd)
else
{
pv->cam_oldbuttons &= ~BUTTON_ATTACK;
if (!pv->cam_auto && autotrackmode == TM_USER)
if (pv->cam_state == CAM_FREECAM && autotrackmode == TM_USER)
{
if ((cmd->buttons & BUTTON_JUMP) && !(pv->cam_oldbuttons & BUTTON_JUMP))
Cam_TrackCrosshairedPlayer(pv);
@ -744,7 +765,7 @@ void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd)
}
}
if (pv->cam_auto && autotrackmode != TM_USER)
if (autotrackmode != TM_USER)
{
if ((cmd->buttons & BUTTON_JUMP) && !(pv->cam_oldbuttons & BUTTON_JUMP))
autotrackmode = TM_USER;
@ -755,7 +776,7 @@ void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd)
}
}
if (pv->cam_locked)
if (pv->cam_state != CAM_FREECAM)
{
if ((cmd->buttons & BUTTON_JUMP) && (pv->cam_oldbuttons & BUTTON_JUMP))
return; // don't pogo stick
@ -770,8 +791,8 @@ void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd)
// Con_Printf("Selecting track target...\n");
if (pv->cam_locked && pv->cam_auto)
end = (pv->cam_spec_track + 1) % MAX_CLIENTS;
if (pv->cam_state != CAM_FREECAM)
end = (pv->cam_spec_track + 1) % MAX_CLIENTS;
else
end = pv->cam_spec_track;
i = end;
@ -796,7 +817,7 @@ void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd)
return;
}
Con_Printf("No target found ...\n");
pv->cam_auto = pv->cam_locked = false;
pv->cam_state = CAM_FREECAM;
}
void Cam_Reset(void)
@ -805,7 +826,7 @@ void Cam_Reset(void)
for (pnum = 0; pnum < MAX_SPLITS; pnum++)
{
playerview_t *pv = &cl.playerview[pnum];
pv->cam_auto = CAM_NONE;
pv->cam_state = CAM_FREECAM;
pv->cam_spec_track = 0;
}
}
@ -919,11 +940,7 @@ void Cam_TrackPlayer(int seat, char *cmdname, char *plrarg)
}
}
pv->cam_auto = CAM_TRACK;
Cam_Lock(pv, slot);
//and force the lock here and now
pv->cam_locked = true;
pv->viewentity = slot+1;
}
void Cam_Track_f(void)

View file

@ -758,7 +758,7 @@ readit:
for (seat = 0; seat < cl.splitclients; seat++)
{
tracknum = cl.playerview[seat].cam_spec_track;
if (!cl.playerview[seat].cam_auto)
if (cl.playerview[seat].cam_state == CAM_FREECAM)
tracknum = -1;
if (tracknum == -1 || !(cls_lastto & (1 << tracknum)))
continue;
@ -780,7 +780,7 @@ readit:
for (seat = 0; seat < maxseat; seat++)
{
tracknum = cl.playerview[seat].cam_spec_track;
if (!cl.playerview[seat].cam_auto)
if (cl.playerview[seat].cam_state == CAM_FREECAM)
tracknum = -1;
if (tracknum == -1 || (cls_lastto != tracknum))
continue;

View file

@ -2535,7 +2535,17 @@ void CLQ1_AddVisibleBBoxes(void)
CLQ1_AddOrientedCylinder(s, rad*2, height*2, true, matrix, (e->v->solid || e->v->movetype)?0.1:0, (e->v->movetype == MOVETYPE_STEP || e->v->movetype == MOVETYPE_TOSS || e->v->movetype == MOVETYPE_BOUNCE)?0.1:0, ((int)e->v->flags & (FL_ONGROUND | ((e->v->movetype == MOVETYPE_STEP)?FL_FLY:0)))?0.1:0, 1);
}
else
CLQ1_AddOrientedCube(s, min, max, NULL, (e->v->solid || e->v->movetype)?0.1:0, (e->v->movetype == MOVETYPE_STEP || e->v->movetype == MOVETYPE_TOSS || e->v->movetype == MOVETYPE_BOUNCE)?0.1:0, ((int)e->v->flags & (FL_ONGROUND | ((e->v->movetype == MOVETYPE_STEP)?FL_FLY:0)))?0.1:0, 1);
{
if (!e->v->solid && !e->v->movetype)
{
vec3_t ep = {1,1,1};
VectorAdd(max, ep, max);
VectorSubtract(min, ep, min);
CLQ1_AddOrientedCube(s, min, max, NULL, 0, 0.1, 0, 1);
}
else
CLQ1_AddOrientedCube(s, min, max, NULL, (e->v->solid || e->v->movetype)?0.1:0, (e->v->movetype == MOVETYPE_STEP || e->v->movetype == MOVETYPE_TOSS || e->v->movetype == MOVETYPE_BOUNCE)?0.1:0, ((int)e->v->flags & (FL_ONGROUND | ((e->v->movetype == MOVETYPE_STEP)?FL_FLY:0)))?0.1:0, 1);
}
}
}
@ -3861,8 +3871,7 @@ void CL_ParsePlayerinfo (void)
info->prevcount = cl.parsecount;
if (cls.findtrack && info->stats[STAT_HEALTH] > 0)
{
cl.playerview[0].cam_auto = CAM_TRACK;
{ //FIXME: is this still needed with the autotrack stuff?
Cam_Lock(&cl.playerview[0], num);
cls.findtrack = false;
}
@ -3950,15 +3959,13 @@ void CL_ParsePlayerinfo (void)
for (i = 0; i < cl.splitclients; i++)
{
playerview_t *pv = &cl.playerview[i];
if (pv->cam_auto && pv->cam_spec_track == num)
if (pv->cam_state != CAM_FREECAM && pv->cam_spec_track == num)
return;
}
if (i == cl.splitclients)
{
playerview_t *pv = &cl.playerview[cl.splitclients++];
pv->cam_auto = CAM_TRACK;
pv->cam_spec_track = num;
Cam_Lock(pv, num);
}
}
@ -4503,7 +4510,7 @@ void CL_LinkPlayers (void)
angles[ROLL] = 0;
angles[ROLL] = V_CalcRoll (angles, state->velocity)*4;
if (j+1 == r_refdef.playerview->viewentity || (cl.spectator && r_refdef.playerview->cam_locked && r_refdef.playerview->cam_spec_track == j))
if (j+1 == r_refdef.playerview->viewentity || (r_refdef.playerview->cam_state == CAM_EYECAM && r_refdef.playerview->cam_spec_track == j))
ent->flags |= RF_EXTERNALMODEL;
// the player object gets added with flags | 2
for (pnum = 0; pnum < cl.splitclients; pnum++)

View file

@ -286,7 +286,7 @@ void IN_JumpDown (void)
cl.inframes[cl.validsequence&UPDATE_MASK].playerstate[cl.playerview[pnum].playernum].messagenum == cl.validsequence && cl.playerview[pnum].waterlevel >= 2 && (!cl.teamfortress || !(in_forward.state[pnum] & 1))
)
KeyDown(&in_up);
else if (condition && cl.spectator && Cam_TrackNum(&cl.playerview[pnum]) == -1)
else if (condition && cl.spectator && !CAM_ISLOCKED(&cl.playerview[pnum]))
KeyDown(&in_up);
else
KeyDown(&in_jump);

View file

@ -55,8 +55,9 @@ typedef enum
SLKEY_MOD,
SLKEY_PROTOCOL,
SLKEY_NUMBOTS,
SLKEY_NUMHUMANS,
SLKEY_NUMBOTS, //uninteresting bots that will presumably get kicked if people join.
SLKEY_NUMSPECTATORS,//spectators
SLKEY_NUMHUMANS, //actual players
SLKEY_QCSTATUS,
// SLKEY_PLAYERS, //eep!
SLKEY_ISFAVORITE,//eep!
@ -92,17 +93,18 @@ typedef struct serverdetailedinfo_s
int numplayers;
struct
struct serverdetailedplayerinfo_s
{
int userid;
int frags;
float time;
int ping;
char name[64];
char skin[16];
char skin[16]; //is this even useful?
char team[16];
char topc;
char botc;
qbyte isspec;
} players[MAX_CLIENTS];
} serverdetailedinfo_t;
@ -115,15 +117,15 @@ typedef struct serverinfo_s
short special; //flags
short protocol;
unsigned char players;
unsigned char maxplayers;
qbyte players;
qbyte maxplayers;
qbyte sends;
qbyte insortedlist;
qbyte numspectators;
qbyte numhumans;
qbyte numbots;
qbyte freeslots;
qbyte pad;
char modname[8+1];
char qcstatus[8+1];

View file

@ -5764,7 +5764,7 @@ void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds from n
}
else if (!strncmp(stufftext, "//at ", 5))
{
Cam_SetAutoTrack(atoi(stufftext+5));
Cam_SetModAutoTrack(atoi(stufftext+5));
}
else if (!strncmp(stufftext, "//wps ", 5))
{

View file

@ -752,14 +752,15 @@ static void CL_EntStateToPlayerState(player_state_t *plstate, entity_state_t *st
else
VectorScale(state->u.q1.velocity, 1/8.0, plstate->velocity);
VectorCopy(state->angles, plstate->viewangles);
if (state->u.q1.pmovetype)
plstate->viewangles[0] *= -3;
plstate->viewangles[2] = V_CalcRoll(plstate->viewangles, plstate->velocity);
// plstate->viewangles[2] = V_CalcRoll(plstate->viewangles, plstate->velocity);
plstate->viewangles[0] = SHORT2ANGLE(state->u.q1.vangle[0]);
plstate->viewangles[1] = SHORT2ANGLE(state->u.q1.vangle[1]);
plstate->viewangles[2] = SHORT2ANGLE(state->u.q1.vangle[2]);
if (state->u.q1.pmovetype)
plstate->viewangles[0] *= -3;
a[0] = ((-192-state->u.q1.gravitydir[0])/256.0f) * 360;
a[1] = (state->u.q1.gravitydir[1]/256.0f) * 360;
a[2] = 0;
@ -850,6 +851,8 @@ void CL_PredictMovePNum (int seat)
lerpents_t *le;
qboolean nopred;
qboolean lerpangles = false;
int trackent;
qboolean cam_nowlocked = false;
//these are to make svc_viewentity work better
float netfps = cl_netfps.value;
@ -890,6 +893,9 @@ void CL_PredictMovePNum (int seat)
pv->nolocalplayer = !!(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) || (cls.protocol != CP_QUAKEWORLD);
if (!cl.spectator) //just in case
pv->cam_state = CAM_FREECAM;
#ifdef Q2CLIENT
if (cls.protocol == CP_QUAKE2)
{
@ -901,7 +907,7 @@ void CL_PredictMovePNum (int seat)
}
#endif
if (cl.paused && !(cls.demoplayback!=DPB_MVD && cls.demoplayback!=DPB_EZTV) && (!cl.spectator || !pv->cam_auto))
if (cl.paused && !(cls.demoplayback!=DPB_MVD && cls.demoplayback!=DPB_EZTV) && pv->cam_state == CAM_FREECAM)
return;
if (!cl.validsequence)
@ -937,31 +943,23 @@ void CL_PredictMovePNum (int seat)
}
}
if (pv->cam_locked && pv->cam_spec_track >= 0)
//if we now know where our target player is, we can finally lock on to them.
if (pv->cam_state == CAM_PENDING && pv->cam_spec_track >= 0 && pv->cam_spec_track < cl.allocated_client_slots && pv->viewentity != pv->cam_spec_track+1)
{
extern cvar_t cl_chasecam;
if (!cl_chasecam.ival)
if ((cl.inframes[cl.validsequence & UPDATE_MASK].playerstate[pv->cam_spec_track].messagenum == cl.validsequence) ||
(pv->cam_spec_track+1 < cl.maxlerpents && cl.lerpents[pv->cam_spec_track+1].sequence == cl.lerpentssequence))
{
//FIXME: don't early out, so that we can smooth out angles too
VectorCopy(pv->cam_desired_position, pv->simorg);
VectorClear(pv->simvel);
return;
extern cvar_t cl_chasecam;
pv->cam_state = CAM_EYECAM;
pv->viewentity = pv->cam_spec_track+1;
cam_nowlocked = true;
}
}
if (!pv->cam_locked && pv->cam_auto && cl.spectator && pv->cam_spec_track >= 0 && pv->cam_spec_track < cl.allocated_client_slots && pv->viewentity != pv->cam_spec_track+1)
{
if (cl.inframes[cl.validsequence & UPDATE_MASK].playerstate[pv->cam_spec_track].messagenum == cl.validsequence)
{
pv->cam_locked = true;
pv->viewentity = pv->cam_spec_track+1;
}
else if (pv->cam_spec_track+1 < cl.maxlerpents && cl.lerpents[pv->cam_spec_track+1].sequence == cl.lerpentssequence)
{
pv->cam_locked = true;
pv->viewentity = pv->cam_spec_track+1;
}
}
if (pv->cam_state == CAM_WALLCAM)
trackent = pv->cam_spec_track+1;
else
trackent = pv->viewentity;
nopred = cl_nopred.ival;
@ -973,7 +971,7 @@ void CL_PredictMovePNum (int seat)
//these things also force-disable prediction
if ((cls.demoplayback==DPB_MVD || cls.demoplayback == DPB_EZTV) ||
cl.paused || pv->pmovetype == PM_NONE || pv->pmovetype == PM_FREEZE || pv->cam_locked)
cl.paused || pv->pmovetype == PM_NONE || pv->pmovetype == PM_FREEZE || CAM_ISLOCKED(pv))
{
nopred = true;
}
@ -1044,10 +1042,10 @@ void CL_PredictMovePNum (int seat)
// Con_DPrintf("sim%f, %i(%i-%i): old%f, cur%f\n", simtime, cl.ackedmovesequence, fromframe, toframe, fromtime, totime);
if (pv->cam_locked && cl.spectator && pv->viewentity && pv->viewentity <= cl.allocated_client_slots)
if ((pv->cam_state == CAM_WALLCAM || pv->cam_state == CAM_EYECAM) && trackent && trackent <= cl.allocated_client_slots)
{
fromstate = &cl.inframes[fromframe & UPDATE_MASK].playerstate[pv->viewentity-1];
tostate = &cl.inframes[toframe & UPDATE_MASK].playerstate[pv->viewentity-1];
fromstate = &cl.inframes[fromframe & UPDATE_MASK].playerstate[trackent-1];
tostate = &cl.inframes[toframe & UPDATE_MASK].playerstate[trackent-1];
}
else
{
@ -1078,7 +1076,7 @@ void CL_PredictMovePNum (int seat)
pe = &cl.inframes[fromframe & UPDATE_MASK].packet_entities;
for (i = 0; i < pe->num_entities; i++)
{
if (pe->entities[i].number == pv->viewentity)
if (pe->entities[i].number == trackent)
{
CL_EntStateToPlayerState(fromstate, &pe->entities[i]);
if (nopred)
@ -1089,7 +1087,7 @@ void CL_PredictMovePNum (int seat)
pe = &cl.inframes[toframe & UPDATE_MASK].packet_entities;
for (i = 0; i < pe->num_entities; i++)
{
if (pe->entities[i].number == pv->viewentity)
if (pe->entities[i].number == trackent)
{
CL_EntStateToPlayerState(tostate, &pe->entities[i]);
if (nopred)
@ -1107,14 +1105,14 @@ void CL_PredictMovePNum (int seat)
break;
}
}
if (pv->nolocalplayer && pv->viewentity < cl.maxlerpents)
le = &cl.lerpents[pv->viewentity];
if (pv->nolocalplayer && trackent < cl.maxlerpents)
le = &cl.lerpents[trackent];
}
// predict forward until cl.time <= to->senttime
oldphysent = pmove.numphysent;
CL_SetSolidPlayers();
pmove.skipent = pv->viewentity;
pmove.skipent = trackent;
//just in case we don't run any prediction
VectorCopy(tostate->gravitydir, pmove.gravitydir);
@ -1166,7 +1164,7 @@ void CL_PredictMovePNum (int seat)
tostate = &framebuf[i&1];
// Con_DPrintf(" pred %i: %f-%f\n", cl.ackedmovesequence+i, fromtime, totime);
CL_PredictUsercmd (seat, pv->viewentity, fromstate, tostate, cmdto);
CL_PredictUsercmd (seat, trackent, fromstate, tostate, cmdto);
}
if (simtime > totime)
@ -1201,7 +1199,7 @@ void CL_PredictMovePNum (int seat)
cmdto->msec = bound(0, msec, 250);
// Con_DPrintf(" extrap %i: %f-%f (%g)\n", toframe, fromtime, simtime, simtime-fromtime);
CL_PredictUsercmd (seat, pv->viewentity, fromstate, tostate, cmdto);
CL_PredictUsercmd (seat, trackent, fromstate, tostate, cmdto);
}
}
pv->onground = pmove.onground;
@ -1215,7 +1213,7 @@ void CL_PredictMovePNum (int seat)
VectorCopy (tostate->velocity, pv->simvel);
VectorCopy (tostate->origin, pv->simorg);
if (pv->viewentity && pv->viewentity != pv->playernum+1 && pv->cam_locked)
if (trackent && trackent != pv->playernum+1 && pv->cam_state == CAM_EYECAM)
VectorCopy(tostate->viewangles, pv->simangles);
//Con_DPrintf("%f %f %f\n", fromtime, simtime, totime);
}
@ -1245,7 +1243,7 @@ void CL_PredictMovePNum (int seat)
pv->simorg[i] = (1-f)*fromstate->origin[i] + f*tostate->origin[i];
pv->simvel[i] = (1-f)*fromstate->velocity[i] + f*tostate->velocity[i];
if (pv->viewentity && pv->viewentity != pv->playernum+1 && pv->cam_locked)
if (trackent && trackent != pv->playernum+1 && pv->cam_state == CAM_EYECAM)
{
pv->simangles[i] = LerpAngles360(fromstate->viewangles[i], tostate->viewangles[i], f);// * (360.0/65535);
// pv->viewangles[i] = LerpAngles16(fromstate->command.angles[i], tostate->command.angles[i], f) * (360.0/65535);
@ -1262,9 +1260,12 @@ void CL_PredictMovePNum (int seat)
CL_CalcCrouch (pv);
pv->waterlevel = pmove.waterlevel;
VectorCopy(pmove.gravitydir, pv->gravitydir);
if (!DotProduct(pmove.gravitydir,pmove.gravitydir))
VectorSet(pmove.gravitydir, 0, 0, -1);
else
VectorCopy(pmove.gravitydir, pv->gravitydir);
if (le)
if (le && pv->cam_state == CAM_FREECAM)
{
//keep the entity tracking the prediction position, so mirrors don't go all weird
VectorMA(pv->simorg, -pv->crouch, pv->gravitydir, le->origin);
@ -1277,6 +1278,29 @@ void CL_PredictMovePNum (int seat)
le->angles[0] *= -0.333;
}
}
if (cam_nowlocked)
Cam_NowLocked(pv);
if (pv->cam_state == CAM_WALLCAM)
{
vec3_t dir;
VectorSubtract(pv->simorg, pv->cam_desired_position, dir);
VectorAngles(dir, NULL, pv->simangles);
pv->simangles[0] *= -1;
VectorCopy(pv->simangles, pv->viewangles);
pv->viewangles[0] = anglemod(pv->viewangles[0]);
if (pv->viewangles[0] > 180)
pv->viewangles[0] -= 360;
VectorCopy(pv->cam_desired_position, pv->simorg);
VectorClear(pv->simvel);
}
if (cam_nowlocked)
{
//invalidate the roll, so we don't spin when switching povs
pv->rollangle = V_CalcRoll(pv->simangles, pv->simvel);
pv->vm.oldmodel = NULL; //invalidate the viewmodel, so the lerps get reset
}
}
void CL_PredictMove (void)

View file

@ -853,7 +853,7 @@ void CL_AddBeam (int tent, int ent, vec3_t start, vec3_t end) //fixme: use TE_ n
for (i = 0; i < cl.splitclients; i++)
{
playerview_t *pv = &cl.playerview[i];
if (ent == (pv->cam_auto?(pv->cam_spec_track+1):(pv->playernum+1)))
if (ent == ((pv->cam_state == CAM_EYECAM)?(pv->cam_spec_track+1):(pv->playernum+1)))
{
VectorCopy(end, playerbeam_end[i]);
break;
@ -3435,7 +3435,7 @@ void CL_UpdateBeams (void)
for (j = 0; j < cl.splitclients; j++)
{
playerview_t *pv = &cl.playerview[j];
if (b->entity == ((cl.spectator&&pv->cam_auto)?pv->cam_spec_track+1:(pv->playernum+1)))
if (b->entity == ((pv->cam_state == CAM_EYECAM)?pv->cam_spec_track+1:(pv->playernum+1)))
{
// player_state_t *pl;
// VectorSubtract(cl.simorg, b->start, org);

View file

@ -628,17 +628,20 @@ struct playerview_s
vec3_t cam_desired_position; // where the camera wants to be
qboolean cam_locked; //
int cam_oldbuttons; //
vec3_t cam_viewangles; //
double cam_lastviewtime; //
double cam_lastviewtime; // timer for wallcam
float cam_reautotrack; // timer to throttle tracking changes.
int cam_spec_track; // player# of who we are tracking
int cam_spec_track; // player# of who we are tracking / want to track / might want to track
enum
{
CAM_NONE = 0,
CAM_TRACK = 1
} cam_auto; //
CAM_FREECAM = 0, //not attached to another player. we are our own thing (or actually playing).
CAM_PENDING = 1, //we want to lock on to cam_spec_track, but we don't have their position / stats yet. still freecamming
CAM_WALLCAM = 2, //locked, cl_chasecam=0. we're watching them from a wall.
CAM_EYECAM = 3 //locked, cl_chasecam=1. we know where they are, we're in their eyes.
#define CAM_ISLOCKED(pv) ((pv)->cam_state > CAM_PENDING)
} cam_state; //
vec3_t vw_axis[3]; //weapons should be positioned relative to this
vec3_t vw_origin; //weapons should be positioned relative to this
@ -1277,18 +1280,18 @@ void CL_CalcClientTime(void);
//
qboolean Cam_DrawViewModel(playerview_t *pv);
int Cam_TrackNum(playerview_t *pv);
void Cam_Unlock(playerview_t *pv);
void Cam_Lock(playerview_t *pv, int playernum);
void Cam_Unlock(playerview_t *pv); //revert to freecam or so, because that entity failed.
void Cam_Lock(playerview_t *pv, int playernum); //attempt to lock on to the given player.
void Cam_NowLocked(playerview_t *pv); //player was located, track them now
void Cam_SelfTrack(playerview_t *pv);
void Cam_Track(playerview_t *pv, usercmd_t *cmd);
void Cam_TrackCrosshairedPlayer(playerview_t *pv);
void Cam_SetAutoTrack(int userid);
void Cam_SetModAutoTrack(int userid);
void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd);
void Cam_Reset(void);
void Cam_TrackPlayer(int seat, char *cmdname, char *plrarg);
void Cam_Lock(playerview_t *pv, int playernum);
void CL_InitCam(void);
void Cam_AutoTrack_Update(const char *mode);
void Cam_AutoTrack_Update(const char *mode); //reset autotrack setting (because we started a new map or whatever)
void QDECL vectoangles(vec3_t fwd, vec3_t ang);

View file

@ -190,7 +190,7 @@ void Stats_FragMessage(int p1, int wid, int p2, qboolean teamkill)
struct wt_s *w = &fragstats.weapontotals[wid];
const char *p1n = (p1 < 0)?nonplayers[-p1]:cl.players[p1].name;
const char *p2n = (p2 < 0)?nonplayers[-p2]:cl.players[p2].name;
int localplayer = (cl.spectator && cl.playerview[0].cam_locked)?cl.playerview[0].cam_spec_track:cl.playerview[0].playernum;
int localplayer = (cl.playerview[0].cam_state == CAM_EYECAM)?cl.playerview[0].cam_spec_track:cl.playerview[0].playernum;
#define YOU_GOOD S_COLOR_GREEN
#define YOU_BAD S_COLOR_BLUE

View file

@ -502,7 +502,7 @@ static void SL_PostDraw (menu_t *menu)
int teamplay = atoi(Info_ValueForKey(server->moreinfo->info, "teamplay"));
x = lx;
Draw_FunStringWidth (x, y, "^mFrgs", 28, true, false);
x += 28+8;
x += 32+8;
Draw_FunStringWidth (x, y, "^mPng", 28, true, false);
x += 3*8+8;
@ -523,12 +523,17 @@ static void SL_PostDraw (menu_t *menu)
for (i = 0; i < server->moreinfo->numplayers; i++)
{
x = lx;
R2D_ImagePaletteColour (Sbar_ColorForMap(server->moreinfo->players[i].topc), 1.0);
R2D_FillBlock (x, y+1, 28, 3);
R2D_ImagePaletteColour (Sbar_ColorForMap(server->moreinfo->players[i].botc), 1.0);
R2D_FillBlock (x, y+4, 28, 4);
Draw_FunStringWidth (x, y, va("%3i", server->moreinfo->players[i].frags), 28, true, false);
x += 28+8;
if (server->moreinfo->players[i].isspec)
Draw_FunStringWidth (x, y, "spec", 32, true, false);
else
{
R2D_ImagePaletteColour (Sbar_ColorForMap(server->moreinfo->players[i].topc), 1.0);
R2D_FillBlock (x, y+1, 32, 3);
R2D_ImagePaletteColour (Sbar_ColorForMap(server->moreinfo->players[i].botc), 1.0);
R2D_FillBlock (x, y+4, 32, 4);
Draw_FunStringWidth (x, y, va("%3i", server->moreinfo->players[i].frags), 32, true, false);
}
x += 32+8;
Draw_FunStringWidth (x, y, va("%3i", server->moreinfo->players[i].ping), 28, true, false);
x += 3*8+8;
@ -956,6 +961,7 @@ void M_Menu_ServerList2_f(void)
serverpreview = false; //in case it was lingering.
Key_Dest_Remove(kdm_console);
Key_Dest_Add(kdm_menu);
m_state = m_complex;

View file

@ -776,6 +776,8 @@ qboolean Master_ServerIsGreater(serverinfo_t *a, serverinfo_t *b)
return Master_CompareInteger(a->players, b->players, SLIST_TEST_LESS);
case SLKEY_NUMHUMANS:
return Master_CompareInteger(a->numhumans, b->numhumans, SLIST_TEST_LESS);
case SLKEY_NUMSPECTATORS:
return Master_CompareInteger(a->numspectators, b->numspectators, SLIST_TEST_LESS);
case SLKEY_NUMBOTS:
return Master_CompareInteger(a->numbots, b->numbots, SLIST_TEST_LESS);
case SLKEY_PING:
@ -850,6 +852,9 @@ qboolean Master_PassesMasks(serverinfo_t *a)
case SLKEY_NUMHUMANS:
res = Master_CompareInteger(a->numhumans, visrules[i].operandi, visrules[i].compareop);
break;
case SLKEY_NUMSPECTATORS:
res = Master_CompareInteger(a->numspectators, visrules[i].operandi, visrules[i].compareop);
break;
case SLKEY_TIMELIMIT:
res = Master_CompareInteger(a->tl, visrules[i].operandi, visrules[i].compareop);
break;
@ -1052,6 +1057,8 @@ float Master_ReadKeyFloat(serverinfo_t *server, int keynum)
return server->numbots;
case SLKEY_NUMHUMANS:
return server->numhumans;
case SLKEY_NUMSPECTATORS:
return server->numspectators;
case SLKEY_ISFAVORITE:
return !!(server->special & SS_FAVORITE);
case SLKEY_ISLOCAL:
@ -1184,6 +1191,8 @@ int Master_KeyForName(const char *keyname)
return SLKEY_NUMBOTS;
else if (!strcmp(keyname, "numhumans"))
return SLKEY_NUMHUMANS;
else if (!strcmp(keyname, "numspectators"))
return SLKEY_NUMSPECTATORS;
else if (!strcmp(keyname, "qcstatus"))
return SLKEY_QCSTATUS;
else if (!strcmp(keyname, "isfavorite"))
@ -2594,7 +2603,7 @@ int CL_ReadServerInfo(char *msg, enum masterprotocol_e prototype, qboolean favor
char *nl;
char *name;
int ping;
int len;
int len, j, k;
serverinfo_t *info;
char adr[MAX_ADR_SIZE];
@ -2748,6 +2757,8 @@ int CL_ReadServerInfo(char *msg, enum masterprotocol_e prototype, qboolean favor
break;
*nl = '\0';
details.players[clnum].isspec = false;
token = msg;
if (!token)
break;
@ -2804,7 +2815,10 @@ int CL_ReadServerInfo(char *msg, enum masterprotocol_e prototype, qboolean favor
if (len >= sizeof(details.players[clnum].name))
len = sizeof(details.players[clnum].name);
if (!strncmp(token, "\"\\s\\", 4))
{
details.players[clnum].isspec = true;
Q_strncpyz(details.players[clnum].name, token+4, len-3);
}
else
Q_strncpyz(details.players[clnum].name, token+1, len);
details.players[clnum].name[len] = '\0';
@ -2848,12 +2862,28 @@ int CL_ReadServerInfo(char *msg, enum masterprotocol_e prototype, qboolean favor
MasterInfo_AddPlayer(&info->adr, details.players[clnum].name, details.players[clnum].ping, details.players[clnum].frags, details.players[clnum].topc*4 | details.players[clnum].botc, details.players[clnum].skin, details.players[clnum].team);
++details.numplayers;
if (details.players[clnum].ping == 807 || !strncmp(details.players[clnum].name, "BOT:", 4))
info->numbots++;
else if (details.players[clnum].isspec)
info->numspectators++;
else
info->numhumans++;
for (k = clnum, j = clnum-1; j >= 0; j--)
{
if ((details.players[k].isspec != details.players[j].isspec && !details.players[k].isspec) ||
details.players[k].frags > details.players[j].frags)
{
struct serverdetailedplayerinfo_s t = details.players[j];
details.players[j] = details.players[k];
details.players[k] = t;
k = j;
}
else
break;
}
details.numplayers++;
info->players++;
msg = nl;

View file

@ -346,7 +346,7 @@ void R_Clutter_Emit(batch_t **batches)
{
const float cluttersize = r_clutter_distance.value;
int vx, vy, vz;
int x, y, z, key, i;
int x, y, z, key, i, j;
cluttersector_t *sect;
batch_t *b;
qboolean rebuildlimit = false;
@ -453,6 +453,8 @@ void R_Clutter_Emit(batch_t **batches)
if (!b)
return;
memset(b, 0, sizeof(*b));
for (j = 0; j < MAXRLIGHTMAPS; j++)
b->lightmap[j] = -1;
b->ent = &r_worldentity;
b->meshes = 1;
b->mesh = &sect->soups[i].pmesh;

View file

@ -358,6 +358,7 @@ cvar_t dpcompat_psa_ungroup = SCVAR ("dpcompat_psa_ungroup", "0");
cvar_t r_noaliasshadows = SCVARF ("r_noaliasshadows", "0", CVAR_ARCHIVE);
cvar_t r_shadows = CVARFD ("r_shadows", "0", CVAR_ARCHIVE, "Draw basic blob shadows underneath entities without using realtime lighting.");
cvar_t r_showbboxes = CVARD("r_showbboxes", "0", "Debugging. Shows bounding boxes. 1=ssqc, 2=csqc. Red=solid, Green=stepping/toss/bounce, Blue=onground.");
cvar_t r_showfields = CVARD("r_showfields", "0", "Debugging. Shows entity fields boxes (entity closest to crosshair). 1=ssqc, 2=csqc.");
cvar_t r_lightprepass = CVARFD("r_lightprepass", "0", CVAR_SHADERSYSTEM, "Experimental. Attempt to use a different lighting mechanism.");
cvar_t r_shadow_bumpscale_basetexture = CVARD ("r_shadow_bumpscale_basetexture", "0", "bumpyness scaler for generation of fallback normalmap textures from models");
@ -748,6 +749,7 @@ void Renderer_Init(void)
Cvar_Register (&r_replacemodels, GRAPHICALNICETIES);
Cvar_Register (&r_showbboxes, GLRENDEREROPTIONS);
Cvar_Register (&r_showfields, GLRENDEREROPTIONS);
Cvar_Register (&r_polygonoffset_submodel_factor, GLRENDEREROPTIONS);
Cvar_Register (&r_polygonoffset_submodel_offset, GLRENDEREROPTIONS);
Cvar_Register (&r_polygonoffset_shadowmap_factor, GLRENDEREROPTIONS);

View file

@ -26,16 +26,16 @@ extern cvar_t *hud_tracking_show;
#define CON_ALTMASK (CON_2NDCHARSETTEXT|CON_WHITEMASK)
cvar_t scr_scoreboard_drawtitle = SCVAR("scr_scoreboard_drawtitle", "1");
cvar_t scr_scoreboard_forcecolors = SCVAR("scr_scoreboard_forcecolors", "0"); //damn americans
cvar_t scr_scoreboard_newstyle = SCVAR("scr_scoreboard_newstyle", "1"); // New scoreboard style ported from Electro, by Molgrum
cvar_t scr_scoreboard_drawtitle = CVARD("scr_scoreboard_drawtitle", "1", "Wastes screen space when looking at the scoreboard.");
cvar_t scr_scoreboard_forcecolors = CVARD("scr_scoreboard_forcecolors", "0", "Makes the scoreboard colours obey enemycolor/teamcolor rules."); //damn americans
cvar_t scr_scoreboard_newstyle = CVARD("scr_scoreboard_newstyle", "1", "Display team colours and stuff in a style popularised by Electro. Looks more modern, but might not quite fit classic huds."); // New scoreboard style ported from Electro, by Molgrum
cvar_t scr_scoreboard_showfrags = CVARD("scr_scoreboard_showfrags", "0", "Display kills+deaths+teamkills, as determined by fragfile.dat-based conprint parsing. These may be inaccurate if you join mid-game.");
cvar_t scr_scoreboard_showflags = CVARD("scr_scoreboard_showflags", "2", "Display flag caps+touches on the scoreboard, where our fragfile.dat supports them.\n0: off\n1: on\n2: on only if someone appears to have interacted with a flag.");
cvar_t scr_scoreboard_fillalpha = CVAR("scr_scoreboard_fillalpha", "0.7");
cvar_t scr_scoreboard_teamscores = SCVAR("scr_scoreboard_teamscores", "1");
cvar_t scr_scoreboard_teamsort = SCVAR("scr_scoreboard_teamsort", "1");
cvar_t scr_scoreboard_fillalpha = CVARD("scr_scoreboard_fillalpha", "0.7", "Transparency amount for newstyle scoreboard.");
cvar_t scr_scoreboard_teamscores = CVARD("scr_scoreboard_teamscores", "1", "Makes +showscores act as +showteamscores. Because reasons.");
cvar_t scr_scoreboard_teamsort = CVARD("scr_scoreboard_teamsort", "0", "On the scoreboard, sort players by their team BEFORE their personal score.");
cvar_t scr_scoreboard_titleseperator = SCVAR("scr_scoreboard_titleseperator", "1");
cvar_t sbar_teamstatus = SCVAR("sbar_teamstatus", "1");
cvar_t sbar_teamstatus = CVARD("sbar_teamstatus", "1", "Display the last team say from each of your team members just above the sbar area.");
//===========================================
//rogue changed and added defines
@ -2123,7 +2123,7 @@ void Sbar_DrawScoreboard (void)
#ifndef CLIENTONLY
/*no scoreboard in single player (if you want bots, set deathmatch)*/
if (sv.state && !cls.deathmatch && sv.allocated_client_slots == 1)
if (sv.state && sv.allocated_client_slots == 1)
{
return;
}
@ -2757,7 +2757,7 @@ void Sbar_Draw (playerview_t *pv)
// top line
if (sb_lines > 24)
{
if (!cl.spectator || pv->cam_auto == CAM_TRACK)
if (!cl.spectator || pv->cam_state == CAM_WALLCAM || pv->cam_state == CAM_EYECAM)
Sbar_DrawInventory (pv);
else if (cl_sbar.ival)
Sbar_DrawPic (0, -24, 320, 24, sb_scorebar); //make sure we don't get HoM
@ -2770,13 +2770,14 @@ void Sbar_Draw (playerview_t *pv)
{
if (cl.spectator)
{
if (pv->cam_auto != CAM_TRACK)
if (pv->cam_state == CAM_FREECAM || pv->cam_state == CAM_PENDING)
{
if (hud_tracking_show->ival || cl_sbar.ival)
{ //this is annoying.
Sbar_DrawPic (0, 0, 320, 24, sb_scorebar);
Sbar_DrawString (160-7*8,4, "SPECTATOR MODE");
Sbar_DrawString(160-14*8+4, 12, "Press [ATTACK] for AutoCamera");
if (pv->cam_state == CAM_FREECAM)
Sbar_DrawString(160-14*8+4, 12, "Press [ATTACK] for AutoCamera");
}
}
else
@ -2888,7 +2889,7 @@ void Sbar_IntermissionNumber (float x, float y, int num, int digits, int color,
#define COL_TEAM_LOWAVGHIGH COLUMN("low/avg/high", 12*8, {sprintf (num, "%3i/%3i/%3i", plow, pavg, phigh); Draw_FunString ( x, y, num); })
#define COL_TEAM_TEAM COLUMN("team", 4*8, {Draw_FunStringWidth ( x, y, tm->team, 4*8, false, false); \
if (!strncmp(cl.players[pv->playernum].team, tm->team, 16))\
if (!strncmp(cl.players[trackplayer].team, tm->team, 16))\
{\
Draw_FunString ( x - 1*8, y, "^Ue010");\
Draw_FunString ( x + 4*8, y, "^Ue011");\
@ -2920,6 +2921,7 @@ void Sbar_TeamOverlay (void)
int rank_width = 320-32*2;
int startx;
int trackplayer;
if (!pv)
pv = &cl.playerview[0];
@ -2998,6 +3000,11 @@ void Sbar_TeamOverlay (void)
// sort the teams
Sbar_SortTeams(pv);
if (cl.spectator)
trackplayer = Cam_TrackNum(pv);
else
trackplayer = pv->playernum;
// draw the text
for (i=0 ; i < scoreboardteams && y <= vid.height-10 ; i++)
{
@ -3060,7 +3067,7 @@ void Sbar_TeamOverlay (void)
sprintf (num, "%5i", tm->players);
Draw_FunString (x + 104 + 88, y, num);
if (!strncmp(cl.players[cl.playernum[0]].team, tm->team, 16))
if (!strncmp(cl.players[trackplayer].team, tm->team, 16))
{
Draw_FunString ( x + 104 - 8, y, "^Ue010");
Draw_FunString ( x + 104 + 32, y, "^Ue011");
@ -3132,20 +3139,20 @@ ping time frags name
f = s->frags; \
sprintf(num, "%3i",f); \
\
Font_BeginString(font_default, x+8, y, &cx, &cy); \
Font_DrawChar(cx, cy, num[0] | 0xe000 | CON_WHITEMASK); \
Font_BeginString(font_default, x+16, y, &cx, &cy); \
Font_DrawChar(cx, cy, num[1] | 0xe000 | CON_WHITEMASK); \
Font_BeginString(font_default, x+24, y, &cx, &cy); \
Font_DrawChar(cx, cy, num[2] | 0xe000 | CON_WHITEMASK); \
\
if ((cl.spectator && k == Cam_TrackNum(pv)) ||\
(!cl.spectator && k == pv->playernum)) \
{ \
Font_BeginString(font_default, x, y, &cx, &cy); \
Font_DrawChar(cx, cy, 16 | 0xe000 | CON_WHITEMASK); \
Font_BeginString(font_default, x+32, y, &cx, &cy); \
Font_DrawChar(cx, cy, 17 | 0xe000 | CON_WHITEMASK); \
Font_BeginString(font_default, x+8, y, &cx, &cy); \
Font_DrawChar(cx, cy, num[0] | 0xe000 | CON_WHITEMASK); \
Font_BeginString(font_default, x+16, y, &cx, &cy); \
Font_DrawChar(cx, cy, num[1] | 0xe000 | CON_WHITEMASK); \
Font_BeginString(font_default, x+24, y, &cx, &cy); \
Font_DrawChar(cx, cy, num[2] | 0xe000 | CON_WHITEMASK); \
\
if ((pv->cam_state == CAM_FREECAM && k == pv->playernum) || \
(pv->cam_state != CAM_FREECAM && k == pv->cam_spec_track)) \
{ \
Font_BeginString(font_default, x, y, &cx, &cy); \
Font_DrawChar(cx, cy, 16 | 0xe000 | CON_WHITEMASK); \
Font_BeginString(font_default, x+32, y, &cx, &cy); \
Font_DrawChar(cx, cy, 17 | 0xe000 | CON_WHITEMASK); \
} \
Font_EndString(font_default); \
} \
@ -3590,7 +3597,7 @@ static void Sbar_MiniDeathmatchOverlay (playerview_t *pv)
Font_BeginString(font_default, x+24, y, &px, &py);
Font_DrawChar ( px, py, num[2] | 0xe000 | CON_WHITEMASK);
if ((cl.spectator && k == pv->cam_spec_track && pv->cam_locked) ||
if ((cl.spectator && k == pv->cam_spec_track && pv->cam_state != CAM_FREECAM) ||
(!cl.spectator && k == pv->playernum))
{
Font_BeginString(font_default, x, y, &px, &py);

View file

@ -1342,7 +1342,7 @@ void V_CalcRefdef (playerview_t *pv)
viewheight += pv->crouch;
if (pv->stats[STAT_HEALTH] < 0 && (!cl.spectator || pv->cam_locked) && v_deathtilt.value) // PF_GIB will also set PF_DEAD
if (pv->stats[STAT_HEALTH] < 0 && (!cl.spectator || pv->cam_state == CAM_EYECAM) && v_deathtilt.value) // PF_GIB will also set PF_DEAD
{
if (!cl.spectator || cl_chasecam.ival)
r_refdef.viewangles[ROLL] = 80*v_deathtilt.value; // dead view angle
@ -1527,21 +1527,21 @@ void R_DrawNameTags(void)
vec3_t tagcenter;
lerpents_t *le;
extern cvar_t r_showbboxes;
if (r_showbboxes.ival && cls.allow_cheats)
extern cvar_t r_showfields;
if (r_showfields.ival && cls.allow_cheats)
{
world_t *w = NULL;
wedict_t *e;
vec3_t org;
vec3_t screenspace;
vec3_t diff;
if (r_showbboxes.ival == 1)
if ((r_showfields.ival & 3) == 1)
{
#ifndef CLIENTONLY
w = &sv.world;
#endif
}
else if (r_showbboxes.ival == 2)
else if ((r_showfields.ival & 3) == 2)
{
#ifdef CSQC_DAT
extern world_t csqc_world;
@ -1549,34 +1549,55 @@ void R_DrawNameTags(void)
#endif
}
if (w && w->progs)
for (i = 1; i < w->num_edicts; i++)
{
e = WEDICT_NUM(w->progs, i);
if (e->isfree)
continue;
VectorInterpolate(e->v->mins, 0.5, e->v->maxs, org);
VectorAdd(org, e->v->origin, org);
VectorSubtract(org, r_refdef.vieworg, diff);
if (DotProduct(diff, diff) > 256*256)
continue;
if (Matrix4x4_CM_Project(org, screenspace, r_refdef.viewangles, r_refdef.vieworg, r_refdef.fov_x, r_refdef.fov_y))
int best = 0;
float bestscore = 0, score = 0;
for (i = 1; i < w->num_edicts; i++)
{
char asciibuffer[8192];
char *entstr;
int buflen;
int x, y;
sprintf(asciibuffer, "entity %i ", e->entnum);
buflen = strlen(asciibuffer);
entstr = w->progs->saveent(w->progs, asciibuffer, &buflen, sizeof(asciibuffer), (edict_t*)e); //will save just one entities vars
if (entstr)
e = WEDICT_NUM(w->progs, i);
if (e->isfree)
continue;
VectorInterpolate(e->v->mins, 0.5, e->v->maxs, org);
VectorAdd(org, e->v->origin, org);
VectorSubtract(org, r_refdef.vieworg, diff);
if (DotProduct(diff, diff) < 16*16)
continue; //ignore stuff too close(like the player themselves)
VectorNormalize(diff);
score = DotProduct(diff, vpn);// r_refdef.viewaxis[0]);
if (score > bestscore)
{
vec2_t scale = {8,8};
x = screenspace[0]*r_refdef.vrect.width+r_refdef.vrect.x;
y = (1-screenspace[1])*r_refdef.vrect.height+r_refdef.vrect.y;
R_DrawTextField(x, y, vid.width - x, vid.height - y, entstr, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, scale);
vec3_t imp;
if (!TraceLineN(r_refdef.vieworg, org, imp, NULL))
{
best = i;
bestscore = score;
}
}
}
if (best)
{
e = WEDICT_NUM(w->progs, best);
VectorInterpolate(e->v->mins, 0.5, e->v->maxs, org);
VectorAdd(org, e->v->origin, org);
if (Matrix4x4_CM_Project(org, screenspace, r_refdef.viewangles, r_refdef.vieworg, r_refdef.fov_x, r_refdef.fov_y))
{
char asciibuffer[8192];
char *entstr;
int buflen;
int x, y;
sprintf(asciibuffer, "entity %i ", e->entnum);
buflen = strlen(asciibuffer);
entstr = w->progs->saveent(w->progs, asciibuffer, &buflen, sizeof(asciibuffer), (edict_t*)e); //will save just one entities vars
if (entstr)
{
vec2_t scale = {8,8};
x = screenspace[0]*r_refdef.vrect.width+r_refdef.vrect.x;
y = (1-screenspace[1])*r_refdef.vrect.height+r_refdef.vrect.y;
R_DrawTextField(x, y, vid.width - x, vid.height - y, entstr, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, scale);
}
}
}
}
}

View file

@ -2025,14 +2025,9 @@ void Cmd_ForwardToServer_f (void)
{
playerview_t *pv = &cl.playerview[CL_TargettedSplit(false)];
if (!*Cmd_Argv(2))
{
Cam_Unlock(pv);
}
else
{
Cam_Lock(pv, atoi(Cmd_Argv(2)));
pv->cam_auto = CAM_TRACK;
}
return;
}

View file

@ -240,7 +240,7 @@ void Netchan_Init (void)
port = ((int)(getpid()+getuid()*1000) * time(NULL)) & 0xffff;
#endif
Q_snprintfz(qportstr, sizeof(qportstr), "%i", port);
qport.string = qportstr;
qport.enginevalue = qportstr;
Cvar_Register (&pext_predinfo, "Protocol Extensions");
Cvar_Register (&pext_replacementdeltas, "Protocol Extensions");

View file

@ -3,13 +3,15 @@
bind mouse1 +attack //left area of the screen
bind mouse2 +jump //right area of the screen
bind menu "toggleconsole"
bind volup +showteamscores
// bind voldown +jump //removed because on most android devices power+voldown takes a screenshot
bind volup inv volume 0.1
bind voldown inv volume -0.1
// Appearance settings
brightness "0.2"
contrast "1.2"
vid_conwidth "0" //make something up based upon aspect ratio
vid_conheight "300" //not using autoscale as it can make the menu unusable.
vid_conautoscale "0" // Text/Menu size. 2 is the default. 4 is bigger

View file

@ -1531,7 +1531,7 @@ void R_GAlias_GenerateBatches(entity_t *e, batch_t **batches)
b->texture = NULL;
b->shader = shader;
for (j = 0; j < MAXRLIGHTMAPS; j++)
b->lightmap[0] = -1;
b->lightmap[j] = -1;
b->surf_first = surfnum;
b->flags = 0;
sort = shader->sort;
@ -1637,7 +1637,8 @@ void R_Sprite_GenerateBatches(entity_t *e, batch_t **batches)
b->skin = frame-;
b->texture = NULL;
b->shader = frame->shader;
b->lightmap = -1;
for (j = 0; j < MAXRLIGHTMAPS; j++)
b->lightmap[j] = -1;
b->surf_first = surfnum;
b->flags = 0;
b->vbo = NULL;

View file

@ -4461,6 +4461,7 @@ static void GLBE_SubmitMeshesPortals(batch_t **worldlist, batch_t *dynamiclist)
static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
{
batch_t *batch;
shader_t *bs;
for (batch = sortlist; batch; batch = batch->next)
{
if (batch->meshes == batch->firstmesh)
@ -4482,31 +4483,33 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
batch->buildmeshes(batch);
}
TRACE(("GLBE_SubmitMeshesSortList: shader %s\n", batch->shader->name));
bs = batch->shader;
TRACE(("GLBE_SubmitMeshesSortList: shader %s\n", bs->name));
//FIXME:!!
if (!batch->shader)
if (!bs)
{
Con_Printf("Shader not set...\n");
if (batch->texture)
batch->shader = R_TextureAnimation(0, batch->texture)->shader;
bs = R_TextureAnimation(0, batch->texture)->shader;
else
continue;
}
if (batch->shader->flags & SHADER_NODRAW)
if (bs->flags & SHADER_NODRAW)
continue;
if (batch->shader->flags & SHADER_NODLIGHT)
if (bs->flags & SHADER_NODLIGHT)
if (shaderstate.mode == BEM_LIGHT)
continue;
if (batch->shader->flags & SHADER_NOSHADOWS)
if (bs->flags & SHADER_NOSHADOWS)
if (shaderstate.mode == BEM_STENCIL || shaderstate.mode == BEM_DEPTHONLY) //fixme: depthonly is not just shadows.
continue;
if (batch->shader->flags & SHADER_SKY)
if (bs->flags & SHADER_SKY)
{
if (shaderstate.mode == BEM_STANDARD || shaderstate.mode == BEM_DEPTHDARK)// || shaderstate.mode == BEM_WIREFRAME)
{
if (!batch->shader->prog)
if (!bs->prog)
{
R_DrawSkyChain (batch);
continue;
@ -4516,7 +4519,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
continue;
}
if ((batch->shader->flags & (SHADER_HASREFLECT | SHADER_HASREFRACT | SHADER_HASRIPPLEMAP)) && shaderstate.mode != BEM_WIREFRAME)
if ((bs->flags & (SHADER_HASREFLECT | SHADER_HASREFRACT | SHADER_HASRIPPLEMAP)) && shaderstate.mode != BEM_WIREFRAME)
{
int oldfbo;
float oldil;
@ -4529,7 +4532,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
oldbem = shaderstate.mode;
oldil = shaderstate.identitylighting;
if ((batch->shader->flags & SHADER_HASREFLECT) && gl_config.ext_framebuffer_objects)
if ((bs->flags & SHADER_HASREFLECT) && gl_config.ext_framebuffer_objects)
{
vrect_t orect = r_refdef.vrect;
pxrect_t oprect = r_refdef.pxrect;
@ -4571,7 +4574,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
r_refdef.pxrect = oprect;
GL_ViewportUpdate();
}
if (batch->shader->flags & (SHADER_HASREFRACT|SHADER_HASREFRACTDEPTH))
if (bs->flags & (SHADER_HASREFRACT|SHADER_HASREFRACTDEPTH))
{
if (r_refract_fboival)
{
@ -4603,7 +4606,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
if (batch->shader->flags & SHADER_HASREFRACTDEPTH)
if (bs->flags & SHADER_HASREFRACTDEPTH)
{
if (!shaderstate.tex_refractiondepth)
{
@ -4634,7 +4637,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
GL_ForceDepthWritable();
qglClearColor(0, 0, 0, 1);
qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GLR_DrawPortal(batch, cl.worldmodel->batches, NULL, ((batch->shader->flags & SHADER_HASREFRACTDEPTH)?3:2)); //fixme
GLR_DrawPortal(batch, cl.worldmodel->batches, NULL, ((bs->flags & SHADER_HASREFRACTDEPTH)?3:2)); //fixme
GLBE_FBO_Pop(oldfbo);
r_refdef.vrect = ovrect;
@ -4644,7 +4647,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
else
GLR_DrawPortal(batch, cl.worldmodel->batches, NULL, 3);
}
if ((batch->shader->flags & SHADER_HASRIPPLEMAP) && gl_config.ext_framebuffer_objects)
if ((bs->flags & SHADER_HASRIPPLEMAP) && gl_config.ext_framebuffer_objects)
{
vrect_t orect = r_refdef.vrect;
pxrect_t oprect = r_refdef.pxrect;
@ -5324,19 +5327,19 @@ void GLBE_DrawWorld (qboolean drawworld, qbyte *vis)
RSpeedRemark();
GLBE_SubmitMeshes(true, SHADER_SORT_PORTAL, SHADER_SORT_DECAL);
RSpeedEnd(RSPEED_WORLD);
}
#ifdef RTLIGHTS
if (drawworld)
{
RSpeedRemark();
TRACE(("GLBE_DrawWorld: drawing lights\n"));
GLBE_SelectEntity(&r_worldentity);
Sh_DrawLights(vis);
RSpeedEnd(RSPEED_STENCILSHADOWS);
TRACE(("GLBE_DrawWorld: lights drawn\n"));
}
if (drawworld)
{
RSpeedRemark();
TRACE(("GLBE_DrawWorld: drawing lights\n"));
GLBE_SelectEntity(&r_worldentity);
Sh_DrawLights(vis);
RSpeedEnd(RSPEED_STENCILSHADOWS);
TRACE(("GLBE_DrawWorld: lights drawn\n"));
}
#endif
}
shaderstate.identitylighting = 1;

View file

@ -663,11 +663,18 @@ static hmsection_t *Terr_GenerateSection(heightmap_t *hm, int sx, int sy, qboole
s->loadstate = TSLS_LOADING1;
if (scheduleload)
COM_AddWork(1, Terr_LoadSectionWorker, s, hm, sx, sy);
}
if (!scheduleload)
return s;
#ifdef LOADERTHREAD
Sys_UnlockMutex(com_resourcemutex);
Sys_UnlockMutex(com_resourcemutex);
#endif
COM_AddWork(1, Terr_LoadSectionWorker, s, hm, sx, sy);
return s;
}
if (scheduleload)
#ifdef LOADERTHREAD
Sys_UnlockMutex(com_resourcemutex);
#endif
return s;
}
@ -1666,13 +1673,24 @@ static void Terr_LoadSectionWorker(void *ctx, void *data, size_t a, size_t b)
{
//noload avoids recursion.
s = Terr_GenerateSection(hm, sx+x, sy+y, false);
if (s->loadstate == TSLS_LOADING1)
if (s)
{
offset = block->offset[x + y*SECTIONSPERBLOCK];
if (!offset)
Terr_ReadSection(hm, s, ver, NULL, 0); //no data in the file for this section
if (s->loadstate == TSLS_LOADING1)
{
s->loadstate = TSLS_LOADING1;
#ifdef LOADERTHREAD
Sys_UnlockMutex(com_resourcemutex);
#endif
offset = block->offset[x + y*SECTIONSPERBLOCK];
if (!offset)
Terr_ReadSection(hm, s, ver, NULL, 0); //no data in the file for this section
else
Terr_ReadSection(hm, s, ver, (char*)diskimage + offset, len - offset);
}
#ifdef LOADERTHREAD
else
Terr_ReadSection(hm, s, ver, (char*)diskimage + offset, len - offset);
Sys_UnlockMutex(com_resourcemutex);
#endif
}
}
}

View file

@ -719,10 +719,8 @@ void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches)
b->skin = &shader->defaulttextures;
b->texture = NULL;
b->shader = shader;
b->lightmap[0] = -1;
b->lightmap[1] = -1;
b->lightmap[2] = -1;
b->lightmap[3] = -1;
for (j = 0; j < MAXRLIGHTMAPS; j++)
b->lightmap[j] = -1;
b->surf_first = batchid;
b->flags = 0;
sort = shader->sort;

View file

@ -3004,6 +3004,8 @@ void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *cli
state->solid |= i<<5;
i = bound(0, ((ent->v->maxs[2]+32)/8), 63); /*up can be negative*/
state->solid |= i<<10;
if (state->solid == 4096)
state->solid = 0; //point sized stuff should just be non-solid. you'll thank me for splitscreens.
}
}
else

View file

@ -41,6 +41,8 @@ extern cvar_t *cl_multiview;
#define Cam_TrackNum() cl.tracknum
#define spec_track cl.tracknum
#define autocam ((spec_track==-1)?CAM_NONE:CAM_TRACK)
#define CAM_TRACK true
#define CAM_NONE false
//#define HAXX
#define vid plugvid

View file

@ -577,11 +577,17 @@ void SCR_HUD_DrawTracking(hud_t *hud)
height *= hud_tracking_scale->value;
width *= hud_tracking_scale->value;
if (!(cl.spectator && autocam == CAM_TRACK))
height = 0;
if(!HUD_PrepareDraw(hud, width, height, &x, &y))
{
return;
}
if (height == 0)
return;
#ifdef HAXX
if (cls.mvdplayback && cl_multiview->value && autocam == CAM_TRACK)
{