2001-02-19 21:15:25 +00:00
|
|
|
/*
|
|
|
|
cl_cam.c
|
|
|
|
|
|
|
|
Player camera tracking in Spectator mode
|
|
|
|
|
|
|
|
Copyright (C) 1996-1997 Id Software, Inc.
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to:
|
|
|
|
|
|
|
|
Free Software Foundation, Inc.
|
|
|
|
59 Temple Place - Suite 330
|
|
|
|
Boston, MA 02111-1307, USA
|
|
|
|
|
|
|
|
*/
|
2001-08-28 23:05:45 +00:00
|
|
|
/*
|
|
|
|
ZOID - This takes over player controls for spectator automatic camera.
|
2001-09-30 03:58:24 +00:00
|
|
|
Player moves as a spectator, but the camera tracks an enemy player
|
2001-08-28 23:05:45 +00:00
|
|
|
*/
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
2003-01-15 15:31:36 +00:00
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
#ifdef HAVE_STRING_H
|
|
|
|
# include <string.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_STRINGS_H
|
|
|
|
# include <strings.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
|
2001-05-31 03:41:35 +00:00
|
|
|
#include "QF/cvar.h"
|
2001-03-27 20:33:07 +00:00
|
|
|
#include "QF/msg.h"
|
2001-05-31 03:41:35 +00:00
|
|
|
|
2001-08-28 23:05:45 +00:00
|
|
|
#include "compat.h"
|
2022-12-01 04:11:16 +00:00
|
|
|
|
|
|
|
#include "client/sbar.h"
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2020-06-21 14:15:17 +00:00
|
|
|
#include "qw/include/cl_cam.h"
|
|
|
|
#include "qw/include/cl_input.h"
|
|
|
|
#include "qw/include/client.h"
|
|
|
|
#include "qw/pmove.h"
|
|
|
|
|
2001-09-10 17:32:22 +00:00
|
|
|
#define PM_SPECTATORMAXSPEED 500
|
|
|
|
#define PM_STOPSPEED 100
|
|
|
|
#define PM_MAXSPEED 320
|
2001-02-19 21:15:25 +00:00
|
|
|
#define BUTTON_JUMP 2
|
|
|
|
#define BUTTON_ATTACK 1
|
|
|
|
#define MAX_ANGLE_TURN 10
|
|
|
|
|
2001-09-28 07:51:15 +00:00
|
|
|
#include "QF/sys.h"
|
|
|
|
#include "QF/keys.h"
|
|
|
|
#include "QF/input.h"
|
|
|
|
#include "QF/mathlib.h"
|
|
|
|
#include "world.h"
|
|
|
|
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
int cl_hightrack;
|
|
|
|
static cvar_t cl_hightrack_cvar = {
|
|
|
|
.name = "cl_hightrack",
|
|
|
|
.description =
|
|
|
|
"view the player who has the most frags while you are in spectator "
|
|
|
|
"mode.",
|
|
|
|
.default_value = "0",
|
|
|
|
.flags = CVAR_NONE,
|
|
|
|
.value = { .type = &cexpr_int, .value = &cl_hightrack },
|
|
|
|
};
|
|
|
|
int cl_chasecam;
|
|
|
|
static cvar_t cl_chasecam_cvar = {
|
|
|
|
.name = "cl_chasecam",
|
|
|
|
.description =
|
|
|
|
"get first person view of the person you are tracking in spectator "
|
|
|
|
"mode",
|
|
|
|
.default_value = "0",
|
|
|
|
.flags = CVAR_NONE,
|
|
|
|
.value = { .type = &cexpr_int, .value = &cl_chasecam },
|
|
|
|
};
|
|
|
|
float cl_camera_maxpitch;
|
|
|
|
static cvar_t cl_camera_maxpitch_cvar = {
|
|
|
|
.name = "cl_camera_maxpitch",
|
|
|
|
.description =
|
|
|
|
"highest camera pitch in spectator mode",
|
|
|
|
.default_value = "10",
|
|
|
|
.flags = CVAR_NONE,
|
|
|
|
.value = { .type = &cexpr_float, .value = &cl_camera_maxpitch },
|
|
|
|
};
|
|
|
|
float cl_camera_maxyaw;
|
|
|
|
static cvar_t cl_camera_maxyaw_cvar = {
|
|
|
|
.name = "cl_camera_maxyaw",
|
|
|
|
.description =
|
|
|
|
"highest camera yaw in spectator mode",
|
|
|
|
.default_value = "30",
|
|
|
|
.flags = CVAR_NONE,
|
|
|
|
.value = { .type = &cexpr_float, .value = &cl_camera_maxyaw },
|
|
|
|
};
|
2001-09-28 07:51:15 +00:00
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
static vec3_t desired_position; // where the camera wants to be
|
2023-06-13 09:06:11 +00:00
|
|
|
static bool locked = false;
|
2001-02-19 21:15:25 +00:00
|
|
|
static int oldbuttons;
|
|
|
|
|
2001-08-28 23:05:45 +00:00
|
|
|
double cam_lastviewtime;
|
2023-06-13 09:06:11 +00:00
|
|
|
bool cam_forceview;
|
2001-02-19 21:15:25 +00:00
|
|
|
vec3_t cam_viewangles;
|
|
|
|
|
|
|
|
int spec_track = 0; // player# of who we are tracking
|
2002-10-02 21:56:45 +00:00
|
|
|
int ideal_track = 0;
|
|
|
|
float last_lock = 0;
|
2001-02-19 21:15:25 +00:00
|
|
|
int autocam = CAM_NONE;
|
|
|
|
|
2001-05-14 03:08:24 +00:00
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
static void
|
|
|
|
vectoangles (vec3_t vec, vec3_t ang)
|
|
|
|
{
|
2001-09-10 17:32:22 +00:00
|
|
|
float forward, pitch, yaw;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (vec[1] == 0 && vec[0] == 0) {
|
|
|
|
yaw = 0;
|
|
|
|
if (vec[2] > 0)
|
|
|
|
pitch = 90;
|
|
|
|
else
|
|
|
|
pitch = 270;
|
|
|
|
} else {
|
2001-09-10 17:32:22 +00:00
|
|
|
yaw = (int) (atan2 (vec[1], vec[0]) * (180.0 / M_PI));
|
2001-02-19 21:15:25 +00:00
|
|
|
if (yaw < 0)
|
|
|
|
yaw += 360;
|
|
|
|
|
|
|
|
forward = sqrt (vec[0] * vec[0] + vec[1] * vec[1]);
|
2001-09-10 17:32:22 +00:00
|
|
|
pitch = (int) (atan2 (vec[2], forward) * (180.0 / M_PI));
|
2001-02-19 21:15:25 +00:00
|
|
|
if (pitch < 0)
|
|
|
|
pitch += 360;
|
|
|
|
}
|
|
|
|
|
|
|
|
ang[0] = pitch;
|
|
|
|
ang[1] = yaw;
|
|
|
|
ang[2] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// returns true if weapon model should be drawn in camera mode
|
2023-06-13 09:06:11 +00:00
|
|
|
bool
|
2001-02-19 21:15:25 +00:00
|
|
|
Cam_DrawViewModel (void)
|
|
|
|
{
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (cl.viewstate.chase && chase_active)
|
2001-09-28 07:51:15 +00:00
|
|
|
return false;
|
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
if (!cl.spectator)
|
|
|
|
return true;
|
|
|
|
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (autocam && locked && cl_chasecam)
|
2001-02-19 21:15:25 +00:00
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// returns true if we should draw this player, we don't if we are chase camming
|
2023-06-13 09:06:11 +00:00
|
|
|
bool
|
2001-02-19 21:15:25 +00:00
|
|
|
Cam_DrawPlayer (int playernum)
|
|
|
|
{
|
2002-07-27 00:44:54 +00:00
|
|
|
if (playernum == cl.playernum) { // client player
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (cl.viewstate.chase == 0 || chase_active == 0)
|
2001-10-11 16:26:09 +00:00
|
|
|
return false;
|
|
|
|
if (!cl.spectator)
|
|
|
|
return true;
|
|
|
|
} else {
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (!cl_chasecam)
|
2001-10-11 16:26:09 +00:00
|
|
|
return true;
|
|
|
|
if (cl.spectator && autocam && locked && spec_track == playernum)
|
|
|
|
return false;
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (cl.viewstate.chase == 0 || chase_active == 0)
|
2001-10-11 16:26:09 +00:00
|
|
|
return true;
|
|
|
|
}
|
2001-10-11 04:43:40 +00:00
|
|
|
return false;
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
2002-10-02 21:56:45 +00:00
|
|
|
int
|
|
|
|
Cam_TrackNum (void)
|
|
|
|
{
|
|
|
|
if (!autocam)
|
|
|
|
return -1;
|
|
|
|
return spec_track;
|
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2001-02-19 21:15:25 +00:00
|
|
|
Cam_Unlock (void)
|
|
|
|
{
|
|
|
|
if (autocam) {
|
2002-10-07 03:58:08 +00:00
|
|
|
if (!cls.demoplayback) {
|
|
|
|
MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
|
|
|
|
MSG_WriteString (&cls.netchan.message, "ptrack");
|
|
|
|
}
|
2001-02-19 21:15:25 +00:00
|
|
|
autocam = CAM_NONE;
|
|
|
|
locked = false;
|
2022-11-12 19:04:27 +00:00
|
|
|
Sbar_SetAutotrack (-1);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Cam_Lock (int playernum)
|
|
|
|
{
|
2001-09-10 17:32:22 +00:00
|
|
|
char st[40];
|
2002-10-04 03:02:38 +00:00
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
snprintf (st, sizeof (st), "ptrack %i", playernum);
|
2002-10-02 21:56:45 +00:00
|
|
|
if (cls.demoplayback2) {
|
2003-03-21 21:25:44 +00:00
|
|
|
memcpy (cl.stats, cl.players[playernum].stats, sizeof (cl.stats));
|
2002-10-02 21:56:45 +00:00
|
|
|
}
|
|
|
|
|
2002-10-05 04:52:09 +00:00
|
|
|
if (!cls.demoplayback) {
|
|
|
|
MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
|
|
|
|
MSG_WriteString (&cls.netchan.message, st);
|
|
|
|
}
|
2001-02-19 21:15:25 +00:00
|
|
|
spec_track = playernum;
|
2002-10-02 21:56:45 +00:00
|
|
|
last_lock = realtime;
|
2001-02-19 21:15:25 +00:00
|
|
|
cam_forceview = true;
|
|
|
|
locked = false;
|
2022-11-12 19:04:27 +00:00
|
|
|
Sbar_SetAutotrack (spec_track);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
2004-11-02 08:40:00 +00:00
|
|
|
static trace_t
|
2022-03-30 15:07:20 +00:00
|
|
|
Cam_DoTrace (vec4f_t vec1, vec3_t vec2)//FIXME vec2 type
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
memset (&pmove, 0, sizeof (pmove));
|
|
|
|
|
|
|
|
pmove.numphysent = 1;
|
2003-09-03 22:17:04 +00:00
|
|
|
VectorZero (pmove.physents[0].origin);
|
2001-02-19 21:15:25 +00:00
|
|
|
pmove.physents[0].model = cl.worldmodel;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
VectorCopy (vec1, pmove.origin);
|
|
|
|
return PM_PlayerMove (pmove.origin, vec2);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns distance or 9999 if invalid for some reason
|
|
|
|
static float
|
|
|
|
Cam_TryFlyby (player_state_t * self, player_state_t * player, vec3_t vec,
|
2023-06-13 09:06:11 +00:00
|
|
|
bool checkvis)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
|
|
|
float len;
|
2004-11-02 08:40:00 +00:00
|
|
|
trace_t trace;
|
2001-08-28 23:05:45 +00:00
|
|
|
vec3_t v;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
vectoangles (vec, v);
|
|
|
|
VectorCopy (v, pmove.angles);
|
|
|
|
VectorNormalize (vec);
|
2021-03-11 05:27:36 +00:00
|
|
|
VectorMultAdd (player->pls.es.origin, 800, vec, v);
|
2001-02-19 21:15:25 +00:00
|
|
|
// v is endpos
|
|
|
|
// fake a player move
|
2022-03-30 15:07:20 +00:00
|
|
|
trace = Cam_DoTrace (player->pls.es.origin, v);
|
2001-02-19 21:15:25 +00:00
|
|
|
if ( /* trace.inopen || */ trace.inwater)
|
|
|
|
return 9999;
|
|
|
|
VectorCopy (trace.endpos, vec);
|
2021-03-11 05:27:36 +00:00
|
|
|
len = VectorDistance (trace.endpos, player->pls.es.origin);
|
2001-10-30 20:00:05 +00:00
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
if (len < 32 || len > 800)
|
|
|
|
return 9999;
|
|
|
|
if (checkvis) {
|
2022-03-30 15:07:20 +00:00
|
|
|
trace = Cam_DoTrace (self->pls.es.origin, vec);
|
2001-02-19 21:15:25 +00:00
|
|
|
if (trace.fraction != 1 || trace.inwater)
|
|
|
|
return 9999;
|
2001-10-30 20:00:05 +00:00
|
|
|
|
2021-03-11 05:27:36 +00:00
|
|
|
len = VectorDistance (trace.endpos, self->pls.es.origin);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
2001-10-30 20:00:05 +00:00
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Is player visible?
|
2023-06-13 09:06:11 +00:00
|
|
|
static bool
|
2021-03-11 07:19:49 +00:00
|
|
|
Cam_IsVisible (player_state_t *player, vec3_t vec)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-08-28 23:05:45 +00:00
|
|
|
float d;
|
2004-11-02 08:40:00 +00:00
|
|
|
trace_t trace;
|
2001-02-19 21:15:25 +00:00
|
|
|
vec3_t v;
|
|
|
|
|
2022-03-30 15:07:20 +00:00
|
|
|
trace = Cam_DoTrace (player->pls.es.origin, vec);
|
2001-02-19 21:15:25 +00:00
|
|
|
if (trace.fraction != 1 || /* trace.inopen || */ trace.inwater)
|
|
|
|
return false;
|
|
|
|
// check distance, don't let the player get too far away or too close
|
2021-03-11 05:27:36 +00:00
|
|
|
VectorSubtract (player->pls.es.origin, vec, v);
|
2002-08-20 02:22:40 +00:00
|
|
|
d = VectorLength (v);
|
2001-10-30 20:00:05 +00:00
|
|
|
|
|
|
|
return (d > 16.0);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
2023-06-13 09:06:11 +00:00
|
|
|
static bool
|
2001-02-19 21:15:25 +00:00
|
|
|
InitFlyby (player_state_t * self, player_state_t * player, int checkvis)
|
|
|
|
{
|
|
|
|
float f, max;
|
2001-09-10 17:32:22 +00:00
|
|
|
vec3_t forward, right, up, vec, vec2;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
VectorCopy (player->viewangles, vec);
|
|
|
|
vec[0] = 0;
|
|
|
|
AngleVectors (vec, forward, right, up);
|
2001-08-28 23:05:45 +00:00
|
|
|
// for (i = 0; i < 3; i++)
|
|
|
|
// forward[i] *= 3;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
max = 1000;
|
|
|
|
VectorAdd (forward, up, vec2);
|
|
|
|
VectorAdd (vec2, right, vec2);
|
|
|
|
if ((f = Cam_TryFlyby (self, player, vec2, checkvis)) < max) {
|
|
|
|
max = f;
|
|
|
|
VectorCopy (vec2, vec);
|
|
|
|
}
|
|
|
|
VectorAdd (forward, up, vec2);
|
|
|
|
VectorSubtract (vec2, right, vec2);
|
|
|
|
if ((f = Cam_TryFlyby (self, player, vec2, checkvis)) < max) {
|
|
|
|
max = f;
|
|
|
|
VectorCopy (vec2, vec);
|
|
|
|
}
|
|
|
|
VectorAdd (forward, right, vec2);
|
|
|
|
if ((f = Cam_TryFlyby (self, player, vec2, checkvis)) < max) {
|
|
|
|
max = f;
|
|
|
|
VectorCopy (vec2, vec);
|
|
|
|
}
|
|
|
|
VectorSubtract (forward, right, vec2);
|
|
|
|
if ((f = Cam_TryFlyby (self, player, vec2, checkvis)) < max) {
|
|
|
|
max = f;
|
|
|
|
VectorCopy (vec2, vec);
|
|
|
|
}
|
|
|
|
VectorAdd (forward, up, vec2);
|
|
|
|
if ((f = Cam_TryFlyby (self, player, vec2, checkvis)) < max) {
|
|
|
|
max = f;
|
|
|
|
VectorCopy (vec2, vec);
|
|
|
|
}
|
|
|
|
VectorSubtract (forward, up, vec2);
|
|
|
|
if ((f = Cam_TryFlyby (self, player, vec2, checkvis)) < max) {
|
|
|
|
max = f;
|
|
|
|
VectorCopy (vec2, vec);
|
|
|
|
}
|
|
|
|
VectorAdd (up, right, vec2);
|
|
|
|
VectorSubtract (vec2, forward, vec2);
|
|
|
|
if ((f = Cam_TryFlyby (self, player, vec2, checkvis)) < max) {
|
|
|
|
max = f;
|
|
|
|
VectorCopy (vec2, vec);
|
|
|
|
}
|
|
|
|
VectorSubtract (up, right, vec2);
|
|
|
|
VectorSubtract (vec2, forward, vec2);
|
|
|
|
if ((f = Cam_TryFlyby (self, player, vec2, checkvis)) < max) {
|
|
|
|
max = f;
|
|
|
|
VectorCopy (vec2, vec);
|
|
|
|
}
|
|
|
|
// invert
|
2003-09-03 22:17:04 +00:00
|
|
|
VectorNegate (forward, vec2);
|
2001-02-19 21:15:25 +00:00
|
|
|
if ((f = Cam_TryFlyby (self, player, vec2, checkvis)) < max) {
|
|
|
|
max = f;
|
|
|
|
VectorCopy (vec2, vec);
|
|
|
|
}
|
|
|
|
VectorCopy (forward, vec2);
|
|
|
|
if ((f = Cam_TryFlyby (self, player, vec2, checkvis)) < max) {
|
|
|
|
max = f;
|
|
|
|
VectorCopy (vec2, vec);
|
|
|
|
}
|
|
|
|
// invert
|
2003-09-03 22:17:04 +00:00
|
|
|
VectorNegate (right, vec2);
|
2001-02-19 21:15:25 +00:00
|
|
|
if ((f = Cam_TryFlyby (self, player, vec2, checkvis)) < max) {
|
|
|
|
max = f;
|
|
|
|
VectorCopy (vec2, vec);
|
|
|
|
}
|
|
|
|
VectorCopy (right, vec2);
|
|
|
|
if ((f = Cam_TryFlyby (self, player, vec2, checkvis)) < max) {
|
|
|
|
max = f;
|
|
|
|
VectorCopy (vec2, vec);
|
|
|
|
}
|
|
|
|
// ack, can't find him
|
|
|
|
if (max >= 1000) {
|
2003-03-21 21:25:44 +00:00
|
|
|
// Cam_Unlock ();
|
2001-02-19 21:15:25 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
locked = true;
|
|
|
|
VectorCopy (vec, desired_position);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
Cam_CheckHighTarget (void)
|
|
|
|
{
|
2001-09-10 17:32:22 +00:00
|
|
|
int i, j, max;
|
|
|
|
player_info_t *s;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
j = -1;
|
|
|
|
for (i = 0, max = -9999; i < MAX_CLIENTS; i++) {
|
|
|
|
s = &cl.players[i];
|
2012-06-29 11:26:27 +00:00
|
|
|
if (s->name && s->name->value[0] && !s->spectator && s->frags > max) {
|
2001-02-19 21:15:25 +00:00
|
|
|
max = s->frags;
|
|
|
|
j = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (j >= 0) {
|
2002-10-02 21:56:45 +00:00
|
|
|
if (!locked || cl.players[j].frags > cl.players[spec_track].frags) {
|
2001-02-19 21:15:25 +00:00
|
|
|
Cam_Lock (j);
|
2002-10-02 21:56:45 +00:00
|
|
|
ideal_track = spec_track;
|
|
|
|
}
|
2001-02-19 21:15:25 +00:00
|
|
|
} else
|
|
|
|
Cam_Unlock ();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ZOID
|
|
|
|
//
|
|
|
|
// Take over the user controls and track a player.
|
|
|
|
// We find a nice position to watch the player and move there
|
|
|
|
void
|
|
|
|
Cam_Track (usercmd_t *cmd)
|
|
|
|
{
|
2001-09-10 17:32:22 +00:00
|
|
|
float len;
|
|
|
|
frame_t *frame;
|
2001-08-28 23:05:45 +00:00
|
|
|
player_state_t *player, *self;
|
2001-09-10 17:32:22 +00:00
|
|
|
vec3_t vec;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (!cl.spectator)
|
|
|
|
return;
|
|
|
|
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (cl_hightrack && !locked)
|
2001-02-19 21:15:25 +00:00
|
|
|
Cam_CheckHighTarget ();
|
|
|
|
|
|
|
|
if (!autocam || cls.state != ca_active)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (locked
|
2022-11-12 05:40:18 +00:00
|
|
|
&& (!cl.players[spec_track].name
|
|
|
|
|| !cl.players[spec_track].name->value[0]
|
2001-02-19 21:15:25 +00:00
|
|
|
|| cl.players[spec_track].spectator)) {
|
|
|
|
locked = false;
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (cl_hightrack)
|
2001-02-19 21:15:25 +00:00
|
|
|
Cam_CheckHighTarget ();
|
|
|
|
else
|
|
|
|
Cam_Unlock ();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
frame = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];
|
2002-10-02 21:56:45 +00:00
|
|
|
if (autocam && cls.demoplayback2 && 0) {
|
|
|
|
if (ideal_track != spec_track && realtime - last_lock > 1
|
|
|
|
&& frame->playerstate[ideal_track].messagenum == cl.parsecount)
|
|
|
|
Cam_Lock (ideal_track);
|
|
|
|
|
|
|
|
if (frame->playerstate[spec_track].messagenum != cl.parsecount) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_CLIENTS; i++) {
|
|
|
|
if (frame->playerstate[i].messagenum == cl.parsecount)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i < MAX_CLIENTS)
|
|
|
|
Cam_Lock (i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
player = frame->playerstate + spec_track;
|
|
|
|
self = frame->playerstate + cl.playernum;
|
|
|
|
|
|
|
|
if (!locked || !Cam_IsVisible (player, desired_position)) {
|
|
|
|
if (!locked || realtime - cam_lastviewtime > 0.1) {
|
|
|
|
if (!InitFlyby (self, player, true))
|
|
|
|
InitFlyby (self, player, false);
|
|
|
|
cam_lastviewtime = realtime;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
cam_lastviewtime = realtime;
|
|
|
|
|
|
|
|
// couldn't track for some reason
|
|
|
|
if (!locked || !autocam)
|
|
|
|
return;
|
|
|
|
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (cl_chasecam) {
|
2001-02-19 21:15:25 +00:00
|
|
|
cmd->forwardmove = cmd->sidemove = cmd->upmove = 0;
|
|
|
|
|
2022-03-01 02:43:23 +00:00
|
|
|
VectorCopy (player->viewangles, cl.viewstate.player_angles);
|
2021-03-11 05:27:36 +00:00
|
|
|
VectorCopy (player->pls.es.origin, desired_position);
|
|
|
|
if (memcmp (&desired_position, &self->pls.es.origin,
|
2002-10-04 03:02:38 +00:00
|
|
|
sizeof (desired_position)) != 0) {
|
2002-10-05 04:52:09 +00:00
|
|
|
if (!cls.demoplayback) {
|
|
|
|
MSG_WriteByte (&cls.netchan.message, clc_tmove);
|
|
|
|
MSG_WriteCoordV (&cls.netchan.message, desired_position);
|
|
|
|
}
|
2001-02-19 21:15:25 +00:00
|
|
|
// move there locally immediately
|
2021-03-11 05:27:36 +00:00
|
|
|
VectorCopy (desired_position, self->pls.es.origin);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
2021-03-11 05:27:36 +00:00
|
|
|
self->pls.es.weaponframe = player->pls.es.weaponframe;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
// Ok, move to our desired position and set our angles to view
|
|
|
|
// the player
|
2021-03-11 05:27:36 +00:00
|
|
|
VectorSubtract (desired_position, self->pls.es.origin, vec);
|
2002-08-20 02:22:40 +00:00
|
|
|
len = VectorLength (vec);
|
2001-02-19 21:15:25 +00:00
|
|
|
cmd->forwardmove = cmd->sidemove = cmd->upmove = 0;
|
|
|
|
if (len > 16) { // close enough?
|
2002-10-07 03:58:08 +00:00
|
|
|
if (!cls.demoplayback) {
|
|
|
|
MSG_WriteByte (&cls.netchan.message, clc_tmove);
|
|
|
|
MSG_WriteCoordV (&cls.netchan.message, desired_position);
|
|
|
|
}
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
// move there locally immediately
|
2021-03-11 05:27:36 +00:00
|
|
|
VectorCopy (desired_position, self->pls.es.origin);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2021-03-11 05:27:36 +00:00
|
|
|
VectorSubtract (player->pls.es.origin, desired_position, vec);
|
2022-03-01 02:43:23 +00:00
|
|
|
vectoangles (vec, cl.viewstate.player_angles);
|
|
|
|
cl.viewstate.player_angles[0] = -cl.viewstate.player_angles[0];
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
static float
|
|
|
|
adjustang (float current, float ideal, float speed)
|
|
|
|
{
|
2001-09-10 17:32:22 +00:00
|
|
|
float move;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
current = anglemod (current);
|
|
|
|
ideal = anglemod (ideal);
|
|
|
|
|
|
|
|
if (current == ideal)
|
|
|
|
return current;
|
|
|
|
|
|
|
|
move = ideal - current;
|
|
|
|
if (ideal > current) {
|
|
|
|
if (move >= 180)
|
|
|
|
move = move - 360;
|
|
|
|
} else {
|
|
|
|
if (move <= -180)
|
|
|
|
move = move + 360;
|
|
|
|
}
|
|
|
|
if (move > 0) {
|
|
|
|
if (move > speed)
|
|
|
|
move = speed;
|
|
|
|
} else {
|
|
|
|
if (move < -speed)
|
|
|
|
move = -speed;
|
|
|
|
}
|
|
|
|
|
|
|
|
return anglemod (current + move);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
void
|
|
|
|
Cam_SetView (void)
|
|
|
|
{
|
2001-09-10 17:32:22 +00:00
|
|
|
frame_t *frame;
|
2001-08-28 23:05:45 +00:00
|
|
|
player_state_t *player, *self;
|
2001-09-10 17:32:22 +00:00
|
|
|
vec3_t vec, vec2;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (cls.state != ca_active || !cl.spectator || !autocam || !locked)
|
|
|
|
return;
|
|
|
|
|
|
|
|
frame = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];
|
|
|
|
player = frame->playerstate + spec_track;
|
|
|
|
self = frame->playerstate + cl.playernum;
|
|
|
|
|
2021-03-11 05:27:36 +00:00
|
|
|
VectorSubtract (player->pls.es.origin, cl.simorg, vec);
|
2001-02-19 21:15:25 +00:00
|
|
|
if (cam_forceview) {
|
|
|
|
cam_forceview = false;
|
|
|
|
vectoangles (vec, cam_viewangles);
|
|
|
|
cam_viewangles[0] = -cam_viewangles[0];
|
|
|
|
} else {
|
|
|
|
vectoangles (vec, vec2);
|
|
|
|
vec2[PITCH] = -vec2[PITCH];
|
|
|
|
|
|
|
|
cam_viewangles[PITCH] =
|
|
|
|
adjustang (cam_viewangles[PITCH], vec2[PITCH],
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
cl_camera_maxpitch);
|
2001-02-19 21:15:25 +00:00
|
|
|
cam_viewangles[YAW] =
|
2001-08-28 23:05:45 +00:00
|
|
|
adjustang (cam_viewangles[YAW], vec2[YAW],
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
cl_camera_maxyaw);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
2022-03-01 02:43:23 +00:00
|
|
|
VectorCopy (cam_viewangles, cl.viewstate.player_angles);
|
|
|
|
VectorCopy (cl.viewstate.player_angles, cl.simangles);
|
2012-05-31 23:14:41 +00:00
|
|
|
cl.simangles[ROLL] = 0; // FIXME @@@
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void
|
|
|
|
Cam_FinishMove (usercmd_t *cmd)
|
|
|
|
{
|
2001-09-10 17:32:22 +00:00
|
|
|
int end, i;
|
|
|
|
player_info_t *s;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (cls.state != ca_active)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!cl.spectator) // only in spectator mode
|
|
|
|
return;
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
if (autocam && locked) {
|
|
|
|
frame = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];
|
|
|
|
player = frame->playerstate + spec_track;
|
|
|
|
self = frame->playerstate + cl.playernum;
|
|
|
|
|
2021-03-11 05:27:36 +00:00
|
|
|
VectorSubtract (player->pls.es.origin, self->pls.es.origin, vec);
|
2001-02-19 21:15:25 +00:00
|
|
|
if (cam_forceview) {
|
|
|
|
cam_forceview = false;
|
|
|
|
vectoangles (vec, cam_viewangles);
|
|
|
|
cam_viewangles[0] = -cam_viewangles[0];
|
|
|
|
} else {
|
|
|
|
vectoangles (vec, vec2);
|
|
|
|
vec2[PITCH] = -vec2[PITCH];
|
|
|
|
|
|
|
|
cam_viewangles[PITCH] =
|
|
|
|
adjustang (cam_viewangles[PITCH], vec2[PITCH],
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
cl_camera_maxpitch);
|
2001-02-19 21:15:25 +00:00
|
|
|
cam_viewangles[YAW] =
|
|
|
|
adjustang (cam_viewangles[YAW], vec2[YAW],
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
cl_camera_maxyaw);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
2022-03-01 02:43:23 +00:00
|
|
|
VectorCopy (cam_viewangles, cl.viewstate.player_angles);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (cmd->buttons & BUTTON_ATTACK) {
|
|
|
|
if (!(oldbuttons & BUTTON_ATTACK)) {
|
|
|
|
oldbuttons |= BUTTON_ATTACK;
|
|
|
|
autocam++;
|
|
|
|
|
|
|
|
if (autocam > CAM_TRACK) {
|
|
|
|
Cam_Unlock ();
|
2022-03-01 02:43:23 +00:00
|
|
|
VectorCopy (cl.viewstate.player_angles, cmd->angles);
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
oldbuttons &= ~BUTTON_ATTACK;
|
|
|
|
if (!autocam)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (autocam && cl_hightrack) {
|
2001-02-19 21:15:25 +00:00
|
|
|
Cam_CheckHighTarget ();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (locked) {
|
|
|
|
if ((cmd->buttons & BUTTON_JUMP) && (oldbuttons & BUTTON_JUMP))
|
|
|
|
return; // don't pogo stick
|
|
|
|
|
|
|
|
if (!(cmd->buttons & BUTTON_JUMP)) {
|
|
|
|
oldbuttons &= ~BUTTON_JUMP;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
oldbuttons |= BUTTON_JUMP; // don't jump again until released
|
|
|
|
}
|
2007-11-06 10:17:14 +00:00
|
|
|
// Sys_Printf ("Selecting track target...\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (locked && autocam)
|
|
|
|
end = (spec_track + 1) % MAX_CLIENTS;
|
|
|
|
else
|
|
|
|
end = spec_track;
|
|
|
|
i = end;
|
|
|
|
do {
|
|
|
|
s = &cl.players[i];
|
2012-06-29 11:26:27 +00:00
|
|
|
if (s->name && s->name->value[0] && !s->spectator) {
|
2001-02-19 21:15:25 +00:00
|
|
|
Cam_Lock (i);
|
2002-10-02 21:56:45 +00:00
|
|
|
ideal_track = i;
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
i = (i + 1) % MAX_CLIENTS;
|
|
|
|
} while (i != end);
|
|
|
|
// stay on same guy?
|
|
|
|
i = spec_track;
|
|
|
|
s = &cl.players[i];
|
2012-06-29 11:26:27 +00:00
|
|
|
if (s->name && s->name->value[0] && !s->spectator) {
|
2001-02-19 21:15:25 +00:00
|
|
|
Cam_Lock (i);
|
2002-10-02 21:56:45 +00:00
|
|
|
ideal_track = i;
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
2007-11-06 10:17:14 +00:00
|
|
|
Sys_Printf ("No target found ...\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
autocam = locked = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Cam_Reset (void)
|
|
|
|
{
|
|
|
|
autocam = CAM_NONE;
|
|
|
|
spec_track = 0;
|
2002-10-02 21:56:45 +00:00
|
|
|
ideal_track = 0;
|
2022-11-12 19:04:27 +00:00
|
|
|
Sbar_SetAutotrack (-1);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CL_Cam_Init_Cvars (void)
|
|
|
|
{
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
Cvar_Register (&cl_camera_maxpitch_cvar, 0, 0);
|
|
|
|
Cvar_Register (&cl_camera_maxyaw_cvar, 0, 0);
|
|
|
|
Cvar_Register (&cl_chasecam_cvar, 0, 0);
|
|
|
|
Cvar_Register (&cl_hightrack_cvar, 0, 0);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|