COPYRIGHTS/PERMISSIONS: This source code cannot be used in anyway without giving me (the author) full credit for its use. It can be distributed freely as long as the distribution includes this text file. This source code is distributed under the GPL (gnu public license, see gnu.txt for details) just as the original Quake source code. This tutorial will show you how to put a real functional chasecam into your QuakeWorld client, which can be used on any server in any mod. First you'll need the Quake source code. This tutorial tells you what to do for the QuakeWorld client code, I'm not sure if it'd work the same for Quake or not. Just do what it says to in the appropriate files and you'll be all set. CL_ENTS.C --------- In void CL_LinkPlayers (void), find this: if (j == cl.playernum) continue; if (j == cl.playernum && !cl_chase.value) continue; CL_SetSolidPlayers (j); CL_PredictUsercmd (state, &exact, &state->command, false); pmove.numphysent = oldphysent; VectorCopy (exact.origin, ent->origin); } //RICH if (j == cl.playernum) { ent->origin[0] = cl.simorg[0]; ent->origin[1] = cl.simorg[1]; ent->origin[2] = cl.simorg[2]; } //we already know our exact location, don't update normally. //END RICH // // angles // //RICH if (j == cl.playernum) { ent->angles[PITCH] = -cl.simangles[PITCH]/3; ent->angles[YAW] = cl.simangles[YAW]; ent->angles[ROLL] = cl.simangles[ROLL]; } //otherwise you'll see yourself as always facing one way else { ent->angles[PITCH] = -state->viewangles[PITCH]/3; ent->angles[YAW] = state->viewangles[YAW]; ent->angles[ROLL] = 0; ent->angles[ROLL] = V_CalcRoll (ent->angles, state->velocity)*4; } //END RICH //RICH extern cvar_t cl_chase; //END RICH ------ Find the void V_CalcRefdef (void) function, and put this right above it: //RICH extern cvar_t cl_chase; extern cvar_t cl_chase_dist; extern cvar_t cl_chase_vert; //END RICH //RICH int cont = 0; vec3_t old_vorg; //END RICH // offsets AngleVectors (cl.simangles, forward, right, up); //RICH if (cl_chase.value) { old_vorg[0] = r_refdef.vieworg[0]; old_vorg[1] = r_refdef.vieworg[1]; old_vorg[2] = r_refdef.vieworg[2]; r_refdef.vieworg[0] = r_refdef.vieworg[0] - forward[0]*cl_chase_dist.value; r_refdef.vieworg[1] = r_refdef.vieworg[1] - forward[1]*cl_chase_dist.value; r_refdef.vieworg[2] = r_refdef.vieworg[2] + cl_chase_vert.value; cont = PM_PointContents (r_refdef.vieworg); while (cont == CONTENTS_SOLID) { //quick hack for view clipping if (r_refdef.vieworg[2] > old_vorg[2]) r_refdef.vieworg[2]--; //Go down until we're at the original view //origin to avoid clipping errors. if (r_refdef.vieworg[1] != old_vorg[1]) r_refdef.vieworg[1] += forward[1]*0.1; //slowly trace back up if (r_refdef.vieworg[0] != old_vorg[0]) r_refdef.vieworg[0] += forward[0]*0.1; //slowly trace back up cont = PM_PointContents (r_refdef.vieworg); } } //END RICH if (view_message->flags & (PF_GIB|PF_DEAD) ) view->model = NULL; else view->model = cl.model_precache[cl.stats[STAT_WEAPON]]; //RICH if (cl_chase.value) view->model = NULL; //don't show weapon in cam mode //END RICH --------- Find the line that says cvar_t localid = {"localid", ""};, and put this right below it: //RICH cvar_t cl_chase = {"cl_chase", "1"}; cvar_t cl_chase_vert = {"cl_chase_v", "30"}; cvar_t cl_chase_dist = {"cl_chase_d", "50"}; //END RICH Cvar_RegisterVariable (&cl_chase); Cvar_RegisterVariable (&cl_chase_vert); Cvar_RegisterVariable (&cl_chase_dist); -Rich |