#include "quakedef.h"#include "colormatrix.h"#include "crosshairs.h" /* * 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. */ /* Used by view and sv_user */vec3_t forward, right, up; /* * 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; cvar_t v_scale = {"v_scale", "1", true}; static cvar_t v_cshiftpercent = {"v_cshiftpercent", "30", true}; static cvar_t scr_ofsx = {"scr_ofsx", "0"};static cvar_t scr_ofsy = {"scr_ofsy", "0"};static cvar_t scr_ofsz = {"scr_ofsz", "0"};static cvar_t cl_rollspeed = {"cl_rollspeed", "200"};static cvar_t cl_rollangle = {"cl_rollangle", "2.0"};static cvar_t cl_bob = {"cl_bob", "0.02"};static cvar_t cl_bobcycle = {"cl_bobcycle", "0.6"};static cvar_t cl_bobup = {"cl_bobup", "0.5"};static cvar_t v_kicktime = {"v_kicktime", "0.5"};static cvar_t v_kickroll = {"v_kickroll", "0.6"};static cvar_t v_kickpitch = {"v_kickpitch", "0.6"};static cvar_t v_iyaw_cycle = {"v_iyaw_cycle", "2"};static cvar_t v_iroll_cycle = {"v_iroll_cycle", "0.5"};static cvar_t v_ipitch_cycle = {"v_ipitch_cycle", "1"};static cvar_t v_iyaw_level = {"v_iyaw_level", "0.3"};static cvar_t v_iroll_level = {"v_iroll_level", "0.1"};static cvar_t v_ipitch_level = {"v_ipitch_level", "0.3"};static cvar_t v_idlescale = {"v_idlescale", "0"};static cvar_t crosshair = {"crosshair", "1", true};static cvar_t crosshair_shape = {"crosshair_shape", "0", true};static cvar_t cl_crossx = {"cl_crossx", "0"};static cvar_t cl_crossy = {"cl_crossy", "0"};static cvar_t v_centermove = {"v_centermove", "0.15"};static cvar_t v_centerspeed = {"v_centerspeed", "500"}; static double v_dmg_time, v_dmg_roll, v_dmg_pitch;static double v_step_time, v_step_z, v_step_oldz; static cshift_t cshift_empty = {{130, 80, 50}, 0};static cshift_t cshift_water = {{130, 80, 50}, 128};static cshift_t cshift_slime = {{0, 25, 5}, 150};static cshift_t cshift_lava = {{255, 80, 0}, 150}; floatV_CalcRoll(vec3_t angles, vec3_t velocity){ float sign, side, value; AngleVectors(angles, forward, right, up); side = DotProduct(velocity, right); sign = side < 0 ? -1 : 1; side = fabs(side); value = cl_rollangle.value; if(side < cl_rollspeed.value) side = side * value / cl_rollspeed.value; else side = value; return side * sign;} static floatV_CalcBob(void){ float bob, 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 = sqrtf(cl.velocity[0] * cl.velocity[0] + cl.velocity[1] * cl.velocity[1]) * cl_bob.value; bob = bob * 0.3 + bob * 0.7 * sinf(cycle); if(bob > 4) bob = 4; else if(bob < -7) bob = -7; return bob;} voidV_StartPitchDrift(cmd_t *c){ USED(c); if(cl.laststop == cl.time) return; // something else is keeping it from drifting if(cl.nodrift || !cl.pitchvel) { cl.pitchvel = v_centerspeed.value; cl.nodrift = false; cl.driftmove = 0; }} voidV_StopPitchDrift(void){ cl.laststop = cl.time; cl.nodrift = true; cl.pitchvel = 0;} /* * 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 */static voidV_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.value) cl.driftmove = 0; else cl.driftmove += scr_frametime; if(cl.driftmove > v_centermove.value) V_StartPitchDrift(nil); return; } delta = cl.idealpitch - cl.viewangles[PITCH]; if(!delta) { cl.pitchvel = 0; return; } move = scr_frametime * cl.pitchvel; cl.pitchvel += scr_frametime * v_centerspeed.value; // Con_Printf("move: %f (%f)\n", move, scr_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; }} voidV_ParseDamage(void){ int armor, blood; vec3_t from, forward, right, up; entity_t *ent; float side, count; armor = MSG_ReadByte(); blood = MSG_ReadByte(); MSG_ReadVec(cl.protocol, from); 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;} static voidV_cshift_f(cmd_t *c){ USED(c); 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));} /* When you run over an item, the server sends this command */static voidV_BonusFlash_f(cmd_t *c){ USED(c); 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;} /* Underwater, lava, etc each has a color shift */voidV_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; }} static voidV_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;} static voidV_Blend(void){ float c[4], a; int i; c[0] = c[1] = c[2] = c[3] = 0; for(i = 0; i < NUM_CSHIFTS; i++) { a = ((cl.cshifts[i].percent * v_cshiftpercent.value) / 100.0) / 255.0; if(a > 0) { c[3] += a * (1 - c[3]); a = a / c[3]; c[0] = c[0] * (1 - a) + cl.cshifts[i].destcolor[0] * a; c[1] = c[1] * (1 - a) + cl.cshifts[i].destcolor[1] * a; c[2] = c[2] * (1 - a) + cl.cshifts[i].destcolor[2] * a; } } c[3] = clamp(c[3], 0, 1.0); c[2] *= c[3] / 255.0; c[1] *= c[3] / 255.0; c[0] *= c[3] / 255.0; cmsetvblend(c);} voidV_ApplyShifts(void){ int i, j; bool update; V_CalcPowerupCshift(); update = false; for(i = 0; i < NUM_CSHIFTS; i++) { if(cl.cshifts[i].percent != cl.prev_cshifts[i].percent) { cl.prev_cshifts[i].percent = cl.cshifts[i].percent; update = true; } for(j = 0; j < 3; j++) { if(cl.cshifts[i].destcolor[j] != cl.prev_cshifts[i].destcolor[j]) { cl.prev_cshifts[i].destcolor[j] = cl.cshifts[i].destcolor[j]; update = true; } } } // drop the damage value if(cl.cshifts[CSHIFT_DAMAGE].percent > 0) { cl.cshifts[CSHIFT_DAMAGE].percent -= scr_frametime * 150; if(cl.cshifts[CSHIFT_DAMAGE].percent < 0) cl.cshifts[CSHIFT_DAMAGE].percent = 0; } // drop the bonus value if(cl.cshifts[CSHIFT_BONUS].percent > 0) { cl.cshifts[CSHIFT_BONUS].percent -= scr_frametime * 100; if(cl.cshifts[CSHIFT_BONUS].percent < 0) cl.cshifts[CSHIFT_BONUS].percent = 0; } if(update) V_Blend();} static floatangledelta(float a){ a = anglemod(a); if(a > 180) a -= 360; return a;} static voidCalcGunAngle(void){ static float oldyaw = 0; static float oldpitch = 0; float yaw, pitch, move; yaw = r_refdef.view.angles[YAW]; pitch = -r_refdef.view.angles[PITCH]; yaw = angledelta(yaw - r_refdef.view.angles[YAW]) * 0.4; if(yaw > 10) yaw = 10; else if(yaw < -10) yaw = -10; pitch = angledelta(-pitch - r_refdef.view.angles[PITCH]) * 0.4; if(pitch > 10) pitch = 10; else if(pitch < -10) pitch = -10; move = scr_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.view.angles[YAW] + yaw; cl.viewent.angles[PITCH] = -(r_refdef.view.angles[PITCH] + pitch); cl.viewent.angles[ROLL] -= v_idlescale.value * sinf(cl.time * v_iroll_cycle.value) * v_iroll_level.value; cl.viewent.angles[PITCH] -= v_idlescale.value * sinf(cl.time * v_ipitch_cycle.value) * v_ipitch_level.value; cl.viewent.angles[YAW] -= v_idlescale.value * sinf(cl.time * v_iyaw_cycle.value) * v_iyaw_level.value;} static voidV_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.view.org[0] < ent->origin[0] - 14) r_refdef.view.org[0] = ent->origin[0] - 14; else if(r_refdef.view.org[0] > ent->origin[0] + 14) r_refdef.view.org[0] = ent->origin[0] + 14; if(r_refdef.view.org[1] < ent->origin[1] - 14) r_refdef.view.org[1] = ent->origin[1] - 14; else if(r_refdef.view.org[1] > ent->origin[1] + 14) r_refdef.view.org[1] = ent->origin[1] + 14; if(r_refdef.view.org[2] < ent->origin[2] - 22) r_refdef.view.org[2] = ent->origin[2] - 22; else if(r_refdef.view.org[2] > ent->origin[2] + 30) r_refdef.view.org[2] = ent->origin[2] + 30;} /* Idle swaying */static voidV_AddIdle(void){ r_refdef.view.angles[ROLL] += v_idlescale.value * sinf(cl.time * v_iroll_cycle.value) * v_iroll_level.value; r_refdef.view.angles[PITCH] += v_idlescale.value * sinf(cl.time * v_ipitch_cycle.value) * v_ipitch_level.value; r_refdef.view.angles[YAW] += v_idlescale.value * sinf(cl.time * v_iyaw_cycle.value) * v_iyaw_level.value;} /* Roll is induced by movement and damage */static voidV_CalcViewRoll(void){ float side; side = V_CalcRoll(cl_entities[cl.viewentity].angles, cl.velocity); r_refdef.view.angles[ROLL] += side; if(v_dmg_time > 0) { r_refdef.view.angles[ROLL] += v_dmg_time / v_kicktime.value * v_dmg_roll; r_refdef.view.angles[PITCH] += v_dmg_time / v_kicktime.value * v_dmg_pitch; v_dmg_time -= scr_frametime; } if(cl.stats[STAT_HEALTH] <= 0) { r_refdef.view.angles[ROLL] = 80; // dead view angle return; }} static voidV_CalcIntermissionRefdef(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.view.org); VectorCopy(ent->angles, r_refdef.view.angles); view->model = nil; Lines 1–500 of 728. Load more
#include "quakedef.h" #include "colormatrix.h" #include "crosshairs.h" /* * 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. */ /* Used by view and sv_user */ vec3_t forward, right, up; /* * 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; cvar_t v_scale = {"v_scale", "1", true}; static cvar_t v_cshiftpercent = {"v_cshiftpercent", "30", true}; static cvar_t scr_ofsx = {"scr_ofsx", "0"}; static cvar_t scr_ofsy = {"scr_ofsy", "0"}; static cvar_t scr_ofsz = {"scr_ofsz", "0"}; static cvar_t cl_rollspeed = {"cl_rollspeed", "200"}; static cvar_t cl_rollangle = {"cl_rollangle", "2.0"}; static cvar_t cl_bob = {"cl_bob", "0.02"}; static cvar_t cl_bobcycle = {"cl_bobcycle", "0.6"}; static cvar_t cl_bobup = {"cl_bobup", "0.5"}; static cvar_t v_kicktime = {"v_kicktime", "0.5"}; static cvar_t v_kickroll = {"v_kickroll", "0.6"}; static cvar_t v_kickpitch = {"v_kickpitch", "0.6"}; static cvar_t v_iyaw_cycle = {"v_iyaw_cycle", "2"}; static cvar_t v_iroll_cycle = {"v_iroll_cycle", "0.5"}; static cvar_t v_ipitch_cycle = {"v_ipitch_cycle", "1"}; static cvar_t v_iyaw_level = {"v_iyaw_level", "0.3"}; static cvar_t v_iroll_level = {"v_iroll_level", "0.1"}; static cvar_t v_ipitch_level = {"v_ipitch_level", "0.3"}; static cvar_t v_idlescale = {"v_idlescale", "0"}; static cvar_t crosshair = {"crosshair", "1", true}; static cvar_t crosshair_shape = {"crosshair_shape", "0", true}; static cvar_t cl_crossx = {"cl_crossx", "0"}; static cvar_t cl_crossy = {"cl_crossy", "0"}; static cvar_t v_centermove = {"v_centermove", "0.15"}; static cvar_t v_centerspeed = {"v_centerspeed", "500"}; static double v_dmg_time, v_dmg_roll, v_dmg_pitch; static double v_step_time, v_step_z, v_step_oldz; static cshift_t cshift_empty = {{130, 80, 50}, 0}; static cshift_t cshift_water = {{130, 80, 50}, 128}; static cshift_t cshift_slime = {{0, 25, 5}, 150}; static cshift_t cshift_lava = {{255, 80, 0}, 150}; float V_CalcRoll(vec3_t angles, vec3_t velocity) { float sign, side, value; AngleVectors(angles, forward, right, up); side = DotProduct(velocity, right); sign = side < 0 ? -1 : 1; side = fabs(side); value = cl_rollangle.value; if(side < cl_rollspeed.value) side = side * value / cl_rollspeed.value; else side = value; return side * sign; } static float V_CalcBob(void) { float bob, 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 = sqrtf(cl.velocity[0] * cl.velocity[0] + cl.velocity[1] * cl.velocity[1]) * cl_bob.value; bob = bob * 0.3 + bob * 0.7 * sinf(cycle); if(bob > 4) bob = 4; else if(bob < -7) bob = -7; return bob; } void V_StartPitchDrift(cmd_t *c) { USED(c); if(cl.laststop == cl.time) return; // something else is keeping it from drifting 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; } /* * 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 */ static 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.value) cl.driftmove = 0; else cl.driftmove += scr_frametime; if(cl.driftmove > v_centermove.value) V_StartPitchDrift(nil); return; } delta = cl.idealpitch - cl.viewangles[PITCH]; if(!delta) { cl.pitchvel = 0; return; } move = scr_frametime * cl.pitchvel; cl.pitchvel += scr_frametime * v_centerspeed.value; // Con_Printf("move: %f (%f)\n", move, scr_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; } } void V_ParseDamage(void) { int armor, blood; vec3_t from, forward, right, up; entity_t *ent; float side, count; armor = MSG_ReadByte(); blood = MSG_ReadByte(); MSG_ReadVec(cl.protocol, from); 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; } static void V_cshift_f(cmd_t *c) { USED(c); 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)); } /* When you run over an item, the server sends this command */ static void V_BonusFlash_f(cmd_t *c) { USED(c); 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; } /* 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; } } static 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; } static void V_Blend(void) { float c[4], a; int i; c[0] = c[1] = c[2] = c[3] = 0; for(i = 0; i < NUM_CSHIFTS; i++) { a = ((cl.cshifts[i].percent * v_cshiftpercent.value) / 100.0) / 255.0; if(a > 0) { c[3] += a * (1 - c[3]); a = a / c[3]; c[0] = c[0] * (1 - a) + cl.cshifts[i].destcolor[0] * a; c[1] = c[1] * (1 - a) + cl.cshifts[i].destcolor[1] * a; c[2] = c[2] * (1 - a) + cl.cshifts[i].destcolor[2] * a; } } c[3] = clamp(c[3], 0, 1.0); c[2] *= c[3] / 255.0; c[1] *= c[3] / 255.0; c[0] *= c[3] / 255.0; cmsetvblend(c); } void V_ApplyShifts(void) { int i, j; bool update; V_CalcPowerupCshift(); update = false; for(i = 0; i < NUM_CSHIFTS; i++) { if(cl.cshifts[i].percent != cl.prev_cshifts[i].percent) { cl.prev_cshifts[i].percent = cl.cshifts[i].percent; update = true; } for(j = 0; j < 3; j++) { if(cl.cshifts[i].destcolor[j] != cl.prev_cshifts[i].destcolor[j]) { cl.prev_cshifts[i].destcolor[j] = cl.cshifts[i].destcolor[j]; update = true; } } } // drop the damage value if(cl.cshifts[CSHIFT_DAMAGE].percent > 0) { cl.cshifts[CSHIFT_DAMAGE].percent -= scr_frametime * 150; if(cl.cshifts[CSHIFT_DAMAGE].percent < 0) cl.cshifts[CSHIFT_DAMAGE].percent = 0; } // drop the bonus value if(cl.cshifts[CSHIFT_BONUS].percent > 0) { cl.cshifts[CSHIFT_BONUS].percent -= scr_frametime * 100; if(cl.cshifts[CSHIFT_BONUS].percent < 0) cl.cshifts[CSHIFT_BONUS].percent = 0; } if(update) V_Blend(); } static float angledelta(float a) { a = anglemod(a); if(a > 180) a -= 360; return a; } static void CalcGunAngle(void) { static float oldyaw = 0; static float oldpitch = 0; float yaw, pitch, move; yaw = r_refdef.view.angles[YAW]; pitch = -r_refdef.view.angles[PITCH]; yaw = angledelta(yaw - r_refdef.view.angles[YAW]) * 0.4; if(yaw > 10) yaw = 10; else if(yaw < -10) yaw = -10; pitch = angledelta(-pitch - r_refdef.view.angles[PITCH]) * 0.4; if(pitch > 10) pitch = 10; else if(pitch < -10) pitch = -10; move = scr_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.view.angles[YAW] + yaw; cl.viewent.angles[PITCH] = -(r_refdef.view.angles[PITCH] + pitch); cl.viewent.angles[ROLL] -= v_idlescale.value * sinf(cl.time * v_iroll_cycle.value) * v_iroll_level.value; cl.viewent.angles[PITCH] -= v_idlescale.value * sinf(cl.time * v_ipitch_cycle.value) * v_ipitch_level.value; cl.viewent.angles[YAW] -= v_idlescale.value * sinf(cl.time * v_iyaw_cycle.value) * v_iyaw_level.value; } static 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.view.org[0] < ent->origin[0] - 14) r_refdef.view.org[0] = ent->origin[0] - 14; else if(r_refdef.view.org[0] > ent->origin[0] + 14) r_refdef.view.org[0] = ent->origin[0] + 14; if(r_refdef.view.org[1] < ent->origin[1] - 14) r_refdef.view.org[1] = ent->origin[1] - 14; else if(r_refdef.view.org[1] > ent->origin[1] + 14) r_refdef.view.org[1] = ent->origin[1] + 14; if(r_refdef.view.org[2] < ent->origin[2] - 22) r_refdef.view.org[2] = ent->origin[2] - 22; else if(r_refdef.view.org[2] > ent->origin[2] + 30) r_refdef.view.org[2] = ent->origin[2] + 30; } /* Idle swaying */ static void V_AddIdle(void) { r_refdef.view.angles[ROLL] += v_idlescale.value * sinf(cl.time * v_iroll_cycle.value) * v_iroll_level.value; r_refdef.view.angles[PITCH] += v_idlescale.value * sinf(cl.time * v_ipitch_cycle.value) * v_ipitch_level.value; r_refdef.view.angles[YAW] += v_idlescale.value * sinf(cl.time * v_iyaw_cycle.value) * v_iyaw_level.value; } /* Roll is induced by movement and damage */ static void V_CalcViewRoll(void) { float side; side = V_CalcRoll(cl_entities[cl.viewentity].angles, cl.velocity); r_refdef.view.angles[ROLL] += side; if(v_dmg_time > 0) { r_refdef.view.angles[ROLL] += v_dmg_time / v_kicktime.value * v_dmg_roll; r_refdef.view.angles[PITCH] += v_dmg_time / v_kicktime.value * v_dmg_pitch; v_dmg_time -= scr_frametime; } if(cl.stats[STAT_HEALTH] <= 0) { r_refdef.view.angles[ROLL] = 80; // dead view angle return; } } static void V_CalcIntermissionRefdef(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.view.org); VectorCopy(ent->angles, r_refdef.view.angles); view->model = nil;