mirror of
https://github.com/nzp-team/glquake.git
synced 2024-11-25 05:21:33 +00:00
1761 lines
42 KiB
C
1761 lines
42 KiB
C
/*
|
|
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 the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
// view.c -- player eye positioning
|
|
|
|
#include "quakedef.h"
|
|
#include "r_local.h"
|
|
|
|
sfx_t *cl_sfx_step[4];
|
|
|
|
/*
|
|
|
|
The view is allowed to move slightly from it's true position for bobbing,
|
|
but if it exceeds 8 pixels linear distance (spherical, not box), the list of
|
|
entities sent from the server may not include everything in the pvs, especially
|
|
when crossing a water boudnary.
|
|
|
|
*/
|
|
|
|
cvar_t lcd_x = {"lcd_x","0"};
|
|
cvar_t lcd_yaw = {"lcd_yaw","0"};
|
|
|
|
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 = {"cl_rollspeed", "200"};
|
|
cvar_t cl_rollangle = {"cl_rollangle", "2.0"};
|
|
|
|
cvar_t cl_bob = {"cl_bob","0.02", false};
|
|
cvar_t cl_bobcycle = {"cl_bobcycle","0.06", false};
|
|
cvar_t cl_bobup = {"cl_bobup","0.02", false};//BLUB changed to 0.02
|
|
|
|
cvar_t cl_sidebobbing = {"cl_sidebobbing","1"};
|
|
cvar_t cl_bobside = {"cl_bobside","0.02"};
|
|
cvar_t cl_bobsidecycle = {"cl_bobsidecycle","0.9"};
|
|
cvar_t cl_bobsideup = {"cl_bobsideup","0.5"};
|
|
|
|
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_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_idlescale = {"v_idlescale", "0", false};
|
|
|
|
cvar_t crosshair = {"crosshair", "1", true};
|
|
|
|
cvar_t gl_cshiftpercent = {"gl_cshiftpercent", "100", false}; //naievil -- wtf is this?
|
|
|
|
float v_dmg_time, v_dmg_roll, v_dmg_pitch;
|
|
|
|
extern int in_forward, in_forward2, in_back;
|
|
|
|
|
|
/*
|
|
===============
|
|
V_CalcRoll
|
|
|
|
Used by view and sv_user
|
|
===============
|
|
*/
|
|
vec3_t forward, right, up;
|
|
|
|
float V_CalcRoll (vec3_t angles, vec3_t velocity)
|
|
{
|
|
float sign;
|
|
float side;
|
|
float value;
|
|
|
|
AngleVectors (angles, forward, right, up);
|
|
side = DotProduct (velocity, right);
|
|
sign = side < 0 ? -1 : 1;
|
|
side = fabsf(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;
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
V_CalcBob
|
|
|
|
===============
|
|
*/
|
|
|
|
// Blub's new V_CalcBob code, both side and pitch are in one, dictated by the (which) parameter
|
|
float V_CalcBob (float speed,float which)//0 = regular, 1 = side bobbing
|
|
{
|
|
float bob = 0;
|
|
float sprint = 1;
|
|
|
|
if (cl.stats[STAT_ZOOM] == 2)
|
|
return;
|
|
|
|
// Bob idle-y, instead of presenting as if in-motion.
|
|
if (speed < 0.1) {
|
|
if(cl.stats[STAT_ZOOM] == 1)
|
|
speed = 0.05;
|
|
else
|
|
speed = 0.25;
|
|
|
|
if (which == 0)
|
|
bob = cl_bobup.value * 10 * speed * (sprint * sprint) * sin(cl.time * 3.25 * sprint);
|
|
else
|
|
bob = cl_bobside.value * 50 * speed * (sprint * sprint * sprint) * sin((cl.time * sprint) - (M_PI * 0.25));
|
|
}
|
|
// Normal walk/sprint bob.
|
|
else {
|
|
if(cl.stats[STAT_ZOOM] == 3)
|
|
sprint = 1.8; //this gets sprinting speed in comparison to walk speed per weapon
|
|
|
|
//12.048 -> 4.3 = 100 -> 36ish, so replace 100 with 36
|
|
if(which == 0)
|
|
bob = cl_bobup.value * 24 * speed * (sprint * sprint) * sin((cl.time * 12.5 * sprint));//Pitch Bobbing 10
|
|
else if(which == 1)
|
|
bob = cl_bobside.value * 24 * speed * (sprint * sprint * sprint) * sin((cl.time * 6.25 * sprint) - (M_PI * 0.25));//Yaw Bobbing 5
|
|
}
|
|
|
|
return bob;
|
|
}
|
|
|
|
//===================================================== View Bobbing =====================================================
|
|
static int lastSound;
|
|
float PlayStepSound(void)
|
|
{
|
|
float num;
|
|
int sound = 0;
|
|
while(1)
|
|
{
|
|
num = (rand ()&0x7fff) / ((float)0x7fff);
|
|
sound = (int)(num * 4);
|
|
sound++;
|
|
if(sound != lastSound)
|
|
break;
|
|
}
|
|
|
|
if(sound == 1)
|
|
S_StartSound (cl.viewentity, 4, cl_sfx_step[0], vec3_origin, 1, 1);
|
|
else if(sound == 2)
|
|
S_StartSound (cl.viewentity, 4, cl_sfx_step[1], vec3_origin, 1, 1);
|
|
else if(sound == 3)
|
|
S_StartSound (cl.viewentity, 4, cl_sfx_step[2], vec3_origin, 1, 1);
|
|
else if(sound == 4)
|
|
S_StartSound (cl.viewentity, 4, cl_sfx_step[3], vec3_origin, 1, 1);
|
|
|
|
lastSound = sound;
|
|
return sound;
|
|
}
|
|
static int canStep;
|
|
|
|
float V_CalcVBob(float speed, float which)
|
|
{
|
|
float bob = 0;
|
|
//float speedMulti = (0.2 + sqrt((cl.velocity[0] * cl.velocity[0]) + (cl.velocity[1] * cl.velocity[1])))/97; We're moving this to parent function to save calculations...
|
|
//was going to multiply by speed in the sine function to step faster when you're moving faster... but it skipped around on points of the sine curve too much
|
|
//It's be much more efficient to just have a constant step speed, though it would look really weird, it's the only way to have a constant step
|
|
|
|
float sprint = 1;
|
|
|
|
if(cl.stats[STAT_ZOOM] == 3)
|
|
sprint = 1.8;
|
|
|
|
if(cl.stats[STAT_ZOOM] == 2)
|
|
return 0;
|
|
|
|
if(sprint == 1)
|
|
{
|
|
if(which == 0)
|
|
bob = speed * 8.6 * (1/sprint) * sin((cl.time * 12.5 * sprint));//10
|
|
else if(which == 1)
|
|
bob = speed * 8.6 * (1/sprint) * sin((cl.time * 6.25 * sprint) - (M_PI * 0.25));//5
|
|
else if(which == 2)
|
|
bob = speed * 8.6 * (1/sprint) * sin((cl.time * 6.25 * sprint) - (M_PI * 0.25));//5
|
|
}
|
|
else
|
|
{
|
|
if(which == 0)
|
|
bob = speed * 8.6 * (1/sprint) * cos((cl.time * 6.25 * sprint));
|
|
else if(which == 1)
|
|
bob = speed * 8.6 * (1/sprint) * cos((cl.time * 12.5 * sprint));
|
|
else if(which == 2)
|
|
bob = speed * 8.6 * (1/sprint) * cos((cl.time * 6.25 * sprint));
|
|
}
|
|
|
|
|
|
if(speed > 0.1 && which == 0)
|
|
{
|
|
if(canStep && sin(cl.time * 12.5 * sprint) < -0.8)
|
|
{
|
|
PlayStepSound();
|
|
canStep = 0;
|
|
}
|
|
if(sin(cl.time * 12.5 * sprint) > 0.9)
|
|
{
|
|
canStep = 1;
|
|
}
|
|
}
|
|
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;
|
|
cl.nodrift = false;
|
|
cl.driftmove = 0;
|
|
}
|
|
}
|
|
|
|
void V_StopPitchDrift (void)
|
|
{
|
|
cl.laststop = cl.time;
|
|
cl.nodrift = true;
|
|
cl.pitchvel = 0;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
V_DriftPitch
|
|
|
|
Moves the client pitch angle towards cl.idealpitch sent by the server.
|
|
|
|
If the user is adjusting pitch manually, either with lookup/lookdown,
|
|
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
|
|
===============
|
|
*/
|
|
void V_DriftPitch (void)
|
|
{
|
|
float delta, move;
|
|
|
|
if (noclip_anglehack || !cl.onground || cls.demoplayback )
|
|
{
|
|
cl.driftmove = 0;
|
|
cl.pitchvel = 0;
|
|
return;
|
|
}
|
|
|
|
// don't count small mouse motion
|
|
if (cl.nodrift)
|
|
{
|
|
if ( fabs(cl.cmd.forwardmove) < cl_forwardspeed)
|
|
cl.driftmove = 0;
|
|
else
|
|
cl.driftmove += host_frametime;
|
|
|
|
if ( cl.driftmove > v_centermove.value)
|
|
{
|
|
V_StartPitchDrift ();
|
|
}
|
|
return;
|
|
}
|
|
|
|
delta = cl.idealpitch - cl.viewangles[PITCH];
|
|
|
|
if (!delta)
|
|
{
|
|
cl.pitchvel = 0;
|
|
return;
|
|
}
|
|
|
|
move = host_frametime * cl.pitchvel;
|
|
cl.pitchvel += host_frametime * v_centerspeed.value;
|
|
|
|
//Con_Printf ("move: %f (%f)\n", move, host_frametime);
|
|
|
|
if (delta > 0)
|
|
{
|
|
if (move > delta)
|
|
{
|
|
cl.pitchvel = 0;
|
|
move = delta;
|
|
}
|
|
cl.viewangles[PITCH] += move;
|
|
}
|
|
else if (delta < 0)
|
|
{
|
|
if (move > -delta)
|
|
{
|
|
cl.pitchvel = 0;
|
|
move = -delta;
|
|
}
|
|
cl.viewangles[PITCH] -= move;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
==============================================================================
|
|
|
|
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 };
|
|
|
|
cvar_t v_gamma = {"gamma", "1.0", true};
|
|
|
|
byte gammatable[256]; // palette is sent through this
|
|
|
|
byte ramps[3][256];
|
|
float v_blend[4]; // rgba 0.0 - 1.0
|
|
|
|
void BuildGammaTable (float g)
|
|
{
|
|
int i, inf;
|
|
|
|
if (g == 1.0)
|
|
{
|
|
for (i=0 ; i<256 ; i++)
|
|
gammatable[i] = i;
|
|
return;
|
|
}
|
|
|
|
for (i=0 ; i<256 ; i++)
|
|
{
|
|
inf = 255 * powf ( (i+0.5f)/255.5f , g ) + 0.5;
|
|
if (inf < 0)
|
|
inf = 0;
|
|
if (inf > 255)
|
|
inf = 255;
|
|
gammatable[i] = inf;
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
V_CheckGamma
|
|
=================
|
|
*/
|
|
qboolean V_CheckGamma (void)
|
|
{
|
|
static float oldgammavalue;
|
|
|
|
if (v_gamma.value == oldgammavalue)
|
|
return false;
|
|
oldgammavalue = v_gamma.value;
|
|
|
|
BuildGammaTable (v_gamma.value);
|
|
vid.recalc_refdef = 1; // force a surface cache flush
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
===============
|
|
V_ParseDamage
|
|
===============
|
|
*/
|
|
void V_ParseDamage (void)
|
|
{
|
|
int armor, blood;
|
|
vec3_t from;
|
|
int i;
|
|
vec3_t forward, right, up;
|
|
entity_t *ent;
|
|
float side;
|
|
float count;
|
|
|
|
armor = MSG_ReadByte ();
|
|
blood = MSG_ReadByte ();
|
|
for (i=0 ; i<3 ; i++)
|
|
from[i] = MSG_ReadCoord ();
|
|
|
|
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.cshifts[CSHIFT_DAMAGE].percent += 3*count;
|
|
if (cl.cshifts[CSHIFT_DAMAGE].percent < 0)
|
|
cl.cshifts[CSHIFT_DAMAGE].percent = 0;
|
|
if (cl.cshifts[CSHIFT_DAMAGE].percent > 150)
|
|
cl.cshifts[CSHIFT_DAMAGE].percent = 150;
|
|
|
|
if (armor > blood)
|
|
{
|
|
cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 200;
|
|
cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 100;
|
|
cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 100;
|
|
}
|
|
else if (armor)
|
|
{
|
|
cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 220;
|
|
cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 50;
|
|
cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 50;
|
|
}
|
|
else
|
|
{
|
|
cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 255;
|
|
cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 0;
|
|
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;
|
|
}
|
|
|
|
|
|
/*
|
|
==================
|
|
V_cshift_f
|
|
==================
|
|
*/
|
|
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_BonusFlash_f
|
|
|
|
When you run over an item, the server sends this command
|
|
==================
|
|
*/
|
|
void V_BonusFlash_f (void)
|
|
{
|
|
cl.cshifts[CSHIFT_BONUS].destcolor[0] = 215;
|
|
cl.cshifts[CSHIFT_BONUS].destcolor[1] = 186;
|
|
cl.cshifts[CSHIFT_BONUS].destcolor[2] = 69;
|
|
cl.cshifts[CSHIFT_BONUS].percent = 50;
|
|
}
|
|
|
|
/*
|
|
=============
|
|
V_SetContentsColor
|
|
|
|
Underwater, lava, etc each has a color shift
|
|
=============
|
|
*/
|
|
void V_SetContentsColor (int contents)
|
|
{
|
|
switch (contents)
|
|
{
|
|
case CONTENTS_EMPTY:
|
|
case CONTENTS_SOLID:
|
|
cl.cshifts[CSHIFT_CONTENTS] = cshift_empty;
|
|
break;
|
|
case CONTENTS_LAVA:
|
|
cl.cshifts[CSHIFT_CONTENTS] = cshift_lava;
|
|
break;
|
|
case CONTENTS_SLIME:
|
|
cl.cshifts[CSHIFT_CONTENTS] = cshift_slime;
|
|
break;
|
|
default:
|
|
cl.cshifts[CSHIFT_CONTENTS] = cshift_water;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
=============
|
|
V_HealthCshift
|
|
=============
|
|
*/
|
|
void V_HealthCshift (void)
|
|
{
|
|
int pulse_value, pulseadd;
|
|
float tempi1, tempi2, tempi3, tempi4;
|
|
if (cl.stats[STAT_HEALTH] < 100 && cl.stats[STAT_HEALTH])
|
|
{
|
|
cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 255;
|
|
cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 0;
|
|
cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 0;
|
|
|
|
if (cl.stats[STAT_HEALTH] < 50)
|
|
{
|
|
pulse_value = abs(((int)(realtime*100)&100) - 50);
|
|
pulseadd = 50;
|
|
}
|
|
else
|
|
{
|
|
pulse_value = abs(((int)(realtime*50)&20) - 10);
|
|
pulseadd = 10;
|
|
}
|
|
tempi1 = cl.stats[STAT_HEALTH] + pulse_value;
|
|
tempi2 = 100 + pulseadd;
|
|
tempi3 = tempi1/tempi2;
|
|
tempi4 = 200 - (tempi3*255);
|
|
if (tempi4 < 0)
|
|
tempi4 = 0;
|
|
cl.cshifts[CSHIFT_DAMAGE].percent = (int)tempi4;
|
|
}
|
|
else
|
|
cl.cshifts[CSHIFT_DAMAGE].percent = 0;
|
|
}
|
|
|
|
/*
|
|
=============
|
|
V_CalcBlend
|
|
=============
|
|
*/
|
|
void V_CalcBlend (void)
|
|
{
|
|
float r, g, b, a, a2;
|
|
int j;
|
|
|
|
r = 0;
|
|
g = 0;
|
|
b = 0;
|
|
a = 0;
|
|
|
|
for (j=0 ; j<NUM_CSHIFTS ; j++)
|
|
{
|
|
if (!gl_polyblend.value) {
|
|
continue;
|
|
}
|
|
|
|
a2 = cl.cshifts[j].percent / 255.0;
|
|
// a2 = cl.cshifts[j].percent/255.0;
|
|
if (!a2)
|
|
continue;
|
|
a = a + a2*(1-a);
|
|
//Con_Printf ("j:%i a:%f\n", j, a);
|
|
a2 = a2/a;
|
|
r = r*(1-a2) + cl.cshifts[j].destcolor[0]*a2;
|
|
g = g*(1-a2) + cl.cshifts[j].destcolor[1]*a2;
|
|
b = b*(1-a2) + cl.cshifts[j].destcolor[2]*a2;
|
|
}
|
|
|
|
v_blend[0] = r/255.0;
|
|
v_blend[1] = g/255.0;
|
|
v_blend[2] = b/255.0;
|
|
v_blend[3] = a;
|
|
if (v_blend[3] > 1)
|
|
v_blend[3] = 1;
|
|
if (v_blend[3] < 0)
|
|
v_blend[3] = 0;
|
|
}
|
|
|
|
/*
|
|
=============
|
|
V_UpdatePalette
|
|
=============
|
|
*/
|
|
void V_UpdatePalette (void)
|
|
{
|
|
int i, j;
|
|
qboolean new;
|
|
byte *basepal, *newpal;
|
|
byte pal[768];
|
|
float r,g,b,a;
|
|
int ir, ig, ib;
|
|
qboolean force;
|
|
|
|
//V_HealthCshift ();
|
|
|
|
new = false;
|
|
|
|
for (i=0 ; i<NUM_CSHIFTS ; i++)
|
|
{
|
|
if (cl.cshifts[i].percent != cl.prev_cshifts[i].percent)
|
|
{
|
|
new = true;
|
|
cl.prev_cshifts[i].percent = cl.cshifts[i].percent;
|
|
}
|
|
for (j=0 ; j<3 ; j++)
|
|
if (cl.cshifts[i].destcolor[j] != cl.prev_cshifts[i].destcolor[j])
|
|
{
|
|
new = true;
|
|
cl.prev_cshifts[i].destcolor[j] = cl.cshifts[i].destcolor[j];
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
|
|
force = V_CheckGamma ();
|
|
if (!new && !force)
|
|
return;
|
|
|
|
V_CalcBlend ();
|
|
|
|
a = v_blend[3];
|
|
r = 255*v_blend[0]*a;
|
|
g = 255*v_blend[1]*a;
|
|
b = 255*v_blend[2]*a;
|
|
|
|
a = 1-a;
|
|
for (i=0 ; i<256 ; i++)
|
|
{
|
|
ir = i*a + r;
|
|
ig = i*a + g;
|
|
ib = i*a + b;
|
|
if (ir > 255)
|
|
ir = 255;
|
|
if (ig > 255)
|
|
ig = 255;
|
|
if (ib > 255)
|
|
ib = 255;
|
|
|
|
ramps[0][i] = gammatable[ir];
|
|
ramps[1][i] = gammatable[ig];
|
|
ramps[2][i] = gammatable[ib];
|
|
}
|
|
|
|
basepal = host_basepal;
|
|
newpal = pal;
|
|
|
|
for (i=0 ; i<256 ; i++)
|
|
{
|
|
ir = basepal[0];
|
|
ig = basepal[1];
|
|
ib = basepal[2];
|
|
basepal += 3;
|
|
|
|
newpal[0] = ramps[0][ir];
|
|
newpal[1] = ramps[1][ig];
|
|
newpal[2] = ramps[2][ib];
|
|
newpal += 3;
|
|
}
|
|
|
|
VID_ShiftPalette (pal);
|
|
}
|
|
|
|
|
|
/*
|
|
==============================================================================
|
|
|
|
VIEW RENDERING
|
|
|
|
==============================================================================
|
|
*/
|
|
|
|
float angledelta (float a)
|
|
{
|
|
a = anglemod(a);
|
|
if (a > 180)
|
|
a -= 360;
|
|
return a;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
CalcGunAngle
|
|
==================
|
|
*/
|
|
|
|
static float OldYawTheta;
|
|
static float OldPitchTheta;
|
|
|
|
|
|
static vec3_t cADSOfs;
|
|
|
|
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;
|
|
|
|
|
|
//=========Strafe-Roll=========
|
|
//Creating backup
|
|
CWeaponRot[PITCH] = cl.viewent.angles[PITCH] * -1;
|
|
CWeaponRot[YAW] = cl.viewent.angles[YAW] * -1;
|
|
CWeaponRot[ROLL] = cl.viewent.angles[ROLL] * -1;
|
|
|
|
float side;
|
|
side = V_CalcRoll (cl_entities[cl.viewentity].angles, cl.velocity);
|
|
cl.viewent.angles[ROLL] = angledelta(cl.viewent.angles[ROLL] - ((cl.viewent.angles[ROLL] - (side * 5)) * 0.5));
|
|
|
|
//^^^ Model swaying
|
|
if(cl.stats[STAT_ZOOM] == 1)
|
|
{
|
|
cl.viewent.angles[YAW] = (r_refdef.viewangles[YAW] + yaw) - (angledelta((r_refdef.viewangles[YAW] + yaw) - OldYawTheta ) * 0.3);//0.6
|
|
}
|
|
else
|
|
{
|
|
cl.viewent.angles[YAW] = (r_refdef.viewangles[YAW] + yaw) - (angledelta((r_refdef.viewangles[YAW] + yaw) - OldYawTheta ) * 0.6);//0.6
|
|
}
|
|
|
|
cl.viewent.angles[PITCH] = -1 * ((r_refdef.viewangles[PITCH] + pitch) - (angledelta((r_refdef.viewangles[PITCH] + pitch) + OldPitchTheta ) * 0.2));
|
|
|
|
//cl.viewent.angles[PITCH] = - (r_refdef.viewangles[PITCH] + pitch);
|
|
|
|
//BLUBS STOPS HERE
|
|
OldYawTheta = cl.viewent.angles[YAW];
|
|
OldPitchTheta = cl.viewent.angles[PITCH];
|
|
//readd this
|
|
cl.viewent2.angles[ROLL] = cl.viewent.angles[ROLL] -= v_idlescale.value * sinf(cl.time*v_iroll_cycle.value * 2) * v_iroll_level.value;
|
|
cl.viewent2.angles[PITCH] = cl.viewent.angles[PITCH] -= v_idlescale.value * sinf(cl.time*v_ipitch_cycle.value * 2) * v_ipitch_level.value;
|
|
cl.viewent2.angles[YAW] = cl.viewent.angles[YAW] -= v_idlescale.value * sinf(cl.time*v_iyaw_cycle.value * 2) * v_iyaw_level.value;
|
|
|
|
//Evaluating total offset
|
|
CWeaponRot[PITCH] -= cl.viewent.angles[PITCH];
|
|
CWeaponRot[YAW] += cl.viewent.angles[YAW];
|
|
CWeaponRot[ROLL] += cl.viewent.angles[ROLL];
|
|
|
|
}
|
|
|
|
/*
|
|
==============
|
|
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] + 32)
|
|
r_refdef.vieworg[2] = ent->origin[2] + 32;
|
|
}
|
|
|
|
/*
|
|
==============
|
|
V_AddIdle
|
|
|
|
Idle swaying
|
|
==============
|
|
*/
|
|
void V_AddIdle (void)
|
|
{
|
|
r_refdef.viewangles[ROLL] += v_idlescale.value * sinf(cl.time*v_iroll_cycle.value) * v_iroll_level.value;
|
|
r_refdef.viewangles[PITCH] += v_idlescale.value * sinf(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value;
|
|
r_refdef.viewangles[YAW] += v_idlescale.value * sinf(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value;
|
|
}
|
|
|
|
|
|
/*
|
|
==============
|
|
V_CalcViewRoll
|
|
|
|
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 (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;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
==================
|
|
V_CalcIntermissionRefdef
|
|
|
|
==================
|
|
*/
|
|
void V_CalcIntermissionRefdef (void)
|
|
{
|
|
entity_t *ent, *view, *view2;
|
|
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;
|
|
view2 = &cl.viewent2;
|
|
|
|
VectorCopy (ent->origin, r_refdef.vieworg);
|
|
VectorCopy (ent->angles, r_refdef.viewangles);
|
|
view->model = NULL;
|
|
view2->model = NULL;
|
|
|
|
// allways idle in intermission
|
|
old = v_idlescale.value;
|
|
v_idlescale.value = 1;
|
|
V_AddIdle ();
|
|
v_idlescale.value = old;
|
|
}
|
|
|
|
float ApproxEqual(float A, float B)
|
|
{
|
|
if((A-B) < -0.001)
|
|
return 0;
|
|
if(A-B > 0.001)
|
|
return 0;
|
|
|
|
//Con_Printf ("%f",sinf(M_PI));
|
|
|
|
return 1;
|
|
};
|
|
|
|
/*
|
|
==================
|
|
Weapon ADS Declarations
|
|
==================
|
|
*/
|
|
void GetWeaponADSOfs(vec2_t out)
|
|
{
|
|
switch(cl.stats[STAT_ACTIVEWEAPON])
|
|
{
|
|
case W_COLT:
|
|
{
|
|
//out[0] = -15.281;
|
|
//out[1] = 5.0677;
|
|
out[0] = -5.4792;
|
|
out[1] = 1.6500;
|
|
return;
|
|
}
|
|
case W_KAR:
|
|
{
|
|
//out[0] = -15.4472;
|
|
//out[1] = 8.75790;
|
|
out[0] = -5.4959;
|
|
out[1] = 3.1869;
|
|
return;
|
|
}
|
|
case W_KAR_SCOPE:
|
|
{
|
|
//out[0] = -15.4472;
|
|
//out[1] = 1.8985;
|
|
out[0] = -5.2860;
|
|
out[1] = 0.7061;
|
|
return;
|
|
}
|
|
case W_THOMPSON:
|
|
{
|
|
//out[0] = -14.0936;
|
|
//out[1] = 6.7265;
|
|
out[0] = -6.0693;
|
|
out[1] = 3.0076;
|
|
return;
|
|
}
|
|
case W_TRENCH:
|
|
{
|
|
//out[0] = -20.5952;
|
|
//out[1] = 10.1903;
|
|
out[0] = -5.5271;
|
|
out[1] = 2.8803;
|
|
return;
|
|
}
|
|
case W_357:
|
|
{
|
|
//out[0] = -15.3425;
|
|
//out[1] = 3.7888;
|
|
out[0] = -8.3065;
|
|
out[1] = 0.8792;
|
|
return;
|
|
}
|
|
case W_MG:
|
|
{
|
|
out[0] = -6.6437;
|
|
out[1] = 3.5092;
|
|
return;
|
|
}
|
|
case W_DB:
|
|
{
|
|
out[0] = -5.8017;
|
|
out[1] = 2.9121;
|
|
return;
|
|
}
|
|
case W_SAWNOFF:
|
|
{
|
|
out[0] = -5.8017;
|
|
out[1] = 2.9121;
|
|
return;
|
|
}
|
|
case W_M1A1:
|
|
{
|
|
out[0] = -5.3878;
|
|
out[1] = 3.6719;
|
|
return;
|
|
}
|
|
case W_BAR:
|
|
{
|
|
out[0] = -3.8833;
|
|
//out[1] = 2.3745;
|
|
out[1] = 2.6745;
|
|
return;
|
|
}
|
|
default:
|
|
{
|
|
//Large values > 20ish cause weapon to flicker, scale model down if we encounter!
|
|
//Scale better be 4.3, or else viewbobbing is going to be inaccurate.
|
|
out[0] = -5.4792;
|
|
out[1] = 1.6500;
|
|
return;
|
|
}
|
|
}
|
|
};
|
|
/*
|
|
==================
|
|
V_CalcRefdef
|
|
|
|
==================
|
|
*/
|
|
|
|
|
|
static float lastUpVelocity;
|
|
static float VerticalOffset;
|
|
static float cVerticalOffset;
|
|
vec3_t CWeaponOffset;//blubs declared this
|
|
vec3_t CWeaponRot;
|
|
|
|
extern double crosshair_spread_time;
|
|
void DropRecoilKick (void)
|
|
{
|
|
float len;
|
|
|
|
if (crosshair_spread_time > sv.time)
|
|
return;
|
|
len = VectorNormalize (cl.gun_kick);
|
|
|
|
//Con_Printf ("len = %f\n",len);
|
|
len = len - 5*host_frametime;
|
|
if (len < 0)
|
|
len = 0;
|
|
VectorScale (cl.gun_kick, len, cl.gun_kick);
|
|
//Con_Printf ("len final = %f\n",len);
|
|
}
|
|
vec3_t lastPunchAngle;
|
|
void V_CalcRefdef (void)
|
|
{
|
|
entity_t *ent, *view, *view2;
|
|
int i;
|
|
vec3_t forward, right, up;
|
|
vec3_t angles;
|
|
|
|
static float oldz = 0;
|
|
|
|
V_DriftPitch ();
|
|
DropRecoilKick();
|
|
|
|
// 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;
|
|
view2 = &cl.viewent2;
|
|
|
|
// 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
|
|
|
|
//Blubs Bobbing calculations were here, moved them down to be right above bob code block
|
|
|
|
// refresh position
|
|
VectorCopy (ent->origin, r_refdef.vieworg);
|
|
r_refdef.vieworg[2] += cl.viewheight;//blubs removed "+ bob", it's added again below actually...
|
|
|
|
// 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 backwards
|
|
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);
|
|
//cl.oldviewangles = cl.viewangles;
|
|
|
|
CalcGunAngle ();
|
|
|
|
view->angles[PITCH] = view->angles[PITCH] - cl.gun_kick[PITCH];
|
|
view->angles[YAW] = view->angles[YAW] + cl.gun_kick[YAW];
|
|
VectorCopy (ent->origin, view->origin);
|
|
view->origin[2] += cl.viewheight;
|
|
|
|
//Storing base location, later to calculate total offset
|
|
CWeaponOffset[0]= view->origin[0] * -1;
|
|
CWeaponOffset[1]= view->origin[1] * -1;
|
|
CWeaponOffset[2]= view->origin[2] * -1;
|
|
|
|
|
|
//Angle Vectors used by landing and iron sights, so do it here
|
|
vec3_t temp_up,temp_right,temp_forward;
|
|
AngleVectors (r_refdef.viewangles,temp_forward, temp_right, temp_up);
|
|
//============================================================ Fall Landing Buffering ============================================================
|
|
if(lastUpVelocity < cl.velocity[2] - 5)//We've had a dramatic change in velocity
|
|
{
|
|
VerticalOffset = (lastUpVelocity - cl.velocity[2])/25;
|
|
if(VerticalOffset < -15)
|
|
{
|
|
VerticalOffset = -15;
|
|
}
|
|
}
|
|
|
|
cVerticalOffset += (VerticalOffset - cVerticalOffset) * 0.3;
|
|
|
|
temp_up[0] *= cVerticalOffset;
|
|
temp_up[1] *= cVerticalOffset;
|
|
temp_up[2] *= cVerticalOffset;
|
|
|
|
view->origin[0] +=(temp_up[0]);
|
|
view->origin[1] +=(temp_up[1]);
|
|
view->origin[2] +=(temp_up[2]);
|
|
|
|
if(cVerticalOffset > VerticalOffset - 2 && cVerticalOffset < VerticalOffset + 2)//Close enough to goal
|
|
{
|
|
VerticalOffset = 0;
|
|
}
|
|
lastUpVelocity = cl.velocity[2];
|
|
|
|
//============================================================ Engine-Side Iron Sights ============================================================
|
|
AngleVectors (r_refdef.viewangles, temp_forward, temp_right, temp_up);
|
|
|
|
vec3_t ADSOffset;
|
|
if(cl.stats[STAT_ZOOM] == 1 || cl.stats[STAT_ZOOM] == 2)
|
|
{
|
|
ADSOffset[0] = sv_player->v.ADS_Offset[0];
|
|
ADSOffset[1] = sv_player->v.ADS_Offset[1];
|
|
ADSOffset[2] = sv_player->v.ADS_Offset[2];
|
|
|
|
ADSOffset[0] = ADSOffset[0]/1000;
|
|
ADSOffset[1] = ADSOffset[1]/1000;
|
|
ADSOffset[2] = ADSOffset[2]/1000;
|
|
}
|
|
else
|
|
{
|
|
ADSOffset[0] = 0;
|
|
ADSOffset[1] = 0;
|
|
ADSOffset[2] = 0;
|
|
}
|
|
//Side offset
|
|
cADSOfs [0] += (ADSOffset[0] - cADSOfs[0]) * 0.25;
|
|
cADSOfs [1] += (ADSOffset[1] - cADSOfs[1]) * 0.25;
|
|
cADSOfs [2] += (ADSOffset[2] - cADSOfs[2]) * 0.25;
|
|
|
|
temp_right[0] *= cADSOfs[0];
|
|
temp_right[1] *= cADSOfs[0];
|
|
temp_right[2] *= cADSOfs[0];
|
|
|
|
temp_up[0] *= cADSOfs[1];
|
|
temp_up[1] *= cADSOfs[1];
|
|
temp_up[2] *= cADSOfs[1];
|
|
|
|
temp_forward[0] *= cADSOfs[2];
|
|
temp_forward[1] *= cADSOfs[2];
|
|
temp_forward[2] *= cADSOfs[2];
|
|
|
|
view->origin[0] +=(temp_forward[0] + temp_right[0] + temp_up[0]);
|
|
view->origin[1] +=(temp_forward[1] + temp_right[1] + temp_up[1]);
|
|
view->origin[2] +=(temp_forward[2] + temp_right[2] + temp_up[2]);
|
|
|
|
float speed = (0.2 + sqrt((cl.velocity[0] * cl.velocity[0]) + (cl.velocity[1] * cl.velocity[1])));
|
|
speed = speed/190;
|
|
|
|
float bob, bobside = 0;
|
|
|
|
if (cl_sidebobbing.value)
|
|
bobside = V_CalcBob(speed,1);
|
|
bob = V_CalcBob (speed,0);
|
|
|
|
//============================ Weapon Bobbing Code Block=================================
|
|
for (i=0 ; i<3 ; i++)
|
|
{
|
|
if (cl_sidebobbing.value)
|
|
{
|
|
view->origin[i] += right[i]*bobside*0.4;
|
|
view->origin[i] += up[i]*bob*0.5;
|
|
// view2->origin[i] += right[i]*bobside*0.2;
|
|
// view2->origin[i] += up[i]*bob*0.2;
|
|
// mz->origin[i] += right[i]*bobside*0.2;
|
|
// mz->origin[i] += up[i]*bob*0.2;
|
|
}
|
|
else
|
|
{
|
|
view->origin[i] += forward[i]*bob*0.4;
|
|
// view2->origin[i] += forward[i]*bob*0.4;
|
|
// mz->origin[i] += forward[i]*bob*0.4;
|
|
}
|
|
}
|
|
|
|
//view->origin[2] += bob * 2;//Removed because it added bobbing 2 times, we need to have more control than that, removed all multipliers but
|
|
|
|
// view2->origin[2] += bob;
|
|
// mz->origin[2] += bob;
|
|
|
|
//=============================== Added View Bobbing Code Block (Blubs wuz here)=======================
|
|
vec3_t vbob;
|
|
vbob[0] = V_CalcVBob(speed,0) * cl_bob.value * 50;//cl_bob * 50 undo each other, but we want to give some control to people to limit view bobbing
|
|
vbob[1] = V_CalcVBob(speed,1) * cl_bob.value * 50;
|
|
vbob[2] = V_CalcVBob(speed,2) * cl_bob.value * 50;
|
|
|
|
r_refdef.viewangles[YAW] = angledelta(r_refdef.viewangles[YAW] + (vbob[0] * 0.1));
|
|
r_refdef.viewangles[PITCH] = angledelta(r_refdef.viewangles[PITCH] + (vbob[1] * 0.1));
|
|
r_refdef.viewangles[ROLL] = anglemod(r_refdef.viewangles[ROLL] + (vbob[2] * 0.05));
|
|
|
|
|
|
|
|
//Here we finally set CWeaponOffset by the total weapon model offset, used for mzfl which uses CWeaponOffset variable.
|
|
CWeaponOffset[0] += view->origin[0];
|
|
CWeaponOffset[1] += view->origin[1];
|
|
CWeaponOffset[2] += view->origin[2];
|
|
//I don't know what the comments below this are, but blubs didn't add them...
|
|
|
|
// fudge position around to keep amount of weapon visible
|
|
// roughly equal with different FOV
|
|
|
|
view->model = cl.model_precache[cl.stats[STAT_WEAPON]];
|
|
view->frame = cl.stats[STAT_WEAPONFRAME];
|
|
view->skinnum = cl.stats[STAT_WEAPONSKIN];
|
|
view->colormap = vid.colormap;
|
|
|
|
view2->model = cl.model_precache[cl.stats[STAT_WEAPON2]];
|
|
view2->frame = cl.stats[STAT_WEAPON2FRAME];
|
|
view2->skinnum = cl.stats[STAT_WEAPON2SKIN];
|
|
view2->colormap = vid.colormap;
|
|
// set up the refresh position
|
|
|
|
//blubs's punchangle interpolation
|
|
lastPunchAngle[0] += (cl.punchangle[0] - lastPunchAngle[0]) * 0.5;
|
|
lastPunchAngle[1] += (cl.punchangle[1] - lastPunchAngle[1]) * 0.5;
|
|
lastPunchAngle[2] += (cl.punchangle[2] - lastPunchAngle[2]) * 0.5;
|
|
//VectorCopy(cl.punchangle,lastPunchAngle);
|
|
|
|
VectorAdd (r_refdef.viewangles, lastPunchAngle, r_refdef.viewangles);
|
|
//VectorCopy(cl.punchangle,lastPunchAngle);
|
|
|
|
VectorAdd (r_refdef.viewangles, cl.gun_kick, 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 ();
|
|
|
|
view2->origin[0] = view->origin[0];
|
|
view2->origin[1] = view->origin[1];
|
|
view2->origin[2] = view->origin[2];
|
|
|
|
view2->angles[0] = view->angles[0];
|
|
view2->angles[1] = view->angles[1];
|
|
view2->angles[2] = view->angles[2];
|
|
|
|
}
|
|
//================
|
|
// Blub's magical debug tracemove, begin debug functions here
|
|
//================
|
|
/*
|
|
int EN_Find(int num,char *string);
|
|
|
|
void drawbbox (vec3_t start,vec3_t mins,vec3_t maxs,vec3_t end,int color)
|
|
{
|
|
vec3_t colorVec;
|
|
if(color == 1)
|
|
{
|
|
colorVec[0] = 0; colorVec[1] = 1; colorVec[2] = 1;
|
|
}
|
|
if(color == 0)
|
|
{
|
|
colorVec[0] = 1; colorVec[1] = 0; colorVec[2] = 0;
|
|
}
|
|
if(color == -1)
|
|
{
|
|
colorVec[0] = 1; colorVec[1] = 0.5; colorVec[2] = 0.5;
|
|
}
|
|
|
|
//Goal Tracebox
|
|
if(color >= 6 && color < 7)
|
|
{
|
|
colorVec[0] = 1; colorVec[1] = 1; colorVec[2] = 0;
|
|
}
|
|
if(color == 7)
|
|
{
|
|
colorVec[0] = 0; colorVec[1] = 1; colorVec[2] = 0;
|
|
}
|
|
|
|
//Down Tracebox
|
|
if(color == 2)
|
|
{
|
|
colorVec[0] = 0.25; colorVec[1] = 0.2; colorVec[2] = 0.2;
|
|
}
|
|
if(color > 2 && color <= 3)
|
|
{
|
|
colorVec[0] = 1; colorVec[1] = 0.5; colorVec[2] = 0.25;
|
|
}
|
|
|
|
//Up Tracebox
|
|
if(color >= 4 && color < 5)
|
|
{
|
|
colorVec[0] = 1; colorVec[1] = 0; colorVec[2] = 1;
|
|
}
|
|
if(color == 5)
|
|
{
|
|
colorVec[0] = 0; colorVec[1] = 0; colorVec[2] = 1;
|
|
}
|
|
|
|
|
|
vec3_t boxmins,boxmaxs;
|
|
int i;
|
|
|
|
if(start[0] == end[0] && start[1] == end[1] && start[2] == end[2])
|
|
{
|
|
for(i = 0; i < 3; i++)
|
|
{
|
|
boxmins[i] = start[i] + mins[i];
|
|
boxmaxs[i] = start[i] + maxs[i];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i=0 ; i<3 ; i++)
|
|
{
|
|
if (end[i] > start[i])
|
|
{
|
|
boxmins[i] = start[i] + mins[i] - 1;
|
|
boxmaxs[i] = end[i] + maxs[i] + 1;
|
|
}
|
|
else
|
|
{
|
|
boxmins[i] = end[i] + mins[i] - 1;
|
|
boxmaxs[i] = start[i] + maxs[i] + 1;
|
|
}
|
|
}
|
|
}
|
|
vec3_t start1,end1;
|
|
|
|
//Drawing resultant box
|
|
//Bottom Square
|
|
start1[0] = boxmins[0]; start1[1] = boxmins[1]; start1[2] = boxmins[2];
|
|
end1[0] = boxmins[0]; end1[1] = boxmaxs[1]; end1[2] = boxmins[2];
|
|
R_DrawLine(start1,end1,colorVec);
|
|
|
|
start1[0] = boxmins[0]; start1[1] = boxmaxs[1]; start1[2] = boxmins[2];
|
|
end1[0] = boxmaxs[0]; end1[1] = boxmaxs[1]; end1[2] = boxmins[2];
|
|
R_DrawLine(start1,end1,colorVec);
|
|
|
|
start1[0] = boxmaxs[0]; start1[1] = boxmaxs[1]; start1[2] = boxmins[2];
|
|
end1[0] = boxmaxs[0]; end1[1] = boxmins[1]; end1[2] = boxmins[2];
|
|
R_DrawLine(start1,end1,colorVec);
|
|
|
|
start1[0] = boxmaxs[0]; start1[1] = boxmins[1]; start1[2] = boxmins[2];
|
|
end1[0] = boxmins[0]; end1[1] = boxmins[1]; end1[2] = boxmins[2];
|
|
R_DrawLine(start1,end1,colorVec);
|
|
|
|
|
|
//Top square
|
|
start1[0] = boxmins[0]; start1[1] = boxmins[1]; start1[2] = boxmaxs[2];
|
|
end1[0] = boxmins[0]; end1[1] = boxmaxs[1]; end1[2] = boxmaxs[2];
|
|
R_DrawLine(start1,end1,colorVec);
|
|
|
|
start1[0] = boxmins[0]; start1[1] = boxmaxs[1]; start1[2] = boxmaxs[2];
|
|
end1[0] = boxmaxs[0]; end1[1] = boxmaxs[1]; end1[2] = boxmaxs[2];
|
|
R_DrawLine(start1,end1,colorVec);
|
|
|
|
start1[0] = boxmaxs[0]; start1[1] = boxmaxs[1]; start1[2] = boxmaxs[2];
|
|
end1[0] = boxmaxs[0]; end1[1] = boxmins[1]; end1[2] = boxmaxs[2];
|
|
R_DrawLine(start1,end1,colorVec);
|
|
|
|
start1[0] = boxmaxs[0]; start1[1] = boxmins[1]; start1[2] = boxmaxs[2];
|
|
end1[0] = boxmins[0]; end1[1] = boxmins[1]; end1[2] = boxmaxs[2];
|
|
R_DrawLine(start1,end1,colorVec);
|
|
|
|
//Side Lines
|
|
start1[0] = boxmins[0]; start1[1] = boxmins[1]; start1[2] = boxmins[2];
|
|
end1[0] = boxmins[0]; end1[1] = boxmins[1]; end1[2] = boxmaxs[2];
|
|
R_DrawLine(start1,end1,colorVec);
|
|
|
|
start1[0] = boxmins[0]; start1[1] = boxmaxs[1]; start1[2] = boxmins[2];
|
|
end1[0] = boxmins[0]; end1[1] = boxmaxs[1]; end1[2] = boxmaxs[2];
|
|
R_DrawLine(start1,end1,colorVec);
|
|
|
|
start1[0] = boxmaxs[0]; start1[1] = boxmaxs[1]; start1[2] = boxmins[2];
|
|
end1[0] = boxmaxs[0]; end1[1] = boxmaxs[1]; end1[2] = boxmaxs[2];
|
|
R_DrawLine(start1,end1,colorVec);
|
|
|
|
start1[0] = boxmaxs[0]; start1[1] = boxmins[1]; start1[2] = boxmins[2];
|
|
end1[0] = boxmaxs[0]; end1[1] = boxmins[1]; end1[2] = boxmaxs[2];
|
|
R_DrawLine(start1,end1,colorVec);
|
|
}
|
|
/////////////////////////////////////////////
|
|
int DebugTraceMove(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, edict_t *ent)
|
|
{
|
|
if(start[0] == end[0] && start[1] == end[1] && start[2] == end[2])
|
|
{
|
|
return 1;
|
|
}
|
|
vec3_t forward, up;
|
|
float HorDist;
|
|
vec3_t HorGoal;
|
|
vec3_t tempHorGoal;
|
|
|
|
up[0] = 0;
|
|
up[1] = 0;
|
|
up[2] = 1;
|
|
|
|
HorGoal[0] = end[0];
|
|
HorGoal[1] = end[1];
|
|
HorGoal[2] = start[2];
|
|
|
|
VectorSubtract(HorGoal,start,forward);
|
|
HorDist = VectorLength(forward);
|
|
VectorNormalize(forward);
|
|
|
|
vec3_t CurrentPos;
|
|
|
|
VectorCopy(start,CurrentPos);
|
|
VectorCopy(HorGoal,tempHorGoal);
|
|
|
|
float CurrentDist = 0;//2d distance from initial 3d positionvector
|
|
|
|
trace_t trace1, trace2;
|
|
float tempDist;
|
|
vec3_t tempVec;
|
|
vec3_t tempVec2;
|
|
float i;
|
|
int STEPSIZEB = 18;//other declaration isn't declared yet
|
|
float SLOPELEN = 10.4;//18/tan(60) = 10.4, the the length of the triangle formed by the max walkable slope of 60 degrees.
|
|
int skip = 0;
|
|
int LoopBreak = 0;
|
|
|
|
while(CurrentDist < HorDist)
|
|
{
|
|
if(LoopBreak > 50)
|
|
{
|
|
Con_Printf("AI Warning: There is a ledge that is greater than 650 meters.\n");
|
|
return -1;
|
|
}
|
|
|
|
trace1 = SV_Move(CurrentPos, mins, maxs, tempHorGoal, MOVE_NOMONSTERS, ent);
|
|
//Goal
|
|
//drawbbox(CurrentPos,mins,maxs,tempHorGoal,trace1.fraction + 6);
|
|
|
|
VectorSubtract(tempHorGoal,CurrentPos,tempVec);
|
|
tempDist = trace1.fraction * VectorLength(tempVec);
|
|
//Check if we fell along the path
|
|
for(i = (maxs[0] * 1); i < tempDist; i += (maxs[0] * 1))
|
|
{
|
|
VectorScale(forward,i,tempVec);
|
|
VectorAdd(tempVec,CurrentPos,tempVec);
|
|
VectorScale(up,-500,tempVec2);//500 inches is about 13 meters
|
|
VectorAdd(tempVec,tempVec2,tempVec2);
|
|
trace2 = SV_Move(tempVec, mins, maxs, tempVec2, MOVE_NOMONSTERS, ent);
|
|
//Down
|
|
if(trace2.fraction > 0)
|
|
{
|
|
vec3_t tVec;
|
|
VectorScale(up,-500,tVec);
|
|
VectorScale(tVec,trace2.fraction,tVec);
|
|
VectorAdd(tempVec,tVec,tVec);
|
|
drawbbox(tempVec,mins,maxs,tVec,3);
|
|
//drawbbox(tempVec,mins,maxs,tempVec2,3);
|
|
|
|
}
|
|
|
|
if(trace2.fraction > 0)
|
|
{
|
|
VectorScale(up,trace2.fraction * -500,tempVec2);
|
|
VectorAdd(tempVec,tempVec2,CurrentPos);
|
|
VectorAdd(tempHorGoal,tempVec2,tempHorGoal);
|
|
skip = 1;
|
|
CurrentDist += i;
|
|
if(trace2.fraction == 1)
|
|
{
|
|
//We fell the full 13 meters!, we need to be careful here,
|
|
//because if we're checking over the void, then we could be stuck in an infinite loop and crash the game
|
|
//So we're going to keep track of how many times we fall 13 meters
|
|
LoopBreak++;
|
|
}
|
|
else
|
|
{
|
|
LoopBreak = 0;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
//If we fell at any location along path, then we don't try to step up
|
|
if(skip == 1)
|
|
{
|
|
trace2.fraction = 0;
|
|
skip = 0;
|
|
continue;
|
|
}
|
|
//We need to advance it as much as possible along path before step up
|
|
if(trace1.fraction > 0 && trace1.fraction < 1)
|
|
{
|
|
VectorCopy(trace1.endpos,CurrentPos);
|
|
trace1.fraction = 0;
|
|
}
|
|
//Check step up
|
|
if(trace1.fraction < 1)
|
|
{
|
|
VectorScale(up,STEPSIZEB,tempVec2);
|
|
VectorAdd(CurrentPos,tempVec2,tempVec);
|
|
|
|
VectorAdd(tempHorGoal,tempVec2,tempVec2);
|
|
|
|
trace2 = SV_Move(tempVec, mins, maxs, tempVec2, MOVE_NOMONSTERS, ent);
|
|
|
|
//up
|
|
//=============================== Debug ==============================================================
|
|
vec3_t debugVec;//temp, we need to do the conditional for success step up but we copy vector after this, so we need to do a temp version of the copy to test in color assignment
|
|
VectorSubtract(tempVec2,tempVec,debugVec);
|
|
if(trace2.fraction <= (trace1.fraction + (SLOPELEN/VectorLength(debugVec))) && trace2.fraction != 1)
|
|
{
|
|
drawbbox(tempVec,mins,maxs,tempVec,4);
|
|
}
|
|
drawbbox(CurrentPos,mins,maxs,CurrentPos,5);
|
|
//=============================== / Debug ==============================================================
|
|
|
|
|
|
//10.4 is minimum length for a slope of 60 degrees, we need to at least advance this much to know the surface is walkable
|
|
VectorSubtract(tempVec2,tempVec,tempVec2);
|
|
if(trace2.fraction > (trace1.fraction + (SLOPELEN/VectorLength(tempVec2))) || trace2.fraction == 1)
|
|
{
|
|
//we check for slope above
|
|
//This is for advancing within the step up
|
|
//VectorCopy(trace2.endpos,CurrentPos);
|
|
//tempHorGoal[2] = CurrentPos[2];
|
|
//VectorSubtract(trace2.endpos,tempVec,tempVec2);
|
|
//CurrentDist += VectorLength(tempVec2);
|
|
|
|
//this is for continuing the search with the step up
|
|
VectorCopy(tempVec,CurrentPos);
|
|
tempHorGoal[2] = CurrentPos[2];
|
|
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
//Con_Printf("t2:%f,t1:%f, delta: %f",trace2.fraction,trace1.fraction,trace1.fraction + (SLOPELEN/VectorLength(tempVec2)));
|
|
//Con_Printf("hitwall ");
|
|
return 0;//stepping up didn't advance so we've hit a wall, we failed
|
|
}
|
|
}
|
|
if(trace1.fraction == 1)//we've made it horizontally to our goal... so check if we've made it vertically...
|
|
{
|
|
if((end[2] - tempHorGoal[2] < STEPSIZEB) && (end[2] - tempHorGoal[2]) > -1 * STEPSIZEB)
|
|
return 1;
|
|
else
|
|
{
|
|
Con_Printf("vert ");
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
Con_Printf("end ");
|
|
return 0;
|
|
}
|
|
|
|
void tryLine()
|
|
{
|
|
edict_t *p;
|
|
int pnum;
|
|
pnum = EN_Find(0,"player");
|
|
p = EDICT_NUM(pnum);
|
|
|
|
vec3_t cv;
|
|
|
|
|
|
int result;
|
|
result = DebugTraceMove(p->v.origin,p->v.mins,p->v.maxs,PROG_TO_EDICT(p->v.enemy)->v.origin ,0,p);
|
|
|
|
|
|
cv[0] = 1; cv[1] = 0; cv[2] = 0;
|
|
|
|
if(result == 1)
|
|
{
|
|
cv[0] = 0; cv[1] = 1; cv[2] = 0;
|
|
}
|
|
R_DrawLine(p->v.origin,PROG_TO_EDICT(p->v.enemy)->v.origin,cv);
|
|
|
|
//drawbbox(p->v.origin,p->v.mins,p->v.maxs,PROG_TO_EDICT(p->v.enemy)->v.origin,result);
|
|
|
|
drawbbox(PROG_TO_EDICT(p->v.enemy)->v.origin,p->v.mins,p->v.maxs,PROG_TO_EDICT(p->v.enemy)->v.origin,1);
|
|
drawbbox(p->v.origin,p->v.mins,p->v.maxs,p->v.origin,1);
|
|
}*/
|
|
//End blubs debug functions
|
|
|
|
|
|
/*
|
|
==================
|
|
V_RenderView
|
|
|
|
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;
|
|
|
|
void V_RenderView (void)
|
|
{
|
|
if (con_forcedup)
|
|
return;
|
|
|
|
// 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");
|
|
}
|
|
|
|
if (cl.intermission)
|
|
{ // intermission / finale rendering
|
|
V_CalcIntermissionRefdef ();
|
|
}
|
|
else
|
|
{
|
|
if (!cl.paused /* && (sv.maxclients > 1 || key_dest == key_game) */ )
|
|
V_CalcRefdef ();
|
|
}
|
|
|
|
R_PushDlights ();
|
|
|
|
if (lcd_x.value)
|
|
{
|
|
//
|
|
// render two interleaved views
|
|
//
|
|
int i;
|
|
|
|
vid.rowbytes <<= 1;
|
|
vid.aspect *= 0.5;
|
|
|
|
r_refdef.viewangles[YAW] -= lcd_yaw.value;
|
|
for (i=0 ; i<3 ; i++)
|
|
r_refdef.vieworg[i] -= right[i]*lcd_x.value;
|
|
R_RenderView ();
|
|
|
|
vid.buffer += vid.rowbytes>>1;
|
|
|
|
R_PushDlights ();
|
|
|
|
r_refdef.viewangles[YAW] += lcd_yaw.value*2;
|
|
for (i=0 ; i<3 ; i++)
|
|
r_refdef.vieworg[i] += 2*right[i]*lcd_x.value;
|
|
R_RenderView ();
|
|
|
|
vid.buffer -= vid.rowbytes>>1;
|
|
|
|
r_refdef.vrect.height <<= 1;
|
|
|
|
vid.rowbytes >>= 1;
|
|
vid.aspect *= 2;
|
|
}
|
|
else
|
|
{
|
|
R_RenderView ();
|
|
}
|
|
|
|
}
|
|
|
|
//============================================================================
|
|
|
|
/*
|
|
=============
|
|
V_Init
|
|
=============
|
|
*/
|
|
void V_Init (void)
|
|
{
|
|
Cmd_AddCommand ("v_cshift", V_cshift_f);
|
|
Cmd_AddCommand ("bf", V_BonusFlash_f);
|
|
Cmd_AddCommand ("centerview", V_StartPitchDrift);
|
|
|
|
Cvar_RegisterVariable (&lcd_x);
|
|
Cvar_RegisterVariable (&lcd_yaw);
|
|
|
|
Cvar_RegisterVariable (&v_centermove);
|
|
Cvar_RegisterVariable (&v_centerspeed);
|
|
|
|
Cvar_RegisterVariable (&v_iyaw_cycle);
|
|
Cvar_RegisterVariable (&v_iroll_cycle);
|
|
Cvar_RegisterVariable (&v_ipitch_cycle);
|
|
Cvar_RegisterVariable (&v_iyaw_level);
|
|
Cvar_RegisterVariable (&v_iroll_level);
|
|
Cvar_RegisterVariable (&v_ipitch_level);
|
|
|
|
Cvar_RegisterVariable (&v_idlescale);
|
|
Cvar_RegisterVariable (&crosshair);
|
|
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 (&v_kicktime);
|
|
Cvar_RegisterVariable (&v_kickroll);
|
|
Cvar_RegisterVariable (&v_kickpitch);
|
|
|
|
Cvar_RegisterVariable (&v_gamma);
|
|
BuildGammaTable (v_gamma.value); // no gamma yet
|
|
}
|
|
|
|
|