X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=view.c;h=7d690e9a987b1ef58cfa268e4e6ddb0231c7e5d5;hp=0f86ef820ca00e4d42480805fec4d75006e25507;hb=c98af94360edd985e70be8330bf04d7d695d9001;hpb=6b6b622f054e260ca0644fa96647892e997d492c diff --git a/view.c b/view.c index 0f86ef82..7d690e9a 100644 --- a/view.c +++ b/view.c @@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // view.c -- player eye positioning #include "quakedef.h" +#include "cl_collision.h" /* @@ -30,30 +31,46 @@ when crossing a water boudnary. */ -cvar_t cl_rollspeed = {0, "cl_rollspeed", "200"}; -cvar_t cl_rollangle = {0, "cl_rollangle", "2.0"}; +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_bob = {0, "cl_bob","0.02"}; -cvar_t cl_bobcycle = {0, "cl_bobcycle","0.6"}; -cvar_t cl_bobup = {0, "cl_bobup","0.5"}; +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 v_kicktime = {0, "v_kicktime", "0.5"}; -cvar_t v_kickroll = {0, "v_kickroll", "0.6"}; -cvar_t v_kickpitch = {0, "v_kickpitch", "0.6"}; +cvar_t cl_bobmodel = {0, "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_iyaw_cycle = {0, "v_iyaw_cycle", "2"}; -cvar_t v_iroll_cycle = {0, "v_iroll_cycle", "0.5"}; -cvar_t v_ipitch_cycle = {0, "v_ipitch_cycle", "1"}; -cvar_t v_iyaw_level = {0, "v_iyaw_level", "0.3"}; -cvar_t v_iroll_level = {0, "v_iroll_level", "0.1"}; -cvar_t v_ipitch_level = {0, "v_ipitch_level", "0.3"}; +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_idlescale = {0, "v_idlescale", "0"}; +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 crosshair = {CVAR_SAVE, "crosshair", "0"}; +cvar_t v_idlescale = {0, "v_idlescale", "0", "how much of the quake 'drunken view' effect to use"}; -cvar_t v_centermove = {0, "v_centermove", "0.15"}; -cvar_t v_centerspeed = {0, "v_centerspeed","500"}; +cvar_t crosshair = {CVAR_SAVE, "crosshair", "0", "selects crosshair to use (0 is none)"}; + +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"}; + +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)"}; + +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; @@ -88,34 +105,6 @@ float V_CalcRoll (vec3_t angles, vec3_t velocity) } -static float V_CalcBob (void) -{ - double bob, cycle; - - // LordHavoc: easy case - if (cl_bob.value == 0) - return 0; - if (cl_bobcycle.value == 0) - return 0; - - // LordHavoc: FIXME: this code is *weird*, redesign it sometime - cycle = cl.time / cl_bobcycle.value; - cycle -= (int) cycle; - 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; - bob = bob*0.3 + bob*0.7*sin(cycle); - bob = bound(-7, bob, 4); - return bob; - -} - void V_StartPitchDrift (void) { if (cl.laststop == cl.time) @@ -149,7 +138,7 @@ Drifting is enabled when the center view key is hit, mlook is released and lookspring is non 0, or when =============== */ -static void V_DriftPitch (void) +void V_DriftPitch (void) { float delta, move; @@ -223,7 +212,7 @@ V_ParseDamage */ void V_ParseDamage (void) { - int i, armor, blood; + int armor, blood; vec3_t from; //vec3_t forward, right; vec3_t localfrom; @@ -233,8 +222,7 @@ void V_ParseDamage (void) 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) @@ -267,28 +255,16 @@ void V_ParseDamage (void) cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 0; } -// -// calculate view angle kicks -// - 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; - - //VectorSubtract (from, ent->render.origin, from); - //VectorNormalize (from); - - //AngleVectors (ent->render.angles, forward, right, NULL); - - //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; @@ -300,10 +276,10 @@ V_cshift_f */ static void V_cshift_f (void) { - v_cshift.destcolor[0] = atoi(Cmd_Argv(1)); - v_cshift.destcolor[1] = atoi(Cmd_Argv(2)); - v_cshift.destcolor[2] = atoi(Cmd_Argv(3)); - v_cshift.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)); } @@ -322,133 +298,6 @@ static void V_BonusFlash_f (void) cl.cshifts[CSHIFT_BONUS].percent = 50; } -/* -============= -V_UpdateBlends -============= -*/ -void V_UpdateBlends (void) -{ - float r, g, b, a, a2; - int j; - - if (cls.signon != SIGNONS) - { - cl.cshifts[CSHIFT_DAMAGE].percent = 0; - cl.cshifts[CSHIFT_BONUS].percent = 0; - cl.cshifts[CSHIFT_CONTENTS].percent = 0; - cl.cshifts[CSHIFT_POWERUP].percent = 0; - r_refdef.viewblend[0] = 0; - r_refdef.viewblend[1] = 0; - r_refdef.viewblend[2] = 0; - r_refdef.viewblend[3] = 0; - return; - } - - // 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; - - // set contents color - switch (Mod_PointContents (r_refdef.vieworg, cl.worldmodel)) - { - case CONTENTS_EMPTY: - case CONTENTS_SOLID: - cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = v_cshift.destcolor[0]; - cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = v_cshift.destcolor[1]; - cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = v_cshift.destcolor[2]; - cl.cshifts[CSHIFT_CONTENTS].percent = v_cshift.percent; - break; - case CONTENTS_LAVA: - cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 255; - cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 80; - cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 0; - cl.cshifts[CSHIFT_CONTENTS].percent = 150 >> 1; - break; - case CONTENTS_SLIME: - cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 0; - cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 25; - cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 5; - cl.cshifts[CSHIFT_CONTENTS].percent = 150 >> 1; - break; - default: - 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 = 128 >> 1; - } - - 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; - - // LordHavoc: fixed V_CalcBlend - r = 0; - g = 0; - b = 0; - a = 0; - - for (j=0 ; j 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; - } - - r_refdef.viewblend[0] = bound(0, r * (1.0/255.0), 1); - r_refdef.viewblend[1] = bound(0, g * (1.0/255.0), 1); - r_refdef.viewblend[2] = bound(0, b * (1.0/255.0), 1); - r_refdef.viewblend[3] = bound(0, a , 1); -} - /* ============================================================================== @@ -457,58 +306,10 @@ void V_UpdateBlends (void) ============================================================================== */ -/* -============== -V_AddIdle +extern matrix4x4_t viewmodelmatrix; -Idle swaying -============== -*/ -static void V_AddIdle (float idle) -{ - r_refdef.viewangles[ROLL] += idle * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value; - r_refdef.viewangles[PITCH] += idle * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value; - r_refdef.viewangles[YAW] += idle * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value; -} - -#define MAXVIEWMODELS 32 -extern int numviewmodels; -extern entity_t *viewmodels[MAXVIEWMODELS]; -void V_LinkViewEntities(void) -{ - int i; - //float v[3]; - entity_t *ent; - matrix4x4_t matrix, matrix2; - - if (numviewmodels <= 0) - return; - - //Matrix4x4_CreateRotate(&matrix, 1, 0, 0, r_refdef.viewangles[0]); - //Matrix4x4_CreateRotate(&matrix, 0, 1, 0, r_refdef.viewangles[0]); - //Matrix4x4_CreateRotate(&matrix, 0, 0, 1, r_refdef.viewangles[0]); - Matrix4x4_CreateFromQuakeEntity(&matrix, r_refdef.vieworg[0], r_refdef.vieworg[1], r_refdef.vieworg[2], r_refdef.viewangles[0], r_refdef.viewangles[1], r_refdef.viewangles[2], 0.3); - for (i = 0;i < numviewmodels && r_refdef.numentities < r_refdef.maxentities;i++) - { - ent = viewmodels[i]; - r_refdef.entities[r_refdef.numentities++] = &ent->render; - - //VectorCopy(ent->render.origin, v); - //ent->render.origin[0] = v[0] * vpn[0] + v[1] * vright[0] + v[2] * vup[0] + r_refdef.vieworg[0]; - //ent->render.origin[1] = v[0] * vpn[1] + v[1] * vright[1] + v[2] * vup[1] + r_refdef.vieworg[1]; - //ent->render.origin[2] = v[0] * vpn[2] + v[1] * vright[2] + v[2] * vup[2] + r_refdef.vieworg[2]; - //ent->render.angles[0] = ent->render.angles[0] + r_refdef.viewangles[0]; - //ent->render.angles[1] = ent->render.angles[1] + r_refdef.viewangles[1]; - //ent->render.angles[2] = ent->render.angles[2] + r_refdef.viewangles[2]; - //ent->render.scale *= 0.3; - - //Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, ent->render.origin[0], ent->render.origin[1], ent->render.origin[2], ent->render.angles[0], ent->render.angles[1], ent->render.angles[2], ent->render.scale); - matrix2 = ent->render.matrix; - Matrix4x4_Concat(&ent->render.matrix, &matrix, &matrix2); - Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix); - CL_BoundingBoxForEntity(&ent->render); - } -} +#include "cl_collision.h" +#include "csprogs.h" /* ================== @@ -518,86 +319,316 @@ V_CalcRefdef */ void V_CalcRefdef (void) { - entity_t *ent, *view; - - if (cls.state != ca_connected || cls.signon != SIGNONS) + static float oldz; + entity_t *ent; + float vieworg[3], gunorg[3], viewangles[3]; + trace_t trace; + if(csqc_loaded) return; - - // 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; - - V_DriftPitch (); - - VectorCopy (ent->render.origin, r_refdef.vieworg); - if (!intimerefresh) - VectorCopy (cl.viewangles, r_refdef.viewangles); - - if (cl.intermission) - { - view->render.model = NULL; - VectorCopy (ent->render.angles, r_refdef.viewangles); - V_AddIdle (1); - } - else if (chase_active.value) + VectorClear(gunorg); + viewmodelmatrix = identitymatrix; + r_refdef.viewentitymatrix = identitymatrix; + if (cls.state == ca_connected && cls.signon == SIGNONS) { - view->render.model = NULL; - r_refdef.vieworg[2] += cl.viewheight; - Chase_Update (); - V_AddIdle (v_idlescale.value); + // ent is the view entity (visible when out of body) + ent = &cl.entities[cl.viewentity]; + if (cl.intermission) + { + // entity is a fixed camera, just copy the matrix + if (cls.protocol == PROTOCOL_QUAKEWORLD) + Matrix4x4_CreateFromQuakeEntity(&r_refdef.viewentitymatrix, 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 + { + r_refdef.viewentitymatrix = ent->render.matrix; + r_refdef.viewentitymatrix.m[2][3] += cl.stats[STAT_VIEWHEIGHT]; + } + viewmodelmatrix = r_refdef.viewentitymatrix; + } + else + { + // 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); + + // apply qw weapon recoil effect (this did not work in QW) + // TODO: add a cvar to disable this + viewangles[PITCH] += cl.qw_weaponkick; + + if (cl.onground) + { + if (!cl.oldonground) + cl.hitgroundtime = cl.time; + cl.lastongroundtime = cl.time; + } + cl.oldonground = cl.onground; + + // 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 (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.frametime; + } + // 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_refdef.viewentitymatrix, 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_refdef.viewentitymatrix, 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); + } } - else - { - r_refdef.viewangles[ROLL] += V_CalcRoll (cl.viewangles, cl.velocity); +} + +void V_FadeViewFlashs(void) +{ + // 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; +} - if (v_dmg_time > 0) +void V_CalcViewBlend(void) +{ + 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) + { + // set contents color + int supercontents; + vec3_t vieworigin; + Matrix4x4_OriginFromMatrix(&r_refdef.viewentitymatrix, vieworigin); + supercontents = CL_PointSuperContents(vieworigin); + if (supercontents & SUPERCONTENTS_LIQUIDSMASK) { - 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 -= cl.frametime; + 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; } - if (cl.stats[STAT_HEALTH] <= 0) - r_refdef.viewangles[ROLL] = 80; // dead view angle - - V_AddIdle (v_idlescale.value); + 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; + } - r_refdef.vieworg[2] += cl.viewheight + V_CalcBob (); + 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; - // LordHavoc: origin view kick added - if (!intimerefresh) + // LordHavoc: fixed V_CalcBlend + for (j = 0;j < NUM_CSHIFTS;j++) { - VectorAdd(r_refdef.viewangles, cl.punchangle, r_refdef.viewangles); - VectorAdd(r_refdef.vieworg, cl.punchvector, r_refdef.vieworg); + 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 + } } - - // set up gun - // (FIXME! this should be in cl_main.c with the other linking code, not view.c!) - view->state_current.modelindex = cl.stats[STAT_WEAPON]; - view->state_current.frame = cl.stats[STAT_WEAPONFRAME]; - //VectorCopy(r_refdef.vieworg, view->render.origin); - //view->render.angles[PITCH] = r_refdef.viewangles[PITCH] + v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value; - //view->render.angles[YAW] = r_refdef.viewangles[YAW] - v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value; - //view->render.angles[ROLL] = r_refdef.viewangles[ROLL] - v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value; - //view->render.scale = 1.0 / 3.0; - Matrix4x4_CreateFromQuakeEntity(&view->render.matrix, r_refdef.vieworg[0], r_refdef.vieworg[1], r_refdef.vieworg[2], r_refdef.viewangles[PITCH] + v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value, r_refdef.viewangles[YAW] - v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value, r_refdef.viewangles[ROLL] - v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value, 0.3); - Matrix4x4_Invert_Simple(&view->render.inversematrix, &view->render.matrix); - CL_BoundingBoxForEntity(&view->render); - // FIXME: this setup code is somewhat evil (CL_LerpUpdate should be private?) - CL_LerpUpdate(view); - view->render.colormap = -1; // no special coloring - view->render.alpha = ent->render.alpha; // LordHavoc: if the player is transparent, so is the gun - view->render.effects = ent->render.effects; - AngleVectors(r_refdef.viewangles, vpn, vright, vup); - - // link into render entities list - if (r_drawviewmodel.integer && !chase_active.integer && !envmap && r_drawentities.integer && !(cl.items & IT_INVISIBILITY) && cl.stats[STAT_HEALTH] > 0) + // saturate color (to avoid blending in black) + if (r_refdef.viewblend[3]) { - if (r_refdef.numentities < r_refdef.maxentities && view->render.model != NULL) - r_refdef.entities[r_refdef.numentities++] = &view->render; - V_LinkViewEntities(); + a2 = 1 / r_refdef.viewblend[3]; + VectorScale(r_refdef.viewblend, a2, r_refdef.viewblend); } + + 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); } } @@ -610,9 +641,9 @@ V_Init */ 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); @@ -632,9 +663,24 @@ void V_Init (void) 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 (&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); }