mirror of
https://github.com/blendogames/thirtyflightsofloving.git
synced 2024-11-15 08:51:22 +00:00
372 lines
12 KiB
C
372 lines
12 KiB
C
|
#include "g_local.h"
|
||
|
|
||
|
void ChasecamTrack (edict_t *ent);
|
||
|
void ClientUserinfoChanged (edict_t *ent, char *userinfo);
|
||
|
|
||
|
void ChasecamStart (edict_t *ent)
|
||
|
{
|
||
|
edict_t *chasecam;
|
||
|
|
||
|
ent->client->chasetoggle = 1;
|
||
|
ent->client->chaseactive = 1;
|
||
|
ent->client->ps.gunindex = 0;
|
||
|
|
||
|
chasecam = G_Spawn ();
|
||
|
chasecam->owner = ent;
|
||
|
chasecam->solid = SOLID_NOT;
|
||
|
chasecam->movetype = MOVETYPE_FLYMISSILE;
|
||
|
|
||
|
ent->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION;
|
||
|
|
||
|
ent->svflags |= SVF_NOCLIENT;
|
||
|
ent->s.renderfx |= RF_NOSHADOW;
|
||
|
|
||
|
VectorCopy (ent->s.angles, chasecam->s.angles);
|
||
|
VectorClear (chasecam->mins);
|
||
|
VectorClear (chasecam->maxs);
|
||
|
VectorCopy (ent->s.origin, chasecam->s.origin);
|
||
|
|
||
|
chasecam->classname = "chasecam";
|
||
|
chasecam->nextthink = level.time + 0.100;
|
||
|
chasecam->prethink = ChasecamTrack;
|
||
|
|
||
|
ent->client->chasecam = chasecam;
|
||
|
ent->client->oldplayer = G_Spawn();
|
||
|
//Knightmare- mark as oldplayer and pointer to client entity
|
||
|
ent->client->oldplayer->svflags |= SVF_OLDPLAYER;
|
||
|
ent->client->oldplayer->to = ent;
|
||
|
|
||
|
// Lazarus reflections
|
||
|
// remove reflection of real player, if any
|
||
|
DeleteReflection (ent, -1);
|
||
|
}
|
||
|
|
||
|
|
||
|
void ChasecamRemove (edict_t *ent)
|
||
|
{
|
||
|
/* Stop the chasecam from moving */
|
||
|
VectorClear (ent->client->chasecam->velocity);
|
||
|
ent->client->ps.gunindex = gi.modelindex(ent->client->pers.weapon->view_model);
|
||
|
|
||
|
// if (ent->owner->health) ?? SKid
|
||
|
ent->s.modelindex = ent->client->oldplayer->s.modelindex;
|
||
|
ent->s.modelindex2= ent->client->oldplayer->s.modelindex2;
|
||
|
ent->s.modelindex3= ent->client->oldplayer->s.modelindex3;
|
||
|
|
||
|
ent->client->ps.pmove.pm_type &= ~PMF_NO_PREDICTION;
|
||
|
|
||
|
if(!ent->client->resp.spectator)
|
||
|
{
|
||
|
ent->svflags &= ~SVF_NOCLIENT;
|
||
|
ent->s.renderfx &= ~RF_NOSHADOW;
|
||
|
}
|
||
|
|
||
|
gi.TagFree(ent->client->oldplayer->client);
|
||
|
G_FreeEdict (ent->client->oldplayer);
|
||
|
G_FreeEdict (ent->client->chasecam);
|
||
|
ent->client->chase_target = NULL;
|
||
|
ent->client->chasetoggle = 0;
|
||
|
ent->client->chaseactive = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
void ChasecamTrack (edict_t *ent)
|
||
|
{
|
||
|
/* Create tempory vectors and trace variables */
|
||
|
trace_t tr;
|
||
|
vec3_t spot1, spot2, dir;
|
||
|
vec3_t forward, right, up;
|
||
|
int dist;
|
||
|
double cap; //mxd. int -> double
|
||
|
|
||
|
ent->nextthink = level.time + 0.100;
|
||
|
|
||
|
/* get the CLIENT's angle, and break it down into direction vectors,
|
||
|
* of forward, right, and up. VERY useful */
|
||
|
AngleVectors (ent->owner->client->v_angle, forward, right, up);
|
||
|
|
||
|
/* go starting at the player's origin, forward, ent->chasedist1
|
||
|
* distance, and save the location in vector spot2 */
|
||
|
|
||
|
VectorMA (ent->owner->s.origin, -ent->chasedist1, forward, spot2);
|
||
|
|
||
|
/* make spot2 a bit higher, but adding 20 to the Z coordinate */
|
||
|
|
||
|
spot2[2] += 20.000;
|
||
|
|
||
|
/* if the client is looking down, do backwards up into the air, 0.6
|
||
|
* to the ratio of looking down, so the crosshair is still roughly
|
||
|
* aiming at where the player is aiming. */
|
||
|
|
||
|
if (ent->owner->client->v_angle[0] < 0.000)
|
||
|
VectorMA (spot2, (ent->owner->client->v_angle[0] * 0.2), up, spot2);
|
||
|
|
||
|
/* if the client is looking up, do the same, but do DOWN rather than
|
||
|
* up, so the camera is behind the player aiming in a similar dir */
|
||
|
|
||
|
else if (ent->owner->client->v_angle[0] > 0.000)
|
||
|
VectorMA (spot2, (ent->owner->client->v_angle[0] * 0.2), up, spot2);
|
||
|
|
||
|
/* make the tr traceline trace from the player model's position, to spot2,
|
||
|
* ignoring the player, with MASK_SHOT. These masks have been fixed
|
||
|
* from the previous version. The MASK_SHOT will stop the camera from
|
||
|
* getting stuck in walls, sky, etc. */
|
||
|
|
||
|
tr = gi.trace (ent->owner->s.origin, NULL, NULL, spot2, ent->owner, MASK_SHOT);
|
||
|
|
||
|
/* subtract the endpoint from the start point for length and
|
||
|
* direction manipulation */
|
||
|
|
||
|
VectorSubtract (tr.endpos, ent->owner->s.origin, spot1);
|
||
|
|
||
|
/* in this case, length */
|
||
|
|
||
|
ent->chasedist1 = VectorLength (spot1);
|
||
|
|
||
|
/* go, starting from the end of the trace, 2 points forward (client
|
||
|
* angles) and save the location in spot2 */
|
||
|
|
||
|
VectorMA (tr.endpos, 2, forward, spot2);
|
||
|
|
||
|
/* make spot1 the same for tempory vector modification and make spot1
|
||
|
* a bit higher than spot2 */
|
||
|
|
||
|
VectorCopy (spot2, spot1);
|
||
|
spot1[2] += 32;
|
||
|
|
||
|
/* another trace from spot2 to spot2, ignoring player, no masks */
|
||
|
|
||
|
tr = gi.trace (spot2, NULL, NULL, spot1, ent->owner, MASK_SHOT);
|
||
|
|
||
|
/* if we hit something, copy the trace end to spot2 and lower spot2 */
|
||
|
|
||
|
if (tr.fraction < 1.000)
|
||
|
{
|
||
|
VectorCopy (tr.endpos, spot2);
|
||
|
spot2[2] -= 32;
|
||
|
}
|
||
|
|
||
|
/* subtract endpos spot2 from startpos the camera origin, saving it to
|
||
|
* the dir vector, and normalize dir for a direction from the camera
|
||
|
* origin, to the spot2 */
|
||
|
|
||
|
VectorSubtract (spot2, ent->s.origin, dir);
|
||
|
VectorNormalize (dir);
|
||
|
|
||
|
/* subtract the same things, but save it in spot1 for a temporary
|
||
|
* length calculation */
|
||
|
|
||
|
VectorSubtract (spot2, ent->s.origin, spot1);
|
||
|
dist = VectorLength (spot1);
|
||
|
|
||
|
/* another traceline */
|
||
|
|
||
|
tr = gi.trace (ent->s.origin, NULL, NULL, spot2, ent->owner, MASK_SHOT);
|
||
|
|
||
|
/* if we DON'T hit anyting, do some freaky stuff <G> */
|
||
|
|
||
|
if (tr.fraction == 1.000)
|
||
|
{
|
||
|
|
||
|
/* Make the angles of the chasecam, the same as the player, so
|
||
|
* we are always behind the player. (angles) */
|
||
|
|
||
|
VectorCopy (ent->owner->s.angles, ent->s.angles);
|
||
|
|
||
|
/* calculate the percentages of the distances, and make sure we're
|
||
|
* not going too far, or too short, in relation to our panning
|
||
|
* speed of the chasecam entity */
|
||
|
|
||
|
cap = (dist * 0.400);
|
||
|
|
||
|
/* if we're going too fast, make us top speed */
|
||
|
|
||
|
if (cap > 5.200)
|
||
|
{
|
||
|
ent->velocity[0] = ((dir[0] * dist) * 5.2);
|
||
|
ent->velocity[1] = ((dir[1] * dist) * 5.2);
|
||
|
ent->velocity[2] = ((dir[2] * dist) * 5.2);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
/* if we're NOT going top speed, but we're going faster than
|
||
|
* 1, relative to the total, make us as fast as we're going */
|
||
|
|
||
|
if ( (cap > 1.000) )
|
||
|
{
|
||
|
ent->velocity[0] = ((dir[0] * dist) * cap);
|
||
|
ent->velocity[1] = ((dir[1] * dist) * cap);
|
||
|
ent->velocity[2] = ((dir[2] * dist) * cap);
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
/* if we're not going faster than one, don't accelerate our
|
||
|
* speed at all, make us go slow to our destination */
|
||
|
|
||
|
ent->velocity[0] = (dir[0] * dist);
|
||
|
ent->velocity[1] = (dir[1] * dist);
|
||
|
ent->velocity[2] = (dir[2] * dist);
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/* subtract endpos;player position, from chasecam position to get
|
||
|
* a length to determine whether we should accelerate faster from
|
||
|
* the player or not */
|
||
|
|
||
|
VectorSubtract (ent->owner->s.origin, ent->s.origin, spot1);
|
||
|
|
||
|
if (VectorLength(spot1) < 20)
|
||
|
{
|
||
|
ent->velocity[0] *= 2;
|
||
|
ent->velocity[1] *= 2;
|
||
|
ent->velocity[2] *= 2;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/* if we DID hit something in the tr.fraction call ages back, then
|
||
|
* make the spot2 we created, the position for the chasecamera. */
|
||
|
|
||
|
else
|
||
|
VectorCopy (spot2, ent->s.origin);
|
||
|
|
||
|
/* If the distance is less than 90, then we haven't reached the
|
||
|
* furthest point. If we HAVEN'T reached the furthest point, keep
|
||
|
* going backwards. This was a fix for the "shaking". The camera was
|
||
|
* getting forced backwards, only to be brought back, next think */
|
||
|
|
||
|
|
||
|
if (ent->chasedist1 < 90.00)
|
||
|
ent->chasedist1 += 1;
|
||
|
|
||
|
/* if we're too far away, give us a maximum distance */
|
||
|
|
||
|
else if (ent->chasedist1 > 90.00)
|
||
|
ent->chasedist1 = 90;
|
||
|
|
||
|
/* if we haven't gone anywhere since the last think routine, and we
|
||
|
* are greater than 20 points in the distance calculated, add one to
|
||
|
* the second chasedistance variable
|
||
|
|
||
|
* The "ent->movedir" is a vector which is not used in this entity, so
|
||
|
* we can use this a tempory vector belonging to the chasecam, which
|
||
|
* can be carried through think routines. */
|
||
|
|
||
|
if (ent->movedir == ent->s.origin)
|
||
|
{
|
||
|
if (dist > 20)
|
||
|
ent->chasedist2++;
|
||
|
}
|
||
|
|
||
|
/* if we've buggered up more than 3 times, there must be some mistake,
|
||
|
* so restart the camera so we re-create a chasecam, destroy the old one,
|
||
|
* slowly go outwards from the player, and keep thinking this routing in
|
||
|
* the new camera entity */
|
||
|
|
||
|
if (ent->chasedist2 > 3)
|
||
|
{
|
||
|
ChasecamStart (ent->owner);
|
||
|
G_FreeEdict(ent);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* Copy the position of the chasecam now, and stick it to the movedir
|
||
|
* variable, for position checking when we rethink this function */
|
||
|
|
||
|
VectorCopy (ent->s.origin, ent->movedir);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
void Cmd_Chasecam_Toggle (edict_t *ent)
|
||
|
{
|
||
|
int i;
|
||
|
edict_t *e;
|
||
|
|
||
|
////////////////////////////////////
|
||
|
// ADDED
|
||
|
if((ent->client->resp.spectator == true))// ||
|
||
|
//(ent->client->resp.team == CTF_NOTEAM && ent->client->resp.player_class == NO_CLASS))
|
||
|
{
|
||
|
if (ent->client->chase_target)
|
||
|
{
|
||
|
//ent->svflags &= ~SVF_NOCLIENT; //added
|
||
|
ent->client->chase_target = NULL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (i = 1; i <= maxclients->value; i++)
|
||
|
{
|
||
|
e = g_edicts + i;
|
||
|
if (e->inuse && e->solid != SOLID_NOT)
|
||
|
{
|
||
|
ent->client->chase_target = e;
|
||
|
ent->client->update_chase = true;
|
||
|
ent->svflags |= SVF_NOCLIENT; //added
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// Lazarus: Don't allow thirdperson when using spycam
|
||
|
else if (!ent->deadflag && !ent->client->spycam /*&& ent->client->resp.player_class*/)
|
||
|
{
|
||
|
// if (ent->client->chasetoggle)
|
||
|
if (ent->client->chaseactive)
|
||
|
{
|
||
|
// gi.cprintf (ent, PRINT_HIGH, "Leaving Third Person mode.\n");
|
||
|
ChasecamRemove (ent);
|
||
|
}
|
||
|
// Knightmare- don't use server chasecam if client chasecam is on
|
||
|
else if (!cl_thirdperson->value || deathmatch->value || coop->value)
|
||
|
{
|
||
|
// gi.cprintf (ent, PRINT_HIGH, "Starting Third Person mode.\n");
|
||
|
ChasecamStart (ent);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void CheckChasecam_Viewent (edict_t *ent)
|
||
|
{
|
||
|
// Added by WarZone - Begin
|
||
|
gclient_t *cl;
|
||
|
|
||
|
if (!ent->client->oldplayer->client)
|
||
|
{
|
||
|
cl = (gclient_t *) gi.TagMalloc(sizeof(gclient_t), TAG_LEVEL);
|
||
|
ent->client->oldplayer->client = cl;
|
||
|
}
|
||
|
// Added by WarZone - End
|
||
|
|
||
|
// if ((ent->client->chasetoggle == 1) && (ent->client->oldplayer)) if ((ent->client->chasetoggle == 1) && (ent->client->oldplayer))
|
||
|
if ((ent->client->chaseactive == 1) && (ent->client->oldplayer))
|
||
|
{
|
||
|
ent->client->oldplayer->s.frame = ent->s.frame;
|
||
|
|
||
|
/* Copy the origin, the speed, and the model angle, NOT
|
||
|
* literal angle to the display entity */
|
||
|
|
||
|
VectorCopy (ent->s.origin, ent->client->oldplayer->s.origin);
|
||
|
VectorCopy (ent->velocity, ent->client->oldplayer->velocity);
|
||
|
VectorCopy (ent->s.angles, ent->client->oldplayer->s.angles);
|
||
|
/* Make sure we are using the same model + skin as selected,
|
||
|
* as well as the weapon model the player model is holding.
|
||
|
* For customized deathmatch weapon displaying, you can
|
||
|
* use the modelindex2 for different weapon changing, as you
|
||
|
* can read in forthcoming tutorials */
|
||
|
ent->client->oldplayer->s.modelindex = ent->s.modelindex;
|
||
|
ent->client->oldplayer->s.modelindex2 = ent->s.modelindex2;
|
||
|
ent->client->oldplayer->s.modelindex3 = ent->s.modelindex3;
|
||
|
ent->client->oldplayer->s = ent->s;
|
||
|
gi.linkentity (ent->client->oldplayer);
|
||
|
}
|
||
|
}
|
||
|
|