1077 lines
27 KiB
C
1077 lines
27 KiB
C
/*****************************************************************
|
|
|
|
Cam Client source code - by Paul Jordan, updated by Acrid-
|
|
|
|
..............................................................
|
|
|
|
This file is Copyright(c) 1998, Paul Jordan, All Rights Reserved.
|
|
|
|
..............................................................
|
|
|
|
All other files are Copyright(c) Id Software, Inc.
|
|
|
|
Please see liscense.txt in the source directory for the copyright
|
|
information regarding those files belonging to Id Software, Inc.
|
|
|
|
..............................................................
|
|
|
|
Should you decide to release a modified version of the Camera, you
|
|
MUST include the following text (minus the BEGIN and END lines) in
|
|
the documentation for your modification, and also on all web pages
|
|
related to your modification, should they exist.
|
|
|
|
--- BEGIN ---
|
|
|
|
The Client Camera is a product of Paul Jordan, and is available from
|
|
the Quake2 Camera homepage at http://www.prismnet.com/~jordan/q2cam,
|
|
Or as part of the Eraser Bot at http://impact.frag.com.
|
|
|
|
This program is a modification of the Quake2 Client Camera, and is
|
|
therefore in NO WAY supported by Paul.
|
|
|
|
This program MUST NOT be sold in ANY form. If you have paid for
|
|
this product, you should contact Paul Jordan immediately, via
|
|
the Quake2 Camera Client homepage.
|
|
|
|
--- END ---
|
|
|
|
Adios and have fun,
|
|
|
|
Paul Jordan
|
|
|
|
*****************************************************************/
|
|
|
|
|
|
/* camclient.c */
|
|
|
|
#include "g_local.h"
|
|
#include "camclient.h"
|
|
#include "extra.h"
|
|
|
|
|
|
|
|
enum {
|
|
CAM_FOLLOW_MODE,
|
|
CAM_NORMAL_MODE};
|
|
|
|
#define DAMP_ANGLE_Y 6
|
|
#define DAMP_VALUE_XY 6
|
|
#define DAMP_VALUE_Z 3
|
|
|
|
|
|
sPlayerList *EntityListHead();
|
|
void CameraStaticThink(edict_t *ent, usercmd_t *ucmd);
|
|
|
|
//K2
|
|
void botAddPlayer(edict_t *ent);
|
|
void botRemovePlayer(edict_t *ent);
|
|
void ClientBegin (edict_t *ent);//acrid 3/99
|
|
//K2
|
|
|
|
edict_t
|
|
*pDeadPlayer=NULL;
|
|
|
|
int
|
|
CameraCmd(edict_t *ent, char *arg)
|
|
{
|
|
double
|
|
fTemp;
|
|
|
|
|
|
if ( Q_stricmp(arg, "on") == 0)
|
|
{
|
|
//K2: If client is not already in server, no cam mode
|
|
if(!ent->client->resp.inServer)
|
|
{
|
|
// if(ctf->value)
|
|
// CTFJoinTeam1(ent,NULL);
|
|
// else
|
|
// K2EnterGame(ent,NULL);
|
|
|
|
}
|
|
|
|
// clear entity values
|
|
ent->groundentity = NULL;
|
|
ent->takedamage = DAMAGE_NO;
|
|
ent->movetype = MOVETYPE_FLY;
|
|
ent->viewheight = 0;
|
|
ent->classname = "camera";
|
|
ent->mass = 0;
|
|
ent->solid = SOLID_NOT;
|
|
ent->deadflag = DEAD_NO;
|
|
ent->clipmask = MASK_ALL;
|
|
ent->model = "";
|
|
ent->waterlevel = 0;
|
|
ent->watertype = 0;
|
|
ent->flags = FL_FLY;// | FL_GODMODE;
|
|
ent->client->bIsCamera = 1;
|
|
|
|
ent->client->ps.fov = 90;
|
|
ent->client->iMode = CAM_FOLLOW_MODE;
|
|
ent->client->bWatchingTheDead = FALSE;
|
|
ent->client->fXYLag = DAMP_VALUE_XY;
|
|
ent->client->fZLag = DAMP_VALUE_Z;
|
|
ent->client->fAngleLag = DAMP_ANGLE_Y;
|
|
|
|
// Ridah, clear the view
|
|
ent->client->pers.weapon = NULL;
|
|
ent->client->ps.gunindex = 0;
|
|
ent->client->resp.ctf_team = CTF_NOTEAM;
|
|
ent->client->pers.player_class = 0; //5/99 for g_cmds
|
|
memset(ent->client->ps.stats, 0, sizeof(ent->client->ps.stats));
|
|
|
|
// CTFPlayerResetGrapple(ent);
|
|
CTFPlayerResetGrapple2(ent);//newgrap 4/99
|
|
CTFDeadDropFlag(ent);
|
|
CTFDeadDropTech(ent);
|
|
// Ridah, done.
|
|
|
|
// clear entity state values
|
|
ent->s.effects = 0;
|
|
ent->s.skinnum = 0;//ent - g_edicts - 1;
|
|
ent->s.modelindex = 0;//255; // will use the skin specified model
|
|
ent->s.modelindex2 = 0;//255; // custom gun model
|
|
ent->s.frame = 0;
|
|
|
|
ent->s.angles[PITCH] = 0;
|
|
ent->s.angles[YAW] = 0;
|
|
ent->s.angles[ROLL] = 0;
|
|
VectorCopy (ent->s.angles, ent->client->ps.viewangles);
|
|
VectorCopy (ent->s.angles, ent->client->v_angle);
|
|
|
|
ent->client->showscores = false;
|
|
ent->client->showinventory = false;
|
|
ent->client->pers.hand = CENTER_HANDED;
|
|
ent->client->ps.stats[STAT_HELPICON] = 0;
|
|
|
|
//K2
|
|
ent->client->resp.inServer=false;
|
|
botRemovePlayer(ent);
|
|
//K2
|
|
|
|
return true;
|
|
}
|
|
//K2:Begin - Add cam off command
|
|
else if (Q_stricmp(arg, "off") == 0)
|
|
{
|
|
if(!ent->client->bIsCamera)
|
|
return false;
|
|
|
|
ent->client->bIsCamera = false;
|
|
ClientBegin (ent);
|
|
return true;
|
|
|
|
}
|
|
//K2:End
|
|
else if (ent->classname[0] != 'c')
|
|
{ // not already in CAM mode, so don't go any further
|
|
return false;
|
|
}
|
|
else if ( Q_stricmp(arg, "follow") == 0)
|
|
{
|
|
ent->client->iMode = CAM_FOLLOW_MODE;
|
|
}
|
|
else if ( Q_stricmp(arg, "normal") == 0)
|
|
{
|
|
ent->client->iMode = CAM_NORMAL_MODE;
|
|
}
|
|
else if (( Q_stricmp(arg, "min_xy") == 0) && ent->client->bIsCamera)
|
|
{
|
|
if ((fTemp = atof(arg)) < 1)
|
|
{
|
|
safe_cprintf (ent, PRINT_HIGH, "Min X/Y delta of %f unchanged!\n",ent->client->fXYLag);
|
|
}
|
|
else
|
|
{
|
|
ent->client->fXYLag = fTemp;
|
|
safe_cprintf (ent, PRINT_HIGH, "Min X/Y delta of %f. set.\n",ent->client->fXYLag);
|
|
}
|
|
}
|
|
else if (( Q_stricmp(arg, "min_z") == 0) && ent->client->bIsCamera)
|
|
{
|
|
if ((fTemp = atof(arg)) < 1)
|
|
{
|
|
safe_cprintf (ent, PRINT_HIGH, "Min Z delta of %f unchanged!\n",ent->client->fZLag);
|
|
}
|
|
else
|
|
{
|
|
ent->client->fZLag = fTemp;
|
|
safe_cprintf (ent, PRINT_HIGH, "Min Z delta of %f set.\n",ent->client->fZLag);
|
|
}
|
|
}
|
|
else if (( Q_stricmp(arg, "min_angle") == 0) && ent->client->bIsCamera)
|
|
{
|
|
if ((fTemp = atof(arg)) < 1)
|
|
{
|
|
safe_cprintf (ent, PRINT_HIGH, "Min Yaw Angle delta of %f unchanged!\n",ent->client->fAngleLag);
|
|
}
|
|
else
|
|
{
|
|
ent->client->fAngleLag = fTemp;
|
|
safe_cprintf (ent, PRINT_HIGH, "Min Yaw Angle delta of %f set.\n",ent->client->fAngleLag);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void
|
|
PlayerDied(edict_t *pPlayer)
|
|
{
|
|
if ( pPlayer->client )
|
|
{
|
|
pDeadPlayer = pPlayer;
|
|
}
|
|
}
|
|
|
|
qboolean
|
|
IsVisible(edict_t *pPlayer1, edict_t *pPlayer2)
|
|
{
|
|
vec3_t
|
|
vLength;
|
|
int
|
|
distance;
|
|
trace_t
|
|
trace;
|
|
|
|
// Ridah, added this so se check for looking through non-transparent water
|
|
if (!gi.inPVS(pPlayer1->s.origin, pPlayer2->s.origin))
|
|
return FALSE;
|
|
// done.
|
|
|
|
trace = gi.trace (pPlayer1->s.origin, vec3_origin, vec3_origin, pPlayer2->s.origin, pPlayer1, MASK_SOLID);
|
|
|
|
vLength[0] = pPlayer1->s.origin[0] - pPlayer2->s.origin[0];
|
|
vLength[1] = pPlayer1->s.origin[1] - pPlayer2->s.origin[1];
|
|
vLength[2] = pPlayer1->s.origin[2] - pPlayer2->s.origin[2];
|
|
distance = VectorLength(vLength);
|
|
|
|
if ((distance < MAX_VISIBLE_RANGE) &&
|
|
(trace.fraction == 1.0))
|
|
{
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
//============================================================================
|
|
//============================================================================
|
|
int
|
|
NumPlayersVisible(edict_t *pViewer)
|
|
{
|
|
int
|
|
iCount=0;
|
|
sPlayerList
|
|
*pTarget;
|
|
|
|
for ( pTarget = EntityListHead();
|
|
pTarget != NULL;
|
|
pTarget=pTarget->pNext)
|
|
{
|
|
// if ((!pTarget->pEntity->deadflag) &&
|
|
if (!pTarget->pEntity->client->bIsCamera)
|
|
{
|
|
if (IsVisible(pTarget->pEntity, pViewer))
|
|
{
|
|
iCount++;
|
|
|
|
// Ridah, added this so we follow the flag carrier if visible
|
|
if ( (pTarget->pEntity->s.effects & (EF_FLAG1 | EF_FLAG2))
|
|
&& (!pViewer->client->pTarget || !(pViewer->client->pTarget->s.effects & (EF_FLAG1 | EF_FLAG2))))
|
|
{ // view this person instead
|
|
pViewer->client->pTarget = pTarget->pEntity;
|
|
}
|
|
// Ridah, done.
|
|
}
|
|
}
|
|
}
|
|
return iCount;
|
|
}
|
|
|
|
edict_t *
|
|
ClosestVisible(edict_t *ent)
|
|
{
|
|
vec3_t
|
|
vDistance;
|
|
sPlayerList
|
|
*pTarget,
|
|
*pBest=NULL;
|
|
unsigned int
|
|
iCurrent,
|
|
iClosest=0xffffffff;
|
|
|
|
for ( pTarget = EntityListHead();
|
|
pTarget != NULL;
|
|
pTarget = pTarget->pNext)
|
|
{
|
|
if (!pTarget->pEntity->client->bIsCamera &&
|
|
IsVisible(pTarget->pEntity, ent))
|
|
{
|
|
VectorSubtract(pTarget->pEntity->s.origin, ent->s.origin, vDistance);
|
|
iCurrent = VectorLength(vDistance);
|
|
if (iCurrent < iClosest)
|
|
{
|
|
pBest = pTarget;
|
|
iClosest = iCurrent;
|
|
}
|
|
}
|
|
}
|
|
if (pBest == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
return pBest->pEntity;
|
|
}
|
|
//============================================================================
|
|
//============================================================================
|
|
edict_t *
|
|
PlayerToFollow()
|
|
{
|
|
sPlayerList
|
|
*pViewer,
|
|
*pBest=NULL;
|
|
int
|
|
iPlayers,
|
|
iBestCount=0;
|
|
|
|
for ( pViewer = EntityListHead();
|
|
pViewer != NULL;
|
|
pViewer = pViewer->pNext)
|
|
{
|
|
iPlayers = 0;
|
|
//
|
|
// Don't switch to dead people
|
|
//
|
|
if ( (!pViewer->pEntity->deadflag) &&
|
|
(!pViewer->pEntity->client->bIsCamera)
|
|
//K2:Not observers
|
|
&& (pViewer->pEntity->client->resp.inServer)
|
|
)
|
|
{
|
|
iPlayers = NumPlayersVisible(pViewer->pEntity);
|
|
if (iPlayers > iBestCount)
|
|
{
|
|
iBestCount = iPlayers;
|
|
pBest = pViewer;
|
|
}
|
|
else if ((iPlayers != 0) && (iPlayers == iBestCount) )
|
|
{
|
|
if (pBest->pEntity->client->resp.score <
|
|
pViewer->pEntity->client->resp.score)
|
|
{
|
|
pBest = pViewer;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (pBest == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
return pBest->pEntity;
|
|
}
|
|
|
|
|
|
//============================================================================
|
|
//============================================================================
|
|
void
|
|
CameraAloneThink(edict_t *ent, usercmd_t *ucmd)
|
|
{
|
|
CameraStaticThink(ent, ucmd);
|
|
}
|
|
|
|
//============================================================================
|
|
//============================================================================
|
|
void
|
|
PointCamAtOrigin(edict_t *ent, vec3_t vLocation)
|
|
{
|
|
vec3_t
|
|
vDiff,
|
|
vAngles;
|
|
|
|
VectorSubtract(vLocation,ent->s.origin,vDiff);
|
|
|
|
|
|
vectoangles(vDiff, vAngles);
|
|
|
|
VectorCopy (vAngles, ent->s.angles);
|
|
VectorCopy (vAngles, ent->client->ps.viewangles);
|
|
VectorCopy (vAngles, ent->client->v_angle);
|
|
}
|
|
|
|
//============================================================================
|
|
//============================================================================
|
|
void
|
|
PointCamAtTarget(edict_t *ent)
|
|
{
|
|
vec3_t
|
|
vDiff,
|
|
vAngles;
|
|
float
|
|
fDifference;
|
|
|
|
VectorSubtract(ent->client->pTarget->s.origin,ent->s.origin,vDiff);
|
|
|
|
vectoangles(vDiff, vAngles);
|
|
|
|
ent->s.angles[0] = vAngles[0];
|
|
ent->s.angles[2] = 0;
|
|
fDifference = vAngles[1] - ent->s.angles[1];
|
|
|
|
while (abs(fDifference) > 180)
|
|
{
|
|
if (fDifference > 0)
|
|
{
|
|
fDifference -= 360;
|
|
}
|
|
else
|
|
{
|
|
fDifference += 360;
|
|
}
|
|
}
|
|
|
|
if (abs(fDifference) > ent->client->fAngleLag)
|
|
{
|
|
if (fDifference > 0)
|
|
{
|
|
ent->s.angles[1] += ent->client->fAngleLag;
|
|
}
|
|
else
|
|
{
|
|
ent->s.angles[1] -= ent->client->fAngleLag;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ent->s.angles[1] = vAngles[1];
|
|
}
|
|
|
|
VectorCopy (ent->s.angles, ent->client->ps.viewangles);
|
|
VectorCopy (ent->s.angles, ent->client->v_angle);
|
|
}
|
|
|
|
//============================================================================
|
|
//============================================================================
|
|
void
|
|
RepositionAtTarget(edict_t *ent, vec3_t vOffsetPosition)
|
|
{
|
|
vec3_t
|
|
vDiff;
|
|
// vAngles;
|
|
vec3_t
|
|
vCamPos,
|
|
forward;//, up;
|
|
|
|
trace_t
|
|
trace;
|
|
|
|
AngleVectors(ent->client->pTarget->client->v_angle, forward, NULL,NULL);
|
|
forward[2] = 0;
|
|
|
|
VectorNormalize(forward);
|
|
|
|
vCamPos[0] = ent->client->pTarget->s.origin[0] +
|
|
(vOffsetPosition[0] * forward[0]);
|
|
|
|
vCamPos[1] = ent->client->pTarget->s.origin[1] +
|
|
(vOffsetPosition[1] * forward[1]);
|
|
|
|
vCamPos[2] = ent->client->pTarget->s.origin[2] +
|
|
vOffsetPosition[2];
|
|
|
|
trace = gi.trace( ent->client->pTarget->s.origin, NULL, NULL, vCamPos,
|
|
ent->client->pTarget, CONTENTS_SOLID);
|
|
|
|
// Ridah, changed this, so we are moved away from the intersection point
|
|
if (trace.fraction < 1)
|
|
{
|
|
VectorSubtract(trace.endpos, ent->client->pTarget->s.origin, vDiff);
|
|
VectorNormalize(vDiff);
|
|
VectorMA(trace.endpos, -8, vDiff, trace.endpos);
|
|
|
|
if (trace.plane.normal[2] > 0.8)
|
|
trace.endpos[2] += 4;
|
|
/*
|
|
trace.endpos[0] += (5 * forward[0]);
|
|
trace.endpos[1] += (5 * forward[1]);
|
|
trace.endpos[2] -= 5;
|
|
*/
|
|
}
|
|
// Ridah , done.
|
|
|
|
if (abs(trace.endpos[0]-ent->s.origin[0]) > ent->client->fXYLag)
|
|
{
|
|
if (trace.endpos[0] > ent->s.origin[0])
|
|
{
|
|
ent->s.origin[0] += ent->client->fXYLag;
|
|
}
|
|
else
|
|
{
|
|
ent->s.origin[0] -= ent->client->fXYLag;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ent->s.origin[0] = trace.endpos[0];
|
|
}
|
|
|
|
if (abs(trace.endpos[1]-ent->s.origin[1]) > ent->client->fXYLag)
|
|
{
|
|
if (trace.endpos[1] > ent->s.origin[1])
|
|
{
|
|
ent->s.origin[1] += ent->client->fXYLag;
|
|
}
|
|
else
|
|
{
|
|
ent->s.origin[1] -= ent->client->fXYLag;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ent->s.origin[1] = trace.endpos[1];
|
|
}
|
|
|
|
if (abs(trace.endpos[2]-ent->s.origin[2]) > ent->client->fZLag)
|
|
{
|
|
if (trace.endpos[2] > ent->s.origin[2])
|
|
{
|
|
ent->s.origin[2] += ent->client->fZLag;
|
|
}
|
|
else
|
|
{
|
|
ent->s.origin[2] -= ent->client->fZLag;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ent->s.origin[2] = trace.endpos[2];
|
|
}
|
|
|
|
trace = gi.trace( ent->client->pTarget->s.origin, NULL, NULL, ent->s.origin,
|
|
ent->client->pTarget, CONTENTS_SOLID);
|
|
|
|
// Ridah, changed this, so we are moved away from the intersection point
|
|
if (trace.fraction < 1)
|
|
{
|
|
VectorSubtract(trace.endpos, ent->client->pTarget->s.origin, vDiff);
|
|
VectorNormalize(vDiff);
|
|
VectorMA(trace.endpos, -8, vDiff, trace.endpos);
|
|
|
|
if (trace.plane.normal[2] > 0.8)
|
|
trace.endpos[2] += 4;
|
|
|
|
VectorCopy(trace.endpos, ent->s.origin);
|
|
}
|
|
/*
|
|
if (trace.fraction != 1)
|
|
{
|
|
|
|
VectorSubtract(ent->client->pTarget->s.origin,ent->s.origin,vDiff);
|
|
|
|
vectoangles(vDiff, vAngles);
|
|
|
|
AngleVectors(vAngles, forward, NULL,NULL);
|
|
|
|
forward[2] = 0;
|
|
|
|
VectorNormalize(forward);
|
|
|
|
trace.endpos[0] += (5 * forward[0]);
|
|
trace.endpos[1] += (5 * forward[1]);
|
|
trace.endpos[2] -= 5;
|
|
VectorCopy(trace.endpos, ent->s.origin);
|
|
}
|
|
*/
|
|
// Ridah , done.
|
|
}
|
|
|
|
//============================================================================
|
|
//============================================================================
|
|
void
|
|
RepositionAtOrigin(edict_t *ent, vec3_t vOffsetPosition)
|
|
{
|
|
vec3_t
|
|
vCamPos;
|
|
|
|
trace_t
|
|
trace;
|
|
|
|
vCamPos[0] = vOffsetPosition[0] + 40;
|
|
|
|
vCamPos[1] = vOffsetPosition[1] + 40;
|
|
|
|
vCamPos[2] = vOffsetPosition[2] + 30;
|
|
|
|
trace = gi.trace( vOffsetPosition, NULL, NULL, vCamPos,
|
|
ent->client->pTarget, CONTENTS_SOLID);
|
|
|
|
// Ridah, added this, so we are moved away from the intersection point
|
|
if (trace.fraction < 1)
|
|
{
|
|
vec3_t vDiff;
|
|
|
|
VectorSubtract(trace.endpos, vOffsetPosition, vDiff);
|
|
VectorNormalize(vDiff);
|
|
VectorMA(trace.endpos, -8, vDiff, trace.endpos);
|
|
|
|
if (trace.plane.normal[2] > 0.8)
|
|
trace.endpos[2] += 4;
|
|
}
|
|
// Ridah, done.
|
|
|
|
if (abs(trace.endpos[0]-ent->s.origin[0]) > ent->client->fXYLag)
|
|
{
|
|
if (trace.endpos[0] > ent->s.origin[0])
|
|
{
|
|
ent->s.origin[0] += ent->client->fXYLag;
|
|
}
|
|
else
|
|
{
|
|
ent->s.origin[0] -= ent->client->fXYLag;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ent->s.origin[0] = trace.endpos[0];
|
|
}
|
|
|
|
if (abs(trace.endpos[1]-ent->s.origin[1]) > ent->client->fXYLag)
|
|
{
|
|
if (trace.endpos[1] > ent->s.origin[1])
|
|
{
|
|
ent->s.origin[1] += ent->client->fXYLag;
|
|
}
|
|
else
|
|
{
|
|
ent->s.origin[1] -= ent->client->fXYLag;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ent->s.origin[1] = trace.endpos[1];
|
|
}
|
|
|
|
if (abs(trace.endpos[2]-ent->s.origin[2]) > ent->client->fZLag)
|
|
{
|
|
if (trace.endpos[2] > ent->s.origin[2])
|
|
{
|
|
ent->s.origin[2] += ent->client->fZLag;
|
|
}
|
|
else
|
|
{
|
|
ent->s.origin[2] -= ent->client->fZLag;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ent->s.origin[2] = trace.endpos[2];
|
|
}
|
|
|
|
trace = gi.trace( vOffsetPosition, NULL, NULL, ent->s.origin,
|
|
ent->client->pTarget, CONTENTS_SOLID);
|
|
|
|
// Ridah, added this, so we are moved away from the intersection point
|
|
if (trace.fraction < 1)
|
|
{
|
|
vec3_t vDiff;
|
|
|
|
VectorSubtract(trace.endpos, vOffsetPosition, vDiff);
|
|
VectorNormalize(vDiff);
|
|
VectorMA(trace.endpos, -8, vDiff, trace.endpos);
|
|
|
|
if (trace.plane.normal[2] > 0.8)
|
|
trace.endpos[2] += 4;
|
|
}
|
|
// Ridah, done.
|
|
|
|
if (trace.fraction != 1)
|
|
{
|
|
VectorCopy(trace.endpos, ent->s.origin);
|
|
}
|
|
}
|
|
void
|
|
UpdateValues(edict_t *ent)
|
|
{
|
|
edict_t
|
|
*pTarget;
|
|
|
|
pTarget = ent->client->pTarget;
|
|
|
|
if (pTarget != NULL)
|
|
{
|
|
// ent->client->resp.score = pTarget->client->resp.score;
|
|
// ent->health = pTarget->health;
|
|
// ent->client->ammo_index = pTarget->client->ammo_index;
|
|
// ent->client->pers.inventory[ent->client->ammo_index] =
|
|
// pTarget->client->pers.inventory[ent->client->ammo_index];
|
|
}
|
|
else
|
|
{
|
|
ent->client->resp.score = 0;
|
|
ent->health = 0;
|
|
}
|
|
}
|
|
|
|
|
|
//============================================================================
|
|
//============================================================================
|
|
void
|
|
CameraFollowThink(edict_t *ent, usercmd_t *ucmd)
|
|
{
|
|
vec3_t
|
|
vCameraOffset;
|
|
// Ridah, changed this so we keep tracking the same player until a new player is selected
|
|
if (ent->client->pTarget || (ent->client->pTarget = PlayerToFollow(ent)) != NULL)
|
|
{
|
|
//
|
|
// Just keep looking for action!
|
|
//
|
|
vCameraOffset[0] = -60;
|
|
vCameraOffset[1] = -60;
|
|
vCameraOffset[2] = 40;
|
|
RepositionAtTarget(ent, vCameraOffset);
|
|
PointCamAtTarget(ent);
|
|
}
|
|
UpdateValues(ent);
|
|
}
|
|
|
|
//============================================================================
|
|
//============================================================================
|
|
void
|
|
CameraNormalThink(edict_t *ent, usercmd_t *ucmd)
|
|
{
|
|
vec3_t
|
|
vCameraOffset;
|
|
int
|
|
iNumVis;
|
|
|
|
iNumVis = NumPlayersVisible(ent);
|
|
|
|
// Ridah, changed this so it only changes when our following target dies
|
|
// if (pDeadPlayer && IsVisible(ent, pDeadPlayer))
|
|
if (!ent->client->bWatchingTheDead && ent->client->pTarget && ent->client->pTarget->deadflag)
|
|
{
|
|
ent->client->bWatchingTheDead = TRUE;
|
|
// ent->client->pTarget = pDeadPlayer;
|
|
ent->last_move_time = level.time + CAMERA_DEAD_SWITCH_TIME;
|
|
PointCamAtTarget(ent);
|
|
}
|
|
else if (ent->client->bWatchingTheDead)
|
|
{
|
|
if (ent->last_move_time < level.time)
|
|
{
|
|
ent->client->bWatchingTheDead = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (ent->client->pTarget->deadflag)
|
|
{
|
|
VectorCopy(ent->client->pTarget->s.origin,ent->client->vDeadOrigin);
|
|
}
|
|
PointCamAtOrigin(ent, ent->client->vDeadOrigin);
|
|
RepositionAtOrigin(ent, ent->client->vDeadOrigin);
|
|
}
|
|
}
|
|
else if ( iNumVis < 2 )
|
|
{
|
|
vCameraOffset[0] = -60;
|
|
vCameraOffset[1] = -60;
|
|
vCameraOffset[2] = 40;
|
|
|
|
if (ent->last_move_time > level.time)
|
|
{
|
|
if (iNumVis > 0)
|
|
{
|
|
//
|
|
// This should always be true but who knows lets check anyway.
|
|
//
|
|
if ((ent->client->pTarget = ClosestVisible(ent)) != NULL)
|
|
{
|
|
RepositionAtTarget(ent, vCameraOffset);
|
|
PointCamAtTarget(ent);
|
|
}
|
|
}
|
|
else if ((ent->client->pTarget = PlayerToFollow()) != NULL)
|
|
{
|
|
//
|
|
// Look for someone new!
|
|
//
|
|
RepositionAtTarget(ent, vCameraOffset);
|
|
PointCamAtTarget(ent);
|
|
ent->last_move_time = 0;
|
|
}
|
|
}
|
|
else if ((ent->client->pTarget = PlayerToFollow(ent)) != NULL)
|
|
{
|
|
//
|
|
// Just keep looking for action!
|
|
//
|
|
vCameraOffset[0] = -60;
|
|
vCameraOffset[1] = -60;
|
|
vCameraOffset[2] = 40;
|
|
RepositionAtTarget(ent, vCameraOffset);
|
|
PointCamAtTarget(ent);
|
|
}
|
|
}
|
|
else if ((ent->last_move_time < level.time) || (ent->client->pTarget && !gi.inPVS(ent->s.origin, ent->client->pTarget->s.origin)))
|
|
{
|
|
if ((ent->client->pTarget = PlayerToFollow()) != NULL)
|
|
{
|
|
vCameraOffset[0] = -60;
|
|
vCameraOffset[1] = -60;
|
|
vCameraOffset[2] = 80;
|
|
PointCamAtTarget(ent);
|
|
RepositionAtTarget(ent, vCameraOffset);
|
|
ent->last_move_time = level.time + CAMERA_SWITCH_TIME;
|
|
}
|
|
}
|
|
else if (ent->client->pTarget != NULL)
|
|
{
|
|
// Ridah, added this to give the camera some movement
|
|
if ( (ent->last_move_time > (level.time + CAMERA_SWITCH_TIME - 3))
|
|
|| (ent->last_move_time < (level.time + 5)))
|
|
{
|
|
RepositionAtOrigin(ent, ent->client->pTarget->s.origin);
|
|
}
|
|
// Ridah, done.
|
|
|
|
PointCamAtTarget(ent);
|
|
}
|
|
|
|
pDeadPlayer = NULL;
|
|
|
|
if (ent->client->pTarget == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UpdateValues(ent);
|
|
}
|
|
|
|
//============================================================================
|
|
//============================================================================
|
|
void
|
|
CameraStaticThink(edict_t *ent, usercmd_t *ucmd)
|
|
{
|
|
trace_t
|
|
trace;
|
|
vec3_t
|
|
vEndFloor,
|
|
vEndCeiling;
|
|
|
|
vEndFloor[0] = ent->s.origin[0];
|
|
vEndFloor[1] = ent->s.origin[1];
|
|
vEndFloor[2] = ent->s.origin[2] - 40000;
|
|
trace = gi.trace( ent->s.origin, NULL, NULL, vEndFloor, ent, CONTENTS_SOLID);
|
|
|
|
VectorCopy ( trace.endpos, vEndFloor );
|
|
|
|
vEndCeiling[0] = vEndFloor[0];
|
|
vEndCeiling[1] = vEndFloor[1];
|
|
vEndCeiling[2] = vEndFloor[2] + 175;
|
|
trace = gi.trace( vEndFloor, NULL, NULL, vEndCeiling, ent, CONTENTS_SOLID);
|
|
|
|
VectorCopy ( trace.endpos, ent->s.origin );
|
|
|
|
if ( ent->last_move_time < level.time )
|
|
{
|
|
ent->last_move_time = level.time + 2;
|
|
ent->s.angles[0] = 45;
|
|
ent->s.angles[1] = 0;
|
|
ent->s.angles[2] = 0;
|
|
VectorCopy (ent->s.angles, ent->client->ps.viewangles);
|
|
VectorCopy (ent->s.angles, ent->client->v_angle);
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//============================================================================
|
|
void
|
|
CameraThink(edict_t *ent, usercmd_t *ucmd)
|
|
{
|
|
// Ridah, added this to cycle through players
|
|
if ((ent->client->pTarget && !ent->client->pTarget->inuse) || ((ucmd->buttons & BUTTON_ATTACK) && !(ent->client->oldbuttons & BUTTON_ATTACK)))
|
|
{
|
|
int count=0;
|
|
sPlayerList *start, *trav;
|
|
|
|
trav = EntityListHead();
|
|
|
|
while (trav && ent->client->pTarget && ent->client->pTarget->inuse && (trav->pEntity != ent->client->pTarget))
|
|
{
|
|
trav = EntityListNext(trav);
|
|
}
|
|
|
|
start = trav;
|
|
|
|
if (!(trav = EntityListNext(trav)))
|
|
trav = EntityListHead();
|
|
|
|
while (!trav->pEntity->solid)
|
|
{
|
|
if (!(trav = EntityListNext(trav)))
|
|
trav = EntityListHead();
|
|
count++;
|
|
|
|
if (count >= maxclients->value)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (count < maxclients->value)
|
|
{
|
|
ent->client->pTarget = trav->pEntity;
|
|
safe_cprintf(ent, PRINT_HIGH, "Now showing %s\n", ent->client->pTarget->client->pers.netname);
|
|
}
|
|
}
|
|
|
|
ent->client->oldbuttons = ucmd->buttons;
|
|
// Ridah, done.
|
|
|
|
ent->client->ps.pmove.pm_type = PM_FREEZE;
|
|
ent->client->ps.pmove.gravity = 0;
|
|
|
|
if (EntityListNumber() == 0)
|
|
{
|
|
CameraAloneThink(ent,ucmd);
|
|
}
|
|
else
|
|
{
|
|
switch (ent->client->iMode)
|
|
{
|
|
case CAM_FOLLOW_MODE:
|
|
CameraFollowThink(ent,ucmd);
|
|
break;
|
|
case CAM_NORMAL_MODE:
|
|
default:
|
|
CameraNormalThink(ent,ucmd);
|
|
break;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
sPlayerList
|
|
*pEntityListHead;
|
|
unsigned long
|
|
ulCount=0;
|
|
|
|
//============================================================================
|
|
//============================================================================
|
|
void
|
|
EntityListRemove(edict_t *pEntity)
|
|
{
|
|
sPlayerList
|
|
*pTrail, *pLead;
|
|
|
|
pTrail = pLead = pEntityListHead;
|
|
|
|
while ( pLead != NULL )
|
|
{
|
|
if (pLead->pEntity->client->bIsCamera)
|
|
{
|
|
//
|
|
// Force rethink on all cameras
|
|
//
|
|
pLead->pEntity->last_move_time = level.time;
|
|
}
|
|
if (pLead->pEntity == pEntity)
|
|
{
|
|
if ( pLead == pTrail)
|
|
{
|
|
pEntityListHead = pLead->pNext;
|
|
|
|
}
|
|
else
|
|
{
|
|
pTrail->pNext = pLead->pNext;
|
|
}
|
|
|
|
free(pLead);
|
|
ulCount--;
|
|
pLead = NULL;
|
|
}
|
|
else
|
|
{
|
|
pTrail = pLead;
|
|
pLead = pLead->pNext;
|
|
}
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//============================================================================
|
|
void
|
|
EntityListAdd(edict_t *pEntity)
|
|
{
|
|
sPlayerList *pNew;
|
|
|
|
pNew = malloc (sizeof(sPlayerList));
|
|
pNew->pEntity = pEntity;
|
|
pNew->pNext = pEntityListHead;
|
|
pEntityListHead = pNew;
|
|
ulCount++;
|
|
}
|
|
|
|
//============================================================================
|
|
//============================================================================
|
|
unsigned long
|
|
EntityListNumber()
|
|
{
|
|
return ulCount;
|
|
}
|
|
|
|
//============================================================================
|
|
//============================================================================
|
|
sPlayerList *
|
|
EntityListHead()
|
|
{
|
|
if (pEntityListHead != NULL)
|
|
{
|
|
return (pEntityListHead);
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
sPlayerList *
|
|
EntityListNext(sPlayerList *pCurrent)
|
|
{
|
|
return(pCurrent->pNext);
|
|
}
|
|
//============================================================================
|
|
//============================================================================
|
|
void
|
|
PrintEntityList()
|
|
{
|
|
sPlayerList
|
|
*pNode;
|
|
|
|
unsigned long ultemp=0;
|
|
gi.dprintf("PrintEntityList\n");
|
|
|
|
for ( pNode = pEntityListHead; pNode != NULL; pNode = pNode->pNext)
|
|
{
|
|
gi.dprintf("Name: %s ",pNode->pEntity->client->pers.netname);
|
|
gi.dprintf("Class: %s\n",pNode->pEntity->classname);
|
|
ultemp++;
|
|
}
|
|
gi.dprintf("Actual Count: %d List Count %d\n",ultemp,EntityListNumber());
|
|
}
|
|
|
|
void
|
|
EnitityListClean()
|
|
{
|
|
sPlayerList
|
|
*pNode;
|
|
|
|
while (NULL != (pNode=EntityListHead()))
|
|
{
|
|
// gi.dprintf("Name: %s\n",pNode->pEntity->client->pers.netname);
|
|
EntityListRemove(pNode->pEntity);
|
|
}
|
|
}
|