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.
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
// view.c -- player eye positioning
#include "quakedef.h"
+#include "cl_collision.h"
/*
*/
-cvar_t scr_ofsx = {"scr_ofsx","0", false};
-cvar_t scr_ofsy = {"scr_ofsy","0", false};
-cvar_t scr_ofsz = {"scr_ofsz","0", false};
+cvar_t cl_rollspeed = {0, "cl_rollspeed", "200", "how much strafing is necessary to tilt the view"};
+cvar_t cl_rollangle = {0, "cl_rollangle", "2.0", "how much to tilt the view when strafing"};
-cvar_t cl_rollspeed = {"cl_rollspeed", "200"};
-cvar_t cl_rollangle = {"cl_rollangle", "2.0"};
+cvar_t cl_bob = {0, "cl_bob","0.02", "view bobbing amount"};
+cvar_t cl_bobcycle = {0, "cl_bobcycle","0.6", "view bobbing speed"};
+cvar_t cl_bobup = {0, "cl_bobup","0.5", "view bobbing adjustment that makes the up or down swing of the bob last longer"};
-cvar_t cl_bob = {"cl_bob","0.02", false};
-cvar_t cl_bobcycle = {"cl_bobcycle","0.6", false};
-cvar_t cl_bobup = {"cl_bobup","0.5", false};
+cvar_t cl_bobmodel = {CVAR_SAVE, "cl_bobmodel", "1", "enables gun bobbing"};
+cvar_t cl_bobmodel_side = {0, "cl_bobmodel_side", "0.05", "gun bobbing sideways sway amount"};
+cvar_t cl_bobmodel_up = {0, "cl_bobmodel_up", "0.02", "gun bobbing upward movement amount"};
+cvar_t cl_bobmodel_speed = {0, "cl_bobmodel_speed", "7", "gun bobbing speed"};
-cvar_t v_kicktime = {"v_kicktime", "0.5", false};
-cvar_t v_kickroll = {"v_kickroll", "0.6", false};
-cvar_t v_kickpitch = {"v_kickpitch", "0.6", false};
+cvar_t v_kicktime = {0, "v_kicktime", "0.5", "how long a view kick from damage lasts"};
+cvar_t v_kickroll = {0, "v_kickroll", "0.6", "how much a view kick from damage rolls your view"};
+cvar_t v_kickpitch = {0, "v_kickpitch", "0.6", "how much a view kick from damage pitches your view"};
-cvar_t v_iyaw_cycle = {"v_iyaw_cycle", "2", false};
-cvar_t v_iroll_cycle = {"v_iroll_cycle", "0.5", false};
-cvar_t v_ipitch_cycle = {"v_ipitch_cycle", "1", false};
-cvar_t v_iyaw_level = {"v_iyaw_level", "0.3", false};
-cvar_t v_iroll_level = {"v_iroll_level", "0.1", false};
-cvar_t v_ipitch_level = {"v_ipitch_level", "0.3", false};
+cvar_t v_iyaw_cycle = {0, "v_iyaw_cycle", "2", "v_idlescale yaw speed"};
+cvar_t v_iroll_cycle = {0, "v_iroll_cycle", "0.5", "v_idlescale roll speed"};
+cvar_t v_ipitch_cycle = {0, "v_ipitch_cycle", "1", "v_idlescale pitch speed"};
+cvar_t v_iyaw_level = {0, "v_iyaw_level", "0.3", "v_idlescale yaw amount"};
+cvar_t v_iroll_level = {0, "v_iroll_level", "0.1", "v_idlescale roll amount"};
+cvar_t v_ipitch_level = {0, "v_ipitch_level", "0.3", "v_idlescale pitch amount"};
-cvar_t v_idlescale = {"v_idlescale", "0", false};
+cvar_t v_idlescale = {0, "v_idlescale", "0", "how much of the quake 'drunken view' effect to use"};
-cvar_t crosshair = {"crosshair", "0", true};
-cvar_t cl_crossx = {"cl_crossx", "0", false};
-cvar_t cl_crossy = {"cl_crossy", "0", false};
+cvar_t crosshair = {CVAR_SAVE, "crosshair", "0", "selects crosshair to use (0 is none)"};
-cvar_t gl_cshiftpercent = {"gl_cshiftpercent", "100", false};
+cvar_t v_centermove = {0, "v_centermove", "0.15", "how long before the view begins to center itself (if freelook/+mlook/+jlook/+klook are off)"};
+cvar_t v_centerspeed = {0, "v_centerspeed","500", "how fast the view centers itself"};
-float v_dmg_time, v_dmg_roll, v_dmg_pitch;
+cvar_t cl_stairsmoothspeed = {CVAR_SAVE, "cl_stairsmoothspeed", "160", "how fast your view moves upward/downward when running up/down stairs"};
+
+cvar_t chase_back = {CVAR_SAVE, "chase_back", "48", "chase cam distance from the player"};
+cvar_t chase_up = {CVAR_SAVE, "chase_up", "24", "chase cam distance from the player"};
+cvar_t chase_active = {CVAR_SAVE, "chase_active", "0", "enables chase cam"};
+// GAME_GOODVSBAD2
+cvar_t chase_stevie = {0, "chase_stevie", "0", "chase cam view from above (used only by GoodVsBad2)"};
-extern int in_forward, in_forward2, in_back;
+cvar_t v_deathtilt = {0, "v_deathtilt", "1", "whether to use sideways view when dead"};
+cvar_t v_deathtiltangle = {0, "v_deathtiltangle", "80", "what roll angle to use when tilting the view while dead"};
+
+float v_dmg_time, v_dmg_roll, v_dmg_pitch;
/*
Used by view and sv_user
===============
*/
-vec3_t forward, right, up;
-
float V_CalcRoll (vec3_t angles, vec3_t velocity)
{
+ vec3_t right;
float sign;
float side;
float value;
-
- AngleVectors (angles, forward, right, up);
+
+ AngleVectors (angles, NULL, right, NULL);
side = DotProduct (velocity, right);
sign = side < 0 ? -1 : 1;
side = fabs(side);
-
+
value = cl_rollangle.value;
-// if (cl.inwater)
-// value *= 6;
if (side < cl_rollspeed.value)
side = side * value / cl_rollspeed.value;
else
side = value;
-
- return side*sign;
-
-}
+ return side*sign;
-/*
-===============
-V_CalcBob
-
-===============
-*/
-float V_CalcBob (void)
-{
- float bob;
- float cycle;
-
- cycle = cl.time - (int)(cl.time/cl_bobcycle.value)*cl_bobcycle.value;
- cycle /= cl_bobcycle.value;
- if (cycle < cl_bobup.value)
- cycle = M_PI * cycle / cl_bobup.value;
- else
- cycle = M_PI + M_PI*(cycle-cl_bobup.value)/(1.0 - cl_bobup.value);
-
-// bob is proportional to velocity in the xy plane
-// (don't count Z, or jumping messes it up)
-
- bob = sqrt(cl.velocity[0]*cl.velocity[0] + cl.velocity[1]*cl.velocity[1]) * cl_bob.value;
-//Con_Printf ("speed: %5.1f\n", Length(cl.velocity));
- bob = bob*0.3 + bob*0.7*sin(cycle);
- if (bob > 4)
- bob = 4;
- else if (bob < -7)
- bob = -7;
- return bob;
-
}
-
-//=============================================================================
-
-
-cvar_t v_centermove = {"v_centermove", "0.15", false};
-cvar_t v_centerspeed = {"v_centerspeed","500"};
-
-
void V_StartPitchDrift (void)
{
-#if 1
if (cl.laststop == cl.time)
- {
return; // something else is keeping it from drifting
- }
-#endif
+
if (cl.nodrift || !cl.pitchvel)
{
cl.pitchvel = v_centerspeed.value;
mlook and mouse, or klook and keyboard, pitch drifting is constantly stopped.
Drifting is enabled when the center view key is hit, mlook is released and
-lookspring is non 0, or when
+lookspring is non 0, or when
===============
*/
void V_DriftPitch (void)
if ( fabs(cl.cmd.forwardmove) < cl_forwardspeed.value)
cl.driftmove = 0;
else
- cl.driftmove += host_frametime;
-
+ cl.driftmove += cl.realframetime;
+
if ( cl.driftmove > v_centermove.value)
{
V_StartPitchDrift ();
}
return;
}
-
+
delta = cl.idealpitch - cl.viewangles[PITCH];
if (!delta)
return;
}
- move = host_frametime * cl.pitchvel;
- cl.pitchvel += host_frametime * v_centerspeed.value;
-
-//Con_Printf ("move: %f (%f)\n", move, host_frametime);
+ move = cl.realframetime * cl.pitchvel;
+ cl.pitchvel += cl.realframetime * v_centerspeed.value;
if (delta > 0)
{
}
+/*
+==============================================================================
+ SCREEN FLASHES
+==============================================================================
+*/
-/*
-==============================================================================
-
- PALETTE FLASHES
-
-==============================================================================
-*/
-
-
-cshift_t cshift_empty = { {130,80,50}, 0 };
-cshift_t cshift_water = { {130,80,50}, 128 };
-cshift_t cshift_slime = { {0,25,5}, 150 };
-cshift_t cshift_lava = { {255,80,0}, 150 };
-
-byte ramps[3][256];
-float v_blend[4]; // rgba 0.0 - 1.0
/*
===============
*/
void V_ParseDamage (void)
{
- int armor, blood;
- vec3_t from;
- int i;
- vec3_t forward, right, up;
- entity_t *ent;
- float side;
- float count;
-
+ int armor, blood;
+ vec3_t from;
+ //vec3_t forward, right;
+ vec3_t localfrom;
+ entity_t *ent;
+ //float side;
+ float count;
+
armor = MSG_ReadByte ();
blood = MSG_ReadByte ();
- for (i=0 ; i<3 ; i++)
- from[i] = MSG_ReadCoord ();
+ MSG_ReadVector(from, cls.protocol);
count = blood*0.5 + armor*0.5;
if (count < 10)
count = 10;
- cl.faceanimtime = cl.time + 0.2; // but sbar face into pain frame
+ cl.faceanimtime = cl.time + 0.2; // put sbar face into pain frame
cl.cshifts[CSHIFT_DAMAGE].percent += 3*count;
if (cl.cshifts[CSHIFT_DAMAGE].percent < 0)
if (cl.cshifts[CSHIFT_DAMAGE].percent > 150)
cl.cshifts[CSHIFT_DAMAGE].percent = 150;
- if (armor > blood)
+ if (armor > blood)
{
cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 200;
cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 100;
cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 0;
}
-//
-// calculate view angle kicks
-//
- ent = &cl_entities[cl.viewentity];
-
- VectorSubtract (from, ent->origin, from);
- VectorNormalize (from);
-
- AngleVectors (ent->angles, forward, right, up);
-
- side = DotProduct (from, right);
- v_dmg_roll = count*side*v_kickroll.value;
-
- side = DotProduct (from, forward);
- v_dmg_pitch = count*side*v_kickpitch.value;
-
- v_dmg_time = v_kicktime.value;
+ // calculate view angle kicks
+ if (cl.entities[cl.viewentity].state_current.active)
+ {
+ ent = &cl.entities[cl.viewentity];
+ Matrix4x4_Transform(&ent->render.inversematrix, from, localfrom);
+ VectorNormalize(localfrom);
+ v_dmg_pitch = count * localfrom[0] * v_kickpitch.value;
+ v_dmg_roll = count * localfrom[1] * v_kickroll.value;
+ v_dmg_time = v_kicktime.value;
+ }
}
+static cshift_t v_cshift;
/*
==================
V_cshift_f
==================
*/
-void V_cshift_f (void)
+static void V_cshift_f (void)
{
- cshift_empty.destcolor[0] = atoi(Cmd_Argv(1));
- cshift_empty.destcolor[1] = atoi(Cmd_Argv(2));
- cshift_empty.destcolor[2] = atoi(Cmd_Argv(3));
- cshift_empty.percent = atoi(Cmd_Argv(4));
+ v_cshift.destcolor[0] = atof(Cmd_Argv(1));
+ v_cshift.destcolor[1] = atof(Cmd_Argv(2));
+ v_cshift.destcolor[2] = atof(Cmd_Argv(3));
+ v_cshift.percent = atof(Cmd_Argv(4));
}
When you run over an item, the server sends this command
==================
*/
-void V_BonusFlash_f (void)
+static void V_BonusFlash_f (void)
{
cl.cshifts[CSHIFT_BONUS].destcolor[0] = 215;
cl.cshifts[CSHIFT_BONUS].destcolor[1] = 186;
}
/*
-=============
-V_SetContentsColor
-
-Underwater, lava, etc each has a color shift
-=============
-*/
-void V_SetContentsColor (int contents)
-{
- cshift_t* c;
- c = &cl.cshifts[CSHIFT_CONTENTS]; // just to shorten the code below
- switch (contents)
- {
- case CONTENTS_EMPTY:
- case CONTENTS_SOLID:
- //cl.cshifts[CSHIFT_CONTENTS] = cshift_empty;
- c->destcolor[0] = cshift_empty.destcolor[0];
- c->destcolor[1] = cshift_empty.destcolor[1];
- c->destcolor[2] = cshift_empty.destcolor[2];
- c->percent = cshift_empty.percent;
- break;
- case CONTENTS_LAVA:
- //cl.cshifts[CSHIFT_CONTENTS] = cshift_lava;
- c->destcolor[0] = cshift_lava.destcolor[0];
- c->destcolor[1] = cshift_lava.destcolor[1];
- c->destcolor[2] = cshift_lava.destcolor[2];
- c->percent = cshift_lava.percent;
- break;
- case CONTENTS_SLIME:
- //cl.cshifts[CSHIFT_CONTENTS] = cshift_slime;
- c->destcolor[0] = cshift_slime.destcolor[0];
- c->destcolor[1] = cshift_slime.destcolor[1];
- c->destcolor[2] = cshift_slime.destcolor[2];
- c->percent = cshift_slime.percent;
- break;
- default:
- //cl.cshifts[CSHIFT_CONTENTS] = cshift_water;
- c->destcolor[0] = cshift_water.destcolor[0];
- c->destcolor[1] = cshift_water.destcolor[1];
- c->destcolor[2] = cshift_water.destcolor[2];
- c->percent = cshift_water.percent;
- }
-}
+==============================================================================
-/*
-=============
-V_CalcPowerupCshift
-=============
-*/
-void V_CalcPowerupCshift (void)
-{
- if (cl.items & IT_QUAD)
- {
- cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0;
- cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 0;
- cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 255;
- cl.cshifts[CSHIFT_POWERUP].percent = 30;
- }
- else if (cl.items & IT_SUIT)
- {
- cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0;
- cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255;
- cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0;
- cl.cshifts[CSHIFT_POWERUP].percent = 20;
- }
- else if (cl.items & IT_INVISIBILITY)
- {
- cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 100;
- cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 100;
- cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 100;
- cl.cshifts[CSHIFT_POWERUP].percent = 100;
- }
- else if (cl.items & IT_INVULNERABILITY)
- {
- cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 255;
- cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255;
- cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0;
- cl.cshifts[CSHIFT_POWERUP].percent = 30;
- }
- else
- cl.cshifts[CSHIFT_POWERUP].percent = 0;
-}
+ VIEW RENDERING
-/*
-=============
-V_CalcBlend
-=============
+==============================================================================
*/
-// LordHavoc: fixed V_CalcBlend
-void V_CalcBlend (void)
-{
- float r, g, b, a, a2;
- int j;
-
- r = 0;
- g = 0;
- b = 0;
- a = 0;
- if (gl_cshiftpercent.value)
- {
- for (j=0 ; j<NUM_CSHIFTS ; j++)
- {
- a2 = ((cl.cshifts[j].percent * gl_cshiftpercent.value) / 100.0) / 255.0;
-
- if (!a2)
- continue;
- if (a2 > 1)
- a2 = 1;
- r += (cl.cshifts[j].destcolor[0]-r) * a2;
- g += (cl.cshifts[j].destcolor[1]-g) * a2;
- b += (cl.cshifts[j].destcolor[2]-b) * a2;
- a = 1 - (1 - a) * (1 - a2); // correct alpha multiply... took a while to find it on the web
- }
- // saturate color (to avoid blending in black)
- if (a)
- {
- a2 = 1 / a;
- r *= a2;
- g *= a2;
- b *= a2;
- }
- }
+extern matrix4x4_t viewmodelmatrix;
- v_blend[0] = bound(0, r * (1.0/255.0), 1);
- v_blend[1] = bound(0, g * (1.0/255.0), 1);
- v_blend[2] = bound(0, b * (1.0/255.0), 1);
- v_blend[3] = bound(0, a , 1);
-}
+#include "cl_collision.h"
+#include "csprogs.h"
/*
-=============
-V_UpdatePalette
-=============
+==================
+V_CalcRefdef
+
+==================
*/
-void V_UpdatePalette (void)
+void V_CalcRefdef (void)
{
- int i, j;
- qboolean new;
-
- V_CalcPowerupCshift ();
-
- new = false;
-
- for (i=0 ; i<NUM_CSHIFTS ; i++)
+ static float oldz;
+ entity_t *ent;
+ float vieworg[3], gunorg[3], viewangles[3];
+ trace_t trace;
+ if(csqc_loaded)
+ return;
+ VectorClear(gunorg);
+ viewmodelmatrix = identitymatrix;
+ r_view.matrix = identitymatrix;
+ if (cls.state == ca_connected && cls.signon == SIGNONS)
{
- if (cl.cshifts[i].percent != cl.prev_cshifts[i].percent)
+ // ent is the view entity (visible when out of body)
+ ent = &cl.entities[cl.viewentity];
+ // player can look around, so take the origin from the entity,
+ // and the angles from the input system
+ Matrix4x4_OriginFromMatrix(&ent->render.matrix, vieworg);
+ VectorCopy(cl.viewangles, viewangles);
+ // interpolate the angles if playing a demo or spectating someone
+ if (cls.demoplayback || cl.fixangle[0])
{
- new = true;
- cl.prev_cshifts[i].percent = cl.cshifts[i].percent;
+ int i;
+ float frac = bound(0, (cl.time - cl.mtime[1]) / (cl.mtime[0] - cl.mtime[1]), 1);
+ for (i = 0;i < 3;i++)
+ {
+ float d = cl.mviewangles[0][i] - cl.mviewangles[1][i];
+ if (d > 180)
+ d -= 360;
+ else if (d < -180)
+ d += 360;
+ viewangles[i] = cl.mviewangles[1][i] + frac * d;
+ }
}
- for (j=0 ; j<3 ; j++)
- if (cl.cshifts[i].destcolor[j] != cl.prev_cshifts[i].destcolor[j])
+ if (cl.intermission)
+ {
+ // entity is a fixed camera, just copy the matrix
+ if (cls.protocol == PROTOCOL_QUAKEWORLD)
+ Matrix4x4_CreateFromQuakeEntity(&r_view.matrix, cl.qw_intermission_origin[0], cl.qw_intermission_origin[1], cl.qw_intermission_origin[2], cl.qw_intermission_angles[0], cl.qw_intermission_angles[1], cl.qw_intermission_angles[2], 1);
+ else
{
- new = true;
- cl.prev_cshifts[i].destcolor[j] = cl.cshifts[i].destcolor[j];
+ r_view.matrix = ent->render.matrix;
+ r_view.matrix.m[2][3] += cl.stats[STAT_VIEWHEIGHT];
}
- }
-
-// drop the damage value
- cl.cshifts[CSHIFT_DAMAGE].percent -= host_frametime*150;
- if (cl.cshifts[CSHIFT_DAMAGE].percent <= 0)
- cl.cshifts[CSHIFT_DAMAGE].percent = 0;
-
-// drop the bonus value
- cl.cshifts[CSHIFT_BONUS].percent -= host_frametime*100;
- if (cl.cshifts[CSHIFT_BONUS].percent <= 0)
- cl.cshifts[CSHIFT_BONUS].percent = 0;
-
- if (!new)
- return;
-
- V_CalcBlend ();
-}
-
-/*
-==============================================================================
-
- VIEW RENDERING
-
-==============================================================================
-*/
-
-float angledelta (float a)
-{
- a = anglemod(a);
- if (a > 180)
- a -= 360;
- return a;
-}
-
-/*
-==================
-CalcGunAngle
-==================
-*/
-void CalcGunAngle (void)
-{
- float yaw, pitch, move;
- static float oldyaw = 0;
- static float oldpitch = 0;
-
- yaw = r_refdef.viewangles[YAW];
- pitch = -r_refdef.viewangles[PITCH];
-
- yaw = angledelta(yaw - r_refdef.viewangles[YAW]) * 0.4;
- if (yaw > 10)
- yaw = 10;
- if (yaw < -10)
- yaw = -10;
- pitch = angledelta(-pitch - r_refdef.viewangles[PITCH]) * 0.4;
- if (pitch > 10)
- pitch = 10;
- if (pitch < -10)
- pitch = -10;
- move = host_frametime*20;
- if (yaw > oldyaw)
- {
- if (oldyaw + move < yaw)
- yaw = oldyaw + move;
- }
- else
- {
- if (oldyaw - move > yaw)
- yaw = oldyaw - move;
- }
-
- if (pitch > oldpitch)
- {
- if (oldpitch + move < pitch)
- pitch = oldpitch + move;
- }
- else
- {
- if (oldpitch - move > pitch)
- pitch = oldpitch - move;
- }
-
- oldyaw = yaw;
- oldpitch = pitch;
-
- cl.viewent.angles[YAW] = r_refdef.viewangles[YAW] + yaw;
- cl.viewent.angles[PITCH] = - (r_refdef.viewangles[PITCH] + pitch);
-
- cl.viewent.angles[ROLL] -= v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value;
- cl.viewent.angles[PITCH] -= v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value;
- cl.viewent.angles[YAW] -= v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value;
-}
-
-/*
-==============
-V_BoundOffsets
-==============
-*/
-void V_BoundOffsets (void)
-{
- entity_t *ent;
-
- ent = &cl_entities[cl.viewentity];
-
-// absolutely bound refresh reletive to entity clipping hull
-// so the view can never be inside a solid wall
-
- if (r_refdef.vieworg[0] < ent->origin[0] - 14)
- r_refdef.vieworg[0] = ent->origin[0] - 14;
- else if (r_refdef.vieworg[0] > ent->origin[0] + 14)
- r_refdef.vieworg[0] = ent->origin[0] + 14;
- if (r_refdef.vieworg[1] < ent->origin[1] - 14)
- r_refdef.vieworg[1] = ent->origin[1] - 14;
- else if (r_refdef.vieworg[1] > ent->origin[1] + 14)
- r_refdef.vieworg[1] = ent->origin[1] + 14;
- if (r_refdef.vieworg[2] < ent->origin[2] - 22)
- r_refdef.vieworg[2] = ent->origin[2] - 22;
- else if (r_refdef.vieworg[2] > ent->origin[2] + 30)
- r_refdef.vieworg[2] = ent->origin[2] + 30;
-}
-
-/*
-==============
-V_AddIdle
-
-Idle swaying
-==============
-*/
-void V_AddIdle (void)
-{
- r_refdef.viewangles[ROLL] += v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value;
- r_refdef.viewangles[PITCH] += v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value;
- r_refdef.viewangles[YAW] += v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value;
-}
-
-
-/*
-==============
-V_CalcViewRoll
+ viewmodelmatrix = r_view.matrix;
+ }
+ else
+ {
+ // apply qw weapon recoil effect (this did not work in QW)
+ // TODO: add a cvar to disable this
+ viewangles[PITCH] += cl.qw_weaponkick;
-Roll is induced by movement and damage
-==============
-*/
-void V_CalcViewRoll (void)
-{
- float side;
-
- side = V_CalcRoll (cl_entities[cl.viewentity].angles, cl.velocity);
- r_refdef.viewangles[ROLL] += side;
+ if (cl.onground)
+ {
+ if (!cl.oldonground)
+ cl.hitgroundtime = cl.time;
+ cl.lastongroundtime = cl.time;
+ }
+ cl.oldonground = cl.onground;
- if (v_dmg_time > 0)
- {
- r_refdef.viewangles[ROLL] += v_dmg_time/v_kicktime.value*v_dmg_roll;
- r_refdef.viewangles[PITCH] += v_dmg_time/v_kicktime.value*v_dmg_pitch;
- v_dmg_time -= host_frametime;
- }
+ // stair smoothing
+ //Con_Printf("cl.onground %i oldz %f newz %f\n", cl.onground, oldz, vieworg[2]);
+ if (cl.onground && oldz < vieworg[2])
+ {
+ oldz += (cl.time - cl.oldtime) * cl_stairsmoothspeed.value;
+ oldz = vieworg[2] = bound(vieworg[2] - 16, oldz, vieworg[2]);
+ }
+ else if (cl.onground && oldz > vieworg[2])
+ {
+ oldz -= (cl.time - cl.oldtime) * cl_stairsmoothspeed.value;
+ oldz = vieworg[2] = bound(vieworg[2], oldz, vieworg[2] + 16);
+ }
+ else
+ oldz = vieworg[2];
- if (cl.stats[STAT_HEALTH] <= 0)
- {
- r_refdef.viewangles[ROLL] = 80; // dead view angle
- return;
+ if (chase_active.value)
+ {
+ // observing entity from third person
+ vec_t camback, camup, dist, forward[3], chase_dest[3];
+
+ camback = bound(0, chase_back.value, 128);
+ if (chase_back.value != camback)
+ Cvar_SetValueQuick(&chase_back, camback);
+ camup = bound(-48, chase_up.value, 96);
+ if (chase_up.value != camup)
+ Cvar_SetValueQuick(&chase_up, camup);
+
+ // this + 22 is to match view_ofs for compatibility with older versions
+ camup += 22;
+
+ if (gamemode == GAME_GOODVSBAD2 && chase_stevie.integer)
+ {
+ // look straight down from high above
+ viewangles[0] = 90;
+ camback = 2048;
+ }
+ AngleVectors(viewangles, forward, NULL, NULL);
+
+ // trace a little further so it hits a surface more consistently (to avoid 'snapping' on the edge of the range)
+ dist = -camback - 8;
+ chase_dest[0] = vieworg[0] + forward[0] * dist;
+ chase_dest[1] = vieworg[1] + forward[1] * dist;
+ chase_dest[2] = vieworg[2] + forward[2] * dist + camup;
+ trace = CL_TraceBox(vieworg, vec3_origin, vec3_origin, chase_dest, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_SKY, false);
+ VectorMAMAM(1, trace.endpos, 8, forward, 4, trace.plane.normal, vieworg);
+ }
+ else
+ {
+ // first person view from entity
+ // angles
+ if (cl.stats[STAT_HEALTH] <= 0 && v_deathtilt.integer)
+ viewangles[ROLL] = v_deathtiltangle.value;
+ VectorAdd(viewangles, cl.punchangle, viewangles);
+ viewangles[ROLL] += V_CalcRoll(cl.viewangles, cl.movement_velocity);
+ if (v_dmg_time > 0)
+ {
+ viewangles[ROLL] += v_dmg_time/v_kicktime.value*v_dmg_roll;
+ viewangles[PITCH] += v_dmg_time/v_kicktime.value*v_dmg_pitch;
+ v_dmg_time -= cl.realframetime;
+ }
+ // origin
+ VectorAdd(vieworg, cl.punchvector, vieworg);
+ vieworg[2] += cl.stats[STAT_VIEWHEIGHT];
+ if (cl.stats[STAT_HEALTH] > 0)
+ {
+ double xyspeed, bob;
+
+ xyspeed = sqrt(cl.movement_velocity[0]*cl.movement_velocity[0] + cl.movement_velocity[1]*cl.movement_velocity[1]);
+ if (cl_bob.value && cl_bobcycle.value)
+ {
+ float cycle;
+ // LordHavoc: this code is *weird*, but not replacable (I think it
+ // should be done in QC on the server, but oh well, quake is quake)
+ // LordHavoc: figured out bobup: the time at which the sin is at 180
+ // degrees (which allows lengthening or squishing the peak or valley)
+ cycle = cl.time / cl_bobcycle.value;
+ cycle -= (int) cycle;
+ if (cycle < cl_bobup.value)
+ cycle = sin(M_PI * cycle / cl_bobup.value);
+ else
+ cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
+ // bob is proportional to velocity in the xy plane
+ // (don't count Z, or jumping messes it up)
+ bob = xyspeed * cl_bob.value;
+ bob = bob*0.3 + bob*0.7*cycle;
+ vieworg[2] += bound(-7, bob, 4);
+ }
+
+ VectorCopy(vieworg, gunorg);
+
+ if (cl_bobmodel.value)
+ {
+ // calculate for swinging gun model
+ // the gun bobs when running on the ground, but doesn't bob when you're in the air.
+ // Sajt: I tried to smooth out the transitions between bob and no bob, which works
+ // for the most part, but for some reason when you go through a message trigger or
+ // pick up an item or anything like that it will momentarily jolt the gun.
+ vec3_t forward, right, up;
+ float bspeed;
+ float s;
+ float t;
+
+ s = cl.time * cl_bobmodel_speed.value;
+ if (cl.onground)
+ {
+ if (cl.time - cl.hitgroundtime < 0.2)
+ {
+ // just hit the ground, speed the bob back up over the next 0.2 seconds
+ t = cl.time - cl.hitgroundtime;
+ t = bound(0, t, 0.2);
+ t *= 5;
+ }
+ else
+ t = 1;
+ }
+ else
+ {
+ // recently left the ground, slow the bob down over the next 0.2 seconds
+ t = cl.time - cl.lastongroundtime;
+ t = 0.2 - bound(0, t, 0.2);
+ t *= 5;
+ }
+
+ bspeed = bound (0, xyspeed, 400) * 0.01f;
+ AngleVectors (viewangles, forward, right, up);
+ bob = bspeed * cl_bobmodel_side.value * sin (s) * t;
+ VectorMA (gunorg, bob, right, gunorg);
+ bob = bspeed * cl_bobmodel_up.value * cos (s * 2) * t;
+ VectorMA (gunorg, bob, up, gunorg);
+ }
+ }
+ }
+ // calculate a view matrix for rendering the scene
+ if (v_idlescale.value)
+ Matrix4x4_CreateFromQuakeEntity(&r_view.matrix, vieworg[0], vieworg[1], vieworg[2], viewangles[0] + v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value, viewangles[1] + v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value, viewangles[2] + v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value, 1);
+ else
+ Matrix4x4_CreateFromQuakeEntity(&r_view.matrix, vieworg[0], vieworg[1], vieworg[2], viewangles[0], viewangles[1], viewangles[2] + v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value, 1);
+ // calculate a viewmodel matrix for use in view-attached entities
+ Matrix4x4_CreateFromQuakeEntity(&viewmodelmatrix, gunorg[0], gunorg[1], gunorg[2], viewangles[0], viewangles[1], viewangles[2], 0.3);
+ VectorCopy(vieworg, csqc_origin);
+ VectorCopy(viewangles, csqc_angles);
+ }
}
-
}
-
-/*
-==================
-V_CalcIntermissionRefdef
-
-==================
-*/
-void V_CalcIntermissionRefdef (void)
+void V_FadeViewFlashs(void)
{
- entity_t *ent, *view;
- float old;
-
-// ent is the player model (visible when out of body)
- ent = &cl_entities[cl.viewentity];
-// view is the weapon model (only visible from inside body)
- view = &cl.viewent;
-
- VectorCopy (ent->origin, r_refdef.vieworg);
- VectorCopy (ent->angles, r_refdef.viewangles);
- view->model = NULL;
-
-// allways idle in intermission
- old = v_idlescale.value;
- v_idlescale.value = 1;
- V_AddIdle ();
- v_idlescale.value = old;
+ // drop the damage value
+ cl.cshifts[CSHIFT_DAMAGE].percent -= (cl.time - cl.oldtime)*150;
+ if (cl.cshifts[CSHIFT_DAMAGE].percent <= 0)
+ cl.cshifts[CSHIFT_DAMAGE].percent = 0;
+ // drop the bonus value
+ cl.cshifts[CSHIFT_BONUS].percent -= (cl.time - cl.oldtime)*100;
+ if (cl.cshifts[CSHIFT_BONUS].percent <= 0)
+ cl.cshifts[CSHIFT_BONUS].percent = 0;
}
-/*
-==================
-V_CalcRefdef
-
-==================
-*/
-void V_CalcRefdef (void)
+void V_CalcViewBlend(void)
{
- entity_t *ent, *view;
- int i;
- vec3_t forward, right, up;
- vec3_t angles;
- float bob;
- static float oldz = 0;
-
- V_DriftPitch ();
-
-// ent is the player model (visible when out of body)
- ent = &cl_entities[cl.viewentity];
-// view is the weapon model (only visible from inside body)
- view = &cl.viewent;
-
-
-// transform the view offset by the model's matrix to get the offset from
-// model origin for the view
- ent->angles[YAW] = cl.viewangles[YAW]; // the model should face the view dir
- ent->angles[PITCH] = -cl.viewangles[PITCH]; // the model should face the view dir
-
-
- bob = V_CalcBob ();
-
-// refresh position
- VectorCopy (ent->origin, r_refdef.vieworg);
- r_refdef.vieworg[2] += cl.viewheight + bob;
-
-// never let it sit exactly on a node line, because a water plane can
-// dissapear when viewed with the eye exactly on it.
-// the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis
- r_refdef.vieworg[0] += 1.0/32;
- r_refdef.vieworg[1] += 1.0/32;
- r_refdef.vieworg[2] += 1.0/32;
-
- VectorCopy (cl.viewangles, r_refdef.viewangles);
- V_CalcViewRoll ();
- V_AddIdle ();
-
-// offsets
- angles[PITCH] = -ent->angles[PITCH]; // because entity pitches are
- // actually backward
- angles[YAW] = ent->angles[YAW];
- angles[ROLL] = ent->angles[ROLL];
-
- AngleVectors (angles, forward, right, up);
-
- for (i=0 ; i<3 ; i++)
- r_refdef.vieworg[i] += scr_ofsx.value*forward[i]
- + scr_ofsy.value*right[i]
- + scr_ofsz.value*up[i];
-
-
- V_BoundOffsets ();
-
-// set up gun position
- VectorCopy (cl.viewangles, view->angles);
-
- CalcGunAngle ();
-
- VectorCopy (ent->origin, view->origin);
- view->origin[2] += cl.viewheight;
-
- for (i=0 ; i<3 ; i++)
+ float a2;
+ int j;
+ r_refdef.viewblend[0] = 0;
+ r_refdef.viewblend[1] = 0;
+ r_refdef.viewblend[2] = 0;
+ r_refdef.viewblend[3] = 0;
+ r_refdef.frustumscale_x = 1;
+ r_refdef.frustumscale_y = 1;
+ if (cls.state == ca_connected && cls.signon == SIGNONS && gl_polyblend.value > 0)
{
- view->origin[i] += forward[i]*bob*0.4;
-// view->origin[i] += right[i]*bob*0.4;
-// view->origin[i] += up[i]*bob*0.8;
- }
- view->origin[2] += bob;
-
-// fudge position around to keep amount of weapon visible
-// roughly equal with different FOV
-
-#if 0
- if (cl.model_precache[cl.stats[STAT_WEAPON]] && strcmp (cl.model_precache[cl.stats[STAT_WEAPON]]->name, "progs/v_shot2.mdl"))
-#endif
-// LordHavoc: everyone hates the gun moving around
-/*
- if (scr_viewsize.value == 110)
- view->origin[2] += 1;
- else if (scr_viewsize.value == 100)
- view->origin[2] += 2;
- else if (scr_viewsize.value == 90)
- view->origin[2] += 1;
- else if (scr_viewsize.value == 80)
- view->origin[2] += 0.5;
-*/
-
- view->model = cl.model_precache[cl.stats[STAT_WEAPON]];
- view->frame = cl.stats[STAT_WEAPONFRAME];
- view->colormap = vid.colormap;
-
-// set up the refresh position
- VectorAdd (r_refdef.viewangles, cl.punchangle, r_refdef.viewangles);
-
-// smooth out stair step ups
-if (cl.onground && ent->origin[2] - oldz > 0)
-{
- float steptime;
-
- steptime = cl.time - cl.oldtime;
- if (steptime < 0)
-//FIXME I_Error ("steptime < 0");
- steptime = 0;
-
- oldz += steptime * 80;
- if (oldz > ent->origin[2])
- oldz = ent->origin[2];
- if (ent->origin[2] - oldz > 12)
- oldz = ent->origin[2] - 12;
- r_refdef.vieworg[2] += oldz - ent->origin[2];
- view->origin[2] += oldz - ent->origin[2];
-}
-else
- oldz = ent->origin[2];
-
- if (chase_active.value)
- Chase_Update ();
-}
-
-/*
-==================
-V_RenderView
+ // set contents color
+ int supercontents;
+ vec3_t vieworigin;
+ Matrix4x4_OriginFromMatrix(&r_view.matrix, vieworigin);
+ supercontents = CL_PointSuperContents(vieworigin);
+ if (supercontents & SUPERCONTENTS_LIQUIDSMASK)
+ {
+ r_refdef.frustumscale_x *= 1 - (((sin(cl.time * 4.7) + 1) * 0.015) * r_waterwarp.value);
+ r_refdef.frustumscale_y *= 1 - (((sin(cl.time * 3.0) + 1) * 0.015) * r_waterwarp.value);
+ if (supercontents & SUPERCONTENTS_LAVA)
+ {
+ cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 255;
+ cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 80;
+ cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 0;
+ }
+ else if (supercontents & SUPERCONTENTS_SLIME)
+ {
+ cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 0;
+ cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 25;
+ cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 5;
+ }
+ else
+ {
+ cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 130;
+ cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 80;
+ cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 50;
+ }
+ cl.cshifts[CSHIFT_CONTENTS].percent = 150 * 0.5;
+ }
+ else
+ {
+ cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 0;
+ cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 0;
+ cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 0;
+ cl.cshifts[CSHIFT_CONTENTS].percent = 0;
+ }
-The player's clipping box goes from (-16 -16 -24) to (16 16 32) from
-the entity origin, so any view position inside that will be valid
-==================
-*/
-extern vrect_t scr_vrect;
+ if (gamemode != GAME_TRANSFUSION)
+ {
+ if (cl.stats[STAT_ITEMS] & IT_QUAD)
+ {
+ cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0;
+ cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 0;
+ cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 255;
+ cl.cshifts[CSHIFT_POWERUP].percent = 30;
+ }
+ else if (cl.stats[STAT_ITEMS] & IT_SUIT)
+ {
+ cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0;
+ cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255;
+ cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0;
+ cl.cshifts[CSHIFT_POWERUP].percent = 20;
+ }
+ else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
+ {
+ cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 100;
+ cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 100;
+ cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 100;
+ cl.cshifts[CSHIFT_POWERUP].percent = 100;
+ }
+ else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY)
+ {
+ cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 255;
+ cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255;
+ cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0;
+ cl.cshifts[CSHIFT_POWERUP].percent = 30;
+ }
+ else
+ cl.cshifts[CSHIFT_POWERUP].percent = 0;
+ }
-void V_RenderView (void)
-{
- if (con_forcedup)
- return;
+ cl.cshifts[CSHIFT_VCSHIFT].destcolor[0] = v_cshift.destcolor[0];
+ cl.cshifts[CSHIFT_VCSHIFT].destcolor[1] = v_cshift.destcolor[1];
+ cl.cshifts[CSHIFT_VCSHIFT].destcolor[2] = v_cshift.destcolor[2];
+ cl.cshifts[CSHIFT_VCSHIFT].percent = v_cshift.percent;
-// don't allow cheats in multiplayer
- if (cl.maxclients > 1)
- {
- Cvar_Set ("scr_ofsx", "0");
- Cvar_Set ("scr_ofsy", "0");
- Cvar_Set ("scr_ofsz", "0");
- }
+ // LordHavoc: fixed V_CalcBlend
+ for (j = 0;j < NUM_CSHIFTS;j++)
+ {
+ a2 = bound(0.0f, cl.cshifts[j].percent * (1.0f / 255.0f), 1.0f);
+ if (a2 > 0)
+ {
+ VectorLerp(r_refdef.viewblend, a2, cl.cshifts[j].destcolor, r_refdef.viewblend);
+ r_refdef.viewblend[3] = (1 - (1 - r_refdef.viewblend[3]) * (1 - a2)); // correct alpha multiply... took a while to find it on the web
+ }
+ }
+ // saturate color (to avoid blending in black)
+ if (r_refdef.viewblend[3])
+ {
+ a2 = 1 / r_refdef.viewblend[3];
+ VectorScale(r_refdef.viewblend, a2, r_refdef.viewblend);
+ }
- if (cl.intermission)
- { // intermission / finale rendering
- V_CalcIntermissionRefdef ();
- }
- else
- {
- if (!cl.paused /* && (sv.maxclients > 1 || key_dest == key_game) */ )
- V_CalcRefdef ();
+ r_refdef.viewblend[0] = bound(0.0f, r_refdef.viewblend[0] * (1.0f/255.0f), 1.0f);
+ r_refdef.viewblend[1] = bound(0.0f, r_refdef.viewblend[1] * (1.0f/255.0f), 1.0f);
+ r_refdef.viewblend[2] = bound(0.0f, r_refdef.viewblend[2] * (1.0f/255.0f), 1.0f);
+ r_refdef.viewblend[3] = bound(0.0f, r_refdef.viewblend[3] * gl_polyblend.value, 1.0f);
}
-
- R_PushDlights ();
-
- R_RenderView ();
}
//============================================================================
*/
void V_Init (void)
{
- Cmd_AddCommand ("v_cshift", V_cshift_f);
- Cmd_AddCommand ("bf", V_BonusFlash_f);
- Cmd_AddCommand ("centerview", V_StartPitchDrift);
+ Cmd_AddCommand ("v_cshift", V_cshift_f, "sets tint color of view");
+ Cmd_AddCommand ("bf", V_BonusFlash_f, "briefly flashes a bright color tint on view (used when items are picked up)");
+ Cmd_AddCommand ("centerview", V_StartPitchDrift, "gradually recenter view (stop looking up/down)");
Cvar_RegisterVariable (&v_centermove);
Cvar_RegisterVariable (&v_centerspeed);
Cvar_RegisterVariable (&v_idlescale);
Cvar_RegisterVariable (&crosshair);
- Cvar_RegisterVariable (&cl_crossx);
- Cvar_RegisterVariable (&cl_crossy);
- Cvar_RegisterVariable (&gl_cshiftpercent);
- Cvar_RegisterVariable (&scr_ofsx);
- Cvar_RegisterVariable (&scr_ofsy);
- Cvar_RegisterVariable (&scr_ofsz);
Cvar_RegisterVariable (&cl_rollspeed);
Cvar_RegisterVariable (&cl_rollangle);
Cvar_RegisterVariable (&cl_bob);
Cvar_RegisterVariable (&cl_bobcycle);
Cvar_RegisterVariable (&cl_bobup);
+ Cvar_RegisterVariable (&cl_bobmodel);
+ Cvar_RegisterVariable (&cl_bobmodel_side);
+ Cvar_RegisterVariable (&cl_bobmodel_up);
+ Cvar_RegisterVariable (&cl_bobmodel_speed);
Cvar_RegisterVariable (&v_kicktime);
Cvar_RegisterVariable (&v_kickroll);
- Cvar_RegisterVariable (&v_kickpitch);
-}
+ Cvar_RegisterVariable (&v_kickpitch);
+ Cvar_RegisterVariable (&cl_stairsmoothspeed);
+
+ Cvar_RegisterVariable (&chase_back);
+ Cvar_RegisterVariable (&chase_up);
+ Cvar_RegisterVariable (&chase_active);
+ if (gamemode == GAME_GOODVSBAD2)
+ Cvar_RegisterVariable (&chase_stevie);
+
+ Cvar_RegisterVariable (&v_deathtilt);
+ Cvar_RegisterVariable (&v_deathtiltangle);
+}