relocated the CL_SendMove call to put it at the end of network parsing (and only...
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sat, 30 Apr 2005 07:14:37 +0000 (07:14 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sat, 30 Apr 2005 07:14:37 +0000 (07:14 +0000)
changed CL_TraceLine to CL_TraceBox and made it return a trace_t
worked on CL_ClientMovement function for clientside movement simulation (not working yet), this has many cl_movement* cvars associated with it which will be updated by the server at some point in the future
added (currently unused and not updated) cl_gravity and cl_slowmo cvars, which the server will be setting at some point in the future

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@5211 d7cf8633-e32d-0410-b094-e92efae38249

16 files changed:
cgamevm.c
cl_collision.c
cl_collision.h
cl_input.c
cl_main.c
cl_parse.c
cl_particles.c
client.h
model_shared.c
netconn.c
protocol.c
r_crosshairs.c
r_explosion.c
r_light.c
r_shadow.c
view.c

index e2b33f4..3af510f 100644 (file)
--- a/cgamevm.c
+++ b/cgamevm.c
@@ -194,19 +194,13 @@ float CGVM_RandomRange(const float r1, const float r2)
 
 float CGVM_TracePhysics(const float *start, const float *end, const float *worldmins, const float *worldmaxs, const float *entitymins, const float *entitymaxs, const cgphysentity_t *physentities, const int numphysentities, float *impactpos, float *impactnormal, int *impactentnum)
 {
-       float frac;
-       vec3_t start2, end2, middle;
+       trace_t trace;
        // FIXME: do tracing agains network entities and physentities here
-       // placeholder world only code assuming 0 size
-       middle[0] = (worldmins[0] + worldmaxs[0]) * 0.5f;
-       middle[1] = (worldmins[1] + worldmaxs[1]) * 0.5f;
-       middle[2] = (worldmins[2] + worldmaxs[2]) * 0.5f;
-       VectorAdd(start, middle, start2);
-       VectorAdd(end, middle, end2);
-       frac = CL_TraceLine((float *)start2, (float *)end2, impactpos, impactnormal, true, NULL, SUPERCONTENTS_SOLID);
-       VectorSubtract(impactpos, middle, impactpos);
+       trace = CL_TraceBox(start, vec3_origin, vec3_origin, end, true, NULL, SUPERCONTENTS_SOLID, false);
+       VectorCopy(trace.endpos, impactpos);
+       VectorCopy(trace.plane.normal, impactnormal);
        *impactentnum = -1;
-       return frac;
+       return trace.fraction;
 }
 
 char *CGVM_GetCvarString(const char *name)
index 41734b3..8920a5e 100644 (file)
@@ -29,42 +29,40 @@ typedef struct physentity_s
 physentity_t;
 */
 
-int cl_traceline_startsupercontents;
-
-float CL_TraceLine(const vec3_t start, const vec3_t end, vec3_t impact, vec3_t normal, int hitbmodels, int *hitent, int hitsupercontentsmask)
+trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitbmodels, int *hitent, int hitsupercontentsmask, qboolean hitplayers)
 {
-       float maxfrac, maxrealfrac;
        int n;
        entity_render_t *ent;
-       float tracemins[3], tracemaxs[3];
-       trace_t trace;
-       float tempnormal[3], starttransformed[3], endtransformed[3];
+       vec3_t tracemins, tracemaxs;
+       trace_t cliptrace, trace;
+       vec3_t starttransformed, endtransformed, starttransformedmins, endtransformedmins, starttransformedmaxs, endtransformedmaxs;
+       vec3_t startmins, startmaxs, endmins, endmaxs, entmins, entmaxs;
+       vec_t *playermins, *playermaxs;
 
-       memset (&trace, 0 , sizeof(trace_t));
-       trace.fraction = 1;
-       trace.realfraction = 1;
-       VectorCopy (end, trace.endpos);
+       VectorAdd(start, mins, startmins);
+       VectorAdd(start, maxs, startmaxs);
+       VectorAdd(end, mins, endmins);
+       VectorAdd(end, maxs, endmaxs);
+
+       memset (&cliptrace, 0 , sizeof(trace_t));
+       cliptrace.fraction = 1;
+       cliptrace.realfraction = 1;
 
-       if (hitent)
-               *hitent = 0;
        Mod_CheckLoaded(cl.worldmodel);
        if (cl.worldmodel && cl.worldmodel->TraceBox)
-               cl.worldmodel->TraceBox(cl.worldmodel, 0, &trace, start, start, end, end, hitsupercontentsmask);
+               cl.worldmodel->TraceBox(cl.worldmodel, 0, &cliptrace, startmins, startmaxs, endmins, endmaxs, hitsupercontentsmask);
 
-       if (normal)
-               VectorCopy(trace.plane.normal, normal);
-       cl_traceline_startsupercontents = trace.startsupercontents;
-       maxfrac = trace.fraction;
-       maxrealfrac = trace.realfraction;
+       if (hitent)
+               *hitent = 0;
 
        if (hitbmodels && cl_num_brushmodel_entities)
        {
-               tracemins[0] = min(start[0], end[0]);
-               tracemaxs[0] = max(start[0], end[0]);
-               tracemins[1] = min(start[1], end[1]);
-               tracemaxs[1] = max(start[1], end[1]);
-               tracemins[2] = min(start[2], end[2]);
-               tracemaxs[2] = max(start[2], end[2]);
+               tracemins[0] = min(start[0], end[0]) + mins[0];
+               tracemaxs[0] = max(start[0], end[0]) + maxs[0];
+               tracemins[1] = min(start[1], end[1]) + mins[1];
+               tracemaxs[1] = max(start[1], end[1]) + maxs[1];
+               tracemins[2] = min(start[2], end[2]) + mins[2];
+               tracemaxs[2] = max(start[2], end[2]) + maxs[2];
 
                // look for embedded bmodels
                for (n = 0;n < cl_num_brushmodel_entities;n++)
@@ -75,31 +73,111 @@ float CL_TraceLine(const vec3_t start, const vec3_t end, vec3_t impact, vec3_t n
 
                        Matrix4x4_Transform(&ent->inversematrix, start, starttransformed);
                        Matrix4x4_Transform(&ent->inversematrix, end, endtransformed);
+                       VectorAdd(starttransformed, mins, starttransformedmins);
+                       VectorAdd(starttransformed, maxs, starttransformedmaxs);
+                       VectorAdd(endtransformed, mins, endtransformedmins);
+                       VectorAdd(endtransformed, maxs, endtransformedmaxs);
+
+                       memset (&trace, 0 , sizeof(trace_t));
+                       trace.fraction = 1;
+                       trace.realfraction = 1;
 
                        if (ent->model && ent->model->TraceBox)
-                               ent->model->TraceBox(ent->model, 0, &trace, starttransformed, starttransformed, endtransformed, endtransformed, hitsupercontentsmask);
+                               ent->model->TraceBox(ent->model, 0, &trace, starttransformedmins, starttransformedmaxs, endtransformedmins, endtransformedmaxs, hitsupercontentsmask);
 
-                       cl_traceline_startsupercontents |= trace.startsupercontents;
-                       if (maxrealfrac > trace.realfraction)
+                       // LordHavoc: take the 'best' answers from the new trace and combine with existing data
+                       if (trace.allsolid)
+                               cliptrace.allsolid = true;
+                       if (trace.startsolid)
                        {
+                               cliptrace.startsolid = true;
+                               if (cliptrace.realfraction == 1)
+                                       if (hitent)
+                                               *hitent = cl_brushmodel_entities[n];
+                       }
+                       // don't set this except on the world, because it can easily confuse
+                       // monsters underwater if there's a bmodel involved in the trace
+                       // (inopen && inwater is how they check water visibility)
+                       //if (trace.inopen)
+                       //      cliptrace.inopen = true;
+                       if (trace.inwater)
+                               cliptrace.inwater = true;
+                       if (trace.realfraction < cliptrace.realfraction)
+                       {
+                               cliptrace.fraction = trace.fraction;
+                               cliptrace.realfraction = trace.realfraction;
+                               cliptrace.plane = trace.plane;
                                if (hitent)
                                        *hitent = cl_brushmodel_entities[n];
-                               maxfrac = trace.fraction;
-                               maxrealfrac = trace.realfraction;
-                               if (normal)
+                               Matrix4x4_Transform3x3(&ent->matrix, trace.plane.normal, cliptrace.plane.normal);
+                       }
+                       cliptrace.startsupercontents |= trace.startsupercontents;
+               }
+       }
+       if (hitplayers)
+       {
+               tracemins[0] = min(start[0], end[0]) + mins[0];
+               tracemaxs[0] = max(start[0], end[0]) + maxs[0];
+               tracemins[1] = min(start[1], end[1]) + mins[1];
+               tracemaxs[1] = max(start[1], end[1]) + maxs[1];
+               tracemins[2] = min(start[2], end[2]) + mins[2];
+               tracemaxs[2] = max(start[2], end[2]) + maxs[2];
+
+               for (n = 1;n < cl.maxclients+1;n++)
+               {
+                       if (n != cl.playerentity)
+                       {
+                               ent = &cl_entities[n].render;
+                               // FIXME: crouch
+                               playermins = cl_playerstandmins;
+                               playermaxs = cl_playerstandmaxs;
+                               VectorAdd(ent->origin, playermins, entmins);
+                               VectorAdd(ent->origin, playermaxs, entmaxs);
+                               if (!BoxesOverlap(tracemins, tracemaxs, entmins, entmaxs))
+                                       continue;
+
+                               memset (&trace, 0 , sizeof(trace_t));
+                               trace.fraction = 1;
+                               trace.realfraction = 1;
+
+                               Matrix4x4_Transform(&ent->inversematrix, start, starttransformed);
+                               Matrix4x4_Transform(&ent->inversematrix, end, endtransformed);
+                               Collision_ClipTrace_Box(&trace, playermins, playermaxs, starttransformed, mins, maxs, endtransformed, hitsupercontentsmask, SUPERCONTENTS_SOLID);
+
+                               // LordHavoc: take the 'best' answers from the new trace and combine with existing data
+                               if (trace.allsolid)
+                                       cliptrace.allsolid = true;
+                               if (trace.startsolid)
+                               {
+                                       cliptrace.startsolid = true;
+                                       if (cliptrace.realfraction == 1)
+                                               if (hitent)
+                                                       *hitent = n;
+                               }
+                               // don't set this except on the world, because it can easily confuse
+                               // monsters underwater if there's a bmodel involved in the trace
+                               // (inopen && inwater is how they check water visibility)
+                               //if (trace.inopen)
+                               //      cliptrace.inopen = true;
+                               if (trace.inwater)
+                                       cliptrace.inwater = true;
+                               if (trace.realfraction < cliptrace.realfraction)
                                {
-                                       VectorCopy(trace.plane.normal, tempnormal);
-                                       Matrix4x4_Transform3x3(&ent->matrix, tempnormal, normal);
+                                       cliptrace.fraction = trace.fraction;
+                                       cliptrace.realfraction = trace.realfraction;
+                                       cliptrace.plane = trace.plane;
+                                       if (hitent)
+                                               *hitent = n;
+                                       Matrix4x4_Transform3x3(&ent->matrix, trace.plane.normal, cliptrace.plane.normal);
                                }
+                               cliptrace.startsupercontents |= trace.startsupercontents;
                        }
                }
        }
-       maxfrac = bound(0, maxfrac, 1);
-       maxrealfrac = bound(0, maxrealfrac, 1);
-       //if (maxfrac < 0 || maxfrac > 1) Con_Printf("fraction out of bounds %f %s:%d\n", maxfrac, __FILE__, __LINE__);
-       if (impact)
-               VectorLerp(start, maxfrac, end, impact);
-       return maxfrac;
+       cliptrace.fraction = bound(0, cliptrace.fraction, 1);
+       cliptrace.realfraction = bound(0, cliptrace.realfraction, 1);
+       VectorLerp(start, cliptrace.fraction, end, cliptrace.endpos);
+       return cliptrace;
 }
 
 float CL_SelectTraceLine(const vec3_t start, const vec3_t end, vec3_t impact, vec3_t normal, int *hitent, entity_render_t *ignoreent)
@@ -124,7 +202,7 @@ float CL_SelectTraceLine(const vec3_t start, const vec3_t end, vec3_t impact, ve
 
        if (normal)
                VectorCopy(trace.plane.normal, normal);
-       cl_traceline_startsupercontents = trace.startsupercontents;
+       //cl_traceline_startsupercontents = trace.startsupercontents;
        maxfrac = trace.fraction;
        maxrealfrac = trace.realfraction;
 
@@ -156,7 +234,7 @@ float CL_SelectTraceLine(const vec3_t start, const vec3_t end, vec3_t impact, ve
                if (ent->model && ent->model->TraceBox)
                        ent->model->TraceBox(ent->model, ent->frameblend[0].frame, &trace, starttransformed, starttransformed, endtransformed, endtransformed, SUPERCONTENTS_SOLID);
 
-               cl_traceline_startsupercontents |= trace.startsupercontents;
+               //cl_traceline_startsupercontents |= trace.startsupercontents;
                if (maxrealfrac > trace.realfraction)
                {
                        if (hitent)
@@ -187,8 +265,7 @@ void CL_FindNonSolidLocation(const vec3_t in, vec3_t out, vec_t radius)
 
 int CL_PointQ1Contents(const vec3_t p)
 {
-       CL_TraceLine(p, p, NULL, NULL, true, NULL, 0);
-       return Mod_Q1BSP_NativeContentsFromSuperContents(NULL, cl_traceline_startsupercontents);
+       return Mod_Q1BSP_NativeContentsFromSuperContents(NULL, CL_TraceBox(p, vec3_origin, vec3_origin, p, true, NULL, 0, false).startsupercontents);
        /*
        // FIXME: check multiple brush models
        if (cl.worldmodel && cl.worldmodel->brush.PointContentsQ1)
@@ -199,8 +276,7 @@ int CL_PointQ1Contents(const vec3_t p)
 
 int CL_PointSuperContents(const vec3_t p)
 {
-       CL_TraceLine(p, p, NULL, NULL, true, NULL, 0);
-       return cl_traceline_startsupercontents;
+       return CL_TraceBox(p, vec3_origin, vec3_origin, p, true, NULL, 0, false).startsupercontents;
        /*
        // FIXME: check multiple brush models
        if (cl.worldmodel && cl.worldmodel->brush.PointContentsQ1)
index bf5390a..532ad25 100644 (file)
@@ -2,11 +2,7 @@
 #ifndef CL_COLLISION_H
 #define CL_COLLISION_H
 
-// if contents is not zero, it will impact on content changes
-// (leafs matching contents are considered empty, others are solid)
-extern int cl_traceline_startcontents; // set by TraceLine
-
-float CL_TraceLine(const vec3_t start, const vec3_t end, vec3_t impact, vec3_t normal, int hitbmodels, int *hitent, int hitsupercontentsmask);
+trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitbmodels, int *hitent, int hitsupercontentsmask, qboolean hitplayers);
 float CL_SelectTraceLine(const vec3_t start, const vec3_t end, vec3_t impact, vec3_t normal, int *hitent, entity_render_t *ignoreent);
 void CL_FindNonSolidLocation(const vec3_t in, vec3_t out, vec_t radius);
 int CL_PointQ1Contents(const vec3_t p);
index f4bb34f..d0bccf0 100644 (file)
@@ -249,6 +249,19 @@ cvar_t cl_pitchspeed = {CVAR_SAVE, "cl_pitchspeed","150"};
 
 cvar_t cl_anglespeedkey = {CVAR_SAVE, "cl_anglespeedkey","1.5"};
 
+cvar_t cl_movement = {CVAR_SAVE, "cl_movement", "0"};
+cvar_t cl_movement_latency = {0, "cl_movement_latency", "0"};
+cvar_t cl_movement_maxspeed = {0, "cl_movement_maxspeed", "320"};
+cvar_t cl_movement_maxairspeed = {0, "cl_movement_maxairspeed", "30"};
+cvar_t cl_movement_stopspeed = {0, "cl_movement_stopspeed", "100"};
+cvar_t cl_movement_friction = {0, "cl_movement_friction", "4"};
+cvar_t cl_movement_edgefriction = {0, "cl_movement_edgefriction", "2"};
+cvar_t cl_movement_stepheight = {0, "cl_movement_stepheight", "18"};
+cvar_t cl_movement_accelerate = {0, "cl_movement_accelerate", "10"};
+cvar_t cl_gravity = {0, "cl_gravity", "800"};
+cvar_t cl_slowmo = {0, "cl_slowmo", "1"};
+
+
 /*
 ================
 CL_AdjustAngles
@@ -403,6 +416,219 @@ void CL_UpdatePrydonCursor(void)
        //CL_SparkShower(cl.cmd.cursor_impact, cl.cmd.cursor_normal, 5, 0);
 }
 
+void CL_ClientMovement(qboolean buttonjump, qboolean buttoncrouch)
+{
+       int i, n, bump, contents, crouch;
+       //double simulatedtime;
+       double currenttime;
+       double newtime;
+       double frametime;
+       double t;
+       vec_t wishspeed, addspeed, accelspeed, f, *playermins, *playermaxs;
+       client_movementqueue_t *q;
+       vec3_t currentorigin, currentvelocity, forward, right, up, wishvel, wishdir, neworigin, currentorigin2, neworigin2, yawangles;
+       trace_t trace, trace2, trace3;
+       // remove stale queue items
+       n = cl.movement_numqueue;
+       cl.movement_numqueue = 0;
+       for (i = 0;i < n;i++)
+               if (cl.movement_queue[i].time >= cl.mtime[0])
+                       cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i];
+       // add to input queue if there is room
+       if (cl.movement_numqueue < sizeof(cl.movement_queue)/sizeof(cl.movement_queue[0]))
+       {
+               // add to input queue
+               cl.movement_queue[cl.movement_numqueue].time = cl.mtime[0] + cl_movement_latency.value;
+               VectorCopy(cl.viewangles, cl.movement_queue[cl.movement_numqueue].viewangles);
+               cl.movement_queue[cl.movement_numqueue].move[0] = cl.cmd.forwardmove;
+               cl.movement_queue[cl.movement_numqueue].move[1] = cl.cmd.sidemove;
+               cl.movement_queue[cl.movement_numqueue].move[2] = cl.cmd.upmove;
+               cl.movement_queue[cl.movement_numqueue].jump = buttonjump;
+               cl.movement_queue[cl.movement_numqueue].crouch = buttoncrouch;
+               cl.movement_numqueue++;
+       }
+       cl.movement = false;
+       // abort if client movement is disabled
+       if (!cl_movement.integer || cl.stats[STAT_HEALTH] <= 0)
+               return;
+       // fetch current starting values
+       currenttime = cl.mtime[0];
+       VectorCopy(cl_entities[cl.playerentity].state_current.origin, currentorigin);
+       VectorCopy(cl.mvelocity[0], currentvelocity);
+       // calculate time to execute for
+       //simulatedtime = currenttime + cl_movement_latency.value;
+       // FIXME: try minor nudges in various directions if startsolid to find a
+       // safe place to start the walk (due to network compression in some
+       // protocols this starts in solid)
+       //currentorigin[2] += (1.0 / 32.0); // slight nudge to get out of the floor
+       crouch = false; // this will be updated on first move
+       //Con_Printf("%f: ", currenttime);
+       // replay input queue, and remove any stale queue items
+       // note: this relies on the fact there's always one queue item at the end
+       for (i = 0, q = cl.movement_queue;i < cl.movement_numqueue;i++, q++)
+       {
+               //newtime = (i == cl.movement_numqueue) ? simulatedtime : q->time;
+               newtime = q->time;
+               frametime = newtime - currenttime;
+               if (frametime < 0)
+                       continue;
+               //Con_Printf(" %f", frametime);
+               currenttime = newtime;
+               if (crouch)
+               {
+                       playermins = cl_playercrouchmins;
+                       playermaxs = cl_playercrouchmaxs;
+               }
+               else
+               {
+                       playermins = cl_playerstandmins;
+                       playermaxs = cl_playerstandmaxs;
+               }
+               for (bump = 0, t = frametime;bump < 8 && VectorLength2(currentvelocity) > 0;bump++)
+               {
+                       VectorMA(currentorigin, t, currentvelocity, neworigin);
+                       trace = CL_TraceBox(currentorigin, playermins, playermaxs, neworigin, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
+                       if (trace.fraction < 1 && trace.plane.normal[2] == 0)
+                       {
+                               // may be a step or wall, try stepping up
+                               // first move forward at a higher level
+                               VectorSet(currentorigin2, currentorigin[0], currentorigin[1], currentorigin[2] + cl_movement_stepheight.value);
+                               VectorSet(neworigin2, neworigin[0], neworigin[1], currentorigin[2] + cl_movement_stepheight.value);
+                               trace2 = CL_TraceBox(currentorigin2, playermins, playermaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
+                               // then move down from there
+                               VectorCopy(trace2.endpos, currentorigin2);
+                               VectorSet(neworigin2, trace2.endpos[0], trace2.endpos[1], currentorigin[2]);
+                               trace3 = CL_TraceBox(currentorigin2, playermins, playermaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
+                               //Con_Printf("%f %f %f %f : %f %f %f %f : %f %f %f %f\n", trace.fraction, trace.endpos[0], trace.endpos[1], trace.endpos[2], trace2.fraction, trace2.endpos[0], trace2.endpos[1], trace2.endpos[2], trace3.fraction, trace3.endpos[0], trace3.endpos[1], trace3.endpos[2]);
+                               // accept the new trace if it made some progress
+                               if (fabs(trace3.endpos[0] - trace.endpos[0]) >= 0.03125 || fabs(trace3.endpos[1] - trace.endpos[1]) >= 0.03125)
+                               {
+                                       trace = trace2;
+                                       VectorCopy(trace3.endpos, trace.endpos);
+                               }
+                       }
+                       if (trace.fraction == 1)
+                       {
+                               VectorCopy(trace.endpos, currentorigin);
+                               break;
+                       }
+                       t *= 1 - trace.fraction;
+                       if (trace.fraction >= 0.001)
+                               VectorCopy(trace.endpos, currentorigin);
+                       f = DotProduct(currentvelocity, trace.plane.normal);
+                       VectorMA(currentvelocity, -f, trace.plane.normal, currentvelocity);
+               }
+               if (i < cl.movement_numqueue)
+               {
+                       if (q->crouch)
+                       {
+                               // wants to crouch, this always works...
+                               if (!crouch)
+                                       crouch = true;
+                       }
+                       else
+                       {
+                               // wants to stand, if currently crouching we need to check for a
+                               // low ceiling first
+                               if (crouch)
+                               {
+                                       trace = CL_TraceBox(currentorigin, cl_playerstandmins, cl_playerstandmaxs, currentorigin, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
+                                       if (!trace.startsolid)
+                                               crouch = false;
+                               }
+                       }
+                       // change velocity according to q->viewangles and q->move
+                       contents = CL_PointSuperContents(currentorigin);
+                       if (contents & SUPERCONTENTS_LIQUIDSMASK)
+                       {
+                               // swim
+                               AngleVectors(q->viewangles, forward, right, up);
+                               VectorSet(up, 0, 0, 1);
+                               VectorMAMAM(q->move[0], forward, q->move[1], right, q->move[2], up, wishvel);
+                               wishspeed = VectorLength(wishvel);
+                               if (wishspeed)
+                                       VectorScale(wishvel, 1 / wishspeed, wishdir);
+                               wishspeed = min(wishspeed, cl_movement_maxspeed.value);
+                               if (crouch)
+                                       wishspeed *= 0.5;
+                               wishspeed *= 0.6;
+                               VectorScale(currentvelocity, (1 - frametime * cl_movement_friction.value), currentvelocity);
+                               f = wishspeed - DotProduct(currentvelocity, wishdir);
+                               if (f > 0)
+                               {
+                                       f = min(f, cl_movement_accelerate.value * frametime * wishspeed);
+                                       VectorMA(currentvelocity, f, wishdir, currentvelocity);
+                               }
+                               if (q->jump)
+                               {
+                                       if (contents & SUPERCONTENTS_LAVA)
+                                               currentvelocity[2] =  50;
+                                       else if (contents & SUPERCONTENTS_SLIME)
+                                               currentvelocity[2] =  80;
+                                       else
+                                       {
+                                               if (gamemode == GAME_NEXUIZ)
+                                                       currentvelocity[2] = 200;
+                                               else
+                                                       currentvelocity[2] = 100;
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               // walk
+                               VectorSet(yawangles, 0, cl.viewangles[1], 0);
+                               AngleVectors(yawangles, forward, right, up);
+                               VectorMAM(q->move[0], forward, q->move[1], right, wishvel);
+                               wishspeed = VectorLength(wishvel);
+                               if (wishspeed)
+                                       VectorScale(wishvel, 1 / wishspeed, wishdir);
+                               wishspeed = min(wishspeed, cl_movement_maxspeed.value);
+                               if (crouch)
+                                       wishspeed *= 0.5;
+                               // check if onground
+                               VectorSet(currentorigin2, currentorigin[0], currentorigin[1], currentorigin[2] + 1);
+                               VectorSet(neworigin2, currentorigin[0], currentorigin[1], currentorigin[2] - 1);
+                               trace = CL_TraceBox(currentorigin2, playermins, playermaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
+                               if (trace.fraction < 1 && trace.plane.normal[2] > 0.7)
+                               {
+                                       // apply ground friction
+                                       f = sqrt(currentvelocity[0] * currentvelocity[0] + currentvelocity[1] * currentvelocity[1]);
+                                       VectorSet(currentorigin2, currentorigin[0] + currentvelocity[0]*(16/f), currentorigin[1] + currentvelocity[1]*(16/f), currentorigin[2] + playermins[2]);
+                                       VectorSet(neworigin2, currentorigin2[0], currentorigin2[1], currentorigin2[2] - 34);
+                                       trace = CL_TraceBox(currentorigin2, vec3_origin, vec3_origin, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
+                                       // apply friction
+                                       f = 1 - frametime * (trace.fraction == 1 ? cl_movement_edgefriction.value : 1) * ((f < cl_movement_stopspeed.value) ? (cl_movement_stopspeed.value / f) : 1) * cl_movement_friction.value;
+                                       f = max(f, 0);
+                                       VectorScale(currentvelocity, f, currentvelocity);
+                               }
+                               else
+                               {
+                                       // apply air speed limit
+                                       wishspeed = min(wishspeed, cl_movement_maxairspeed.value);
+                               }
+                               if (gamemode == GAME_NEXUIZ)
+                                       addspeed = wishspeed;
+                               else
+                                       addspeed = wishspeed - DotProduct(currentvelocity, wishdir);
+                               if (addspeed > 0)
+                               {
+                                       accelspeed = min(cl_movement_accelerate.value * frametime * wishspeed, addspeed);
+                                       VectorMA(currentvelocity, accelspeed, wishdir, currentvelocity);
+                               }
+                               currentvelocity[2] -= cl_gravity.value * frametime;
+                       }
+               }
+       }
+       //Con_Printf(" :%f\n", currenttime);
+       // store replay location
+       cl.movement = true;
+       VectorCopy(cl.movement_origin, cl.movement_oldorigin);
+       VectorCopy(currentorigin, cl.movement_origin);
+       //VectorCopy(currentorigin, cl_entities[cl.playerentity].state_current.origin);
+       //VectorSet(cl_entities[cl.playerentity].state_current.angles, 0, cl.viewangles[1], 0);
+}
+
 /*
 ==============
 CL_SendMove
@@ -414,7 +640,6 @@ void CL_SendMove(void)
        int bits;
        sizebuf_t buf;
        qbyte data[128];
-       static double nextmovetime = 0;
 #define MOVEAVERAGING 0
 #if MOVEAVERAGING
        static float forwardmove, sidemove, upmove, total; // accumulation
@@ -422,8 +647,6 @@ void CL_SendMove(void)
        float forwardmove, sidemove, upmove;
 #endif
 
-       CL_UpdatePrydonCursor();
-
 #if MOVEAVERAGING
        // accumulate changes between messages
        forwardmove += cl.cmd.forwardmove;
@@ -431,11 +654,8 @@ void CL_SendMove(void)
        upmove += cl.cmd.upmove;
        total++;
 #endif
-       // LordHavoc: cap outgoing movement messages to sys_ticrate
-       nextmovetime = bound(realtime - sys_ticrate.value, nextmovetime, realtime + sys_ticrate.value);
-       if (!cl.islocalgame && realtime < nextmovetime)
+       if (cls.signon != SIGNONS)
                return;
-       nextmovetime += sys_ticrate.value;
 #if MOVEAVERAGING
        // average the accumulated changes
        total = 1.0f / total;
@@ -573,6 +793,9 @@ void CL_SendMove(void)
        if (!buf.cursize)
                return;
 
+       // FIXME: bits & 64 is +button5, Nexuiz specific
+       CL_ClientMovement((bits & 2) != 0, (bits & 64) != 0);
+
        if (NetConn_SendUnreliableMessage(cls.netcon, &buf) == -1)
        {
                Con_Print("CL_SendMove: lost server connection\n");
@@ -639,5 +862,17 @@ void CL_InitInput (void)
        Cmd_AddCommand ("-button7", IN_Button7Up);
        Cmd_AddCommand ("+button8", IN_Button8Down);
        Cmd_AddCommand ("-button8", IN_Button8Up);
+
+       Cvar_RegisterVariable(&cl_movement);
+       Cvar_RegisterVariable(&cl_movement_latency);
+       Cvar_RegisterVariable(&cl_movement_maxspeed);
+       Cvar_RegisterVariable(&cl_movement_maxairspeed);
+       Cvar_RegisterVariable(&cl_movement_stopspeed);
+       Cvar_RegisterVariable(&cl_movement_friction);
+       Cvar_RegisterVariable(&cl_movement_edgefriction);
+       Cvar_RegisterVariable(&cl_movement_stepheight);
+       Cvar_RegisterVariable(&cl_movement_accelerate);
+       Cvar_RegisterVariable(&cl_gravity);
+       Cvar_RegisterVariable(&cl_slowmo);
 }
 
index afb593a..e8760d2 100644 (file)
--- a/cl_main.c
+++ b/cl_main.c
@@ -63,6 +63,11 @@ cvar_t cl_noplayershadow = {CVAR_SAVE, "cl_noplayershadow", "0"};
 
 cvar_t cl_prydoncursor = {0, "cl_prydoncursor", "0"};
 
+vec3_t cl_playerstandmins;
+vec3_t cl_playerstandmaxs;
+vec3_t cl_playercrouchmins;
+vec3_t cl_playercrouchmaxs;
+
 mempool_t *cl_mempool;
 
 client_static_t        cls;
@@ -158,6 +163,21 @@ void CL_ClearState(void)
                cl_entities[i].state_current = defaultstate;
        }
 
+       if (gamemode == GAME_NEXUIZ)
+       {
+               VectorSet(cl_playerstandmins, -16, -16, -24);
+               VectorSet(cl_playerstandmaxs, 16, 16, 45);
+               VectorSet(cl_playercrouchmins, -16, -16, -24);
+               VectorSet(cl_playercrouchmaxs, 16, 16, 25);
+       }
+       else
+       {
+               VectorSet(cl_playerstandmins, -16, -16, -24);
+               VectorSet(cl_playerstandmaxs, 16, 16, 24);
+               VectorSet(cl_playercrouchmins, -16, -16, -24);
+               VectorSet(cl_playercrouchmaxs, 16, 16, 24);
+       }
+
        CL_Screen_NewMap();
        CL_Particles_Clear();
        CL_CGVM_Clear();
@@ -543,9 +563,10 @@ void CL_LinkNetworkEntity(entity_t *e)
        matrix4x4_t *matrix, blendmatrix, tempmatrix, matrix2;
        //matrix4x4_t dlightmatrix;
        int j, k, l, trailtype, temp;
-       float origin[3], angles[3], delta[3], lerp, dlightcolor[3], dlightradius, mins[3], maxs[3], v[3], v2[3], d;
+       float origin[3], angles[3], delta[3], lerp, dlightcolor[3], dlightradius, mins[3], maxs[3], v2[3], d;
        entity_t *t;
        model_t *model;
+       trace_t trace;
        //entity_persistent_t *p = &e->persistent;
        //entity_render_t *r = &e->render;
        if (e->persistent.linkframe != entitylinkframenumber)
@@ -617,7 +638,15 @@ void CL_LinkNetworkEntity(entity_t *e)
                }
 
                // movement lerp
-               if (e->persistent.lerpdeltatime > 0 && (lerp = (cl.time - e->persistent.lerpstarttime) / e->persistent.lerpdeltatime) < 1)
+               // if it's the player entity, update according to client movement
+               if (e == cl_entities + cl.playerentity && cl.movement)
+               {
+                       lerp = (cl.time - cl.mtime[0]) / (cl.mtime[0] - cl.mtime[1]);
+                       lerp = bound(0, lerp, 1);
+                       VectorLerp(cl.movement_oldorigin, lerp, cl.movement_origin, origin);
+                       VectorSet(angles, 0, cl.viewangles[1], 0);
+               }
+               else if (e->persistent.lerpdeltatime > 0 && (lerp = (cl.time - e->persistent.lerpstarttime) / e->persistent.lerpdeltatime) < 1)
                {
                        // interpolate the origin and angles
                        VectorLerp(e->persistent.oldorigin, lerp, e->persistent.neworigin, origin);
@@ -782,11 +811,11 @@ void CL_LinkNetworkEntity(entity_t *e)
                if (e->persistent.muzzleflash > 0)
                {
                        Matrix4x4_Transform(&e->render.matrix, muzzleflashorigin, v2);
-                       CL_TraceLine(origin, v2, v, NULL, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY);
+                       trace = CL_TraceBox(origin, vec3_origin, vec3_origin, v2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, false);
                        tempmatrix = e->render.matrix;
-                       tempmatrix.m[0][3] = v[0];
-                       tempmatrix.m[1][3] = v[1];
-                       tempmatrix.m[2][3] = v[2];
+                       tempmatrix.m[0][3] = trace.endpos[0];
+                       tempmatrix.m[1][3] = trace.endpos[1];
+                       tempmatrix.m[2][3] = trace.endpos[2];
                        CL_AllocDlight(NULL, &tempmatrix, 100, e->persistent.muzzleflash, e->persistent.muzzleflash, e->persistent.muzzleflash, 0, 0, 0, -1, true, 0, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
                        e->persistent.muzzleflash -= cl.frametime * 10;
                }
@@ -1254,10 +1283,11 @@ int CL_ReadFromServer(void)
 CL_SendCmd
 =================
 */
+void CL_UpdatePrydonCursor(void);
 void CL_SendCmd(void)
 {
        if (cls.signon == SIGNONS)
-               CL_SendMove();
+               CL_UpdatePrydonCursor();
 
        if (cls.demoplayback)
        {
index 3edb16a..e600f7c 100644 (file)
@@ -1340,6 +1340,7 @@ void CL_ParseServerMessage(void)
        qbyte           cmdlog[32];
        char            *cmdlogname[32], *temp;
        int                     cmdindex, cmdcount = 0;
+       qboolean        sendmove = false;
 
        if (cls.demorecording)
                CL_WriteDemoMessage ();
@@ -1440,6 +1441,7 @@ void CL_ParseServerMessage(void)
                case svc_time:
                        cl.mtime[1] = cl.mtime[0];
                        cl.mtime[0] = MSG_ReadFloat ();
+                       sendmove = true;
                        break;
 
                case svc_clientdata:
@@ -1758,6 +1760,12 @@ void CL_ParseServerMessage(void)
 
        EntityFrameQuake_ISeeDeadEntities();
 
+       if (sendmove)
+       {
+               // send one move per server frame
+               CL_SendMove();
+       }
+
        parsingerror = false;
 }
 
index 2ac1966..8683c08 100644 (file)
@@ -152,7 +152,7 @@ void VectorVectors(const vec3_t forward, vec3_t right, vec3_t up)
 #include "pmove.h"
 extern qboolean PM_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, pmtrace_t *trace);
 #endif
-float CL_TraceLine (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal, int hitbmodels, int *hitent, int hitsupercontentsmask)
+trace_t CL_TraceBox (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int hitbmodels, int *hitent, int hitsupercontentsmask, qboolean hitplayers)
 {
 #if QW
        pmtrace_t trace;
@@ -167,9 +167,7 @@ float CL_TraceLine (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal, int
 #else
        RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, start, end, &trace);
 #endif
-       VectorCopy(trace.endpos, impact);
-       VectorCopy(trace.plane.normal, normal);
-       return trace.fraction;
+       return trace;
 }
 #else
 #include "cl_collision.h"
@@ -476,20 +474,21 @@ void CL_SpawnDecalParticleForPoint(const vec3_t org, float maxdist, float size,
 {
        int i;
        float bestfrac, bestorg[3], bestnormal[3];
-       float frac, v[3], normal[3], org2[3];
+       float org2[3];
        int besthitent = 0, hitent;
+       trace_t trace;
        bestfrac = 10;
        for (i = 0;i < 32;i++)
        {
                VectorRandom(org2);
                VectorMA(org, maxdist, org2, org2);
-               frac = CL_TraceLine(org, org2, v, normal, true, &hitent, SUPERCONTENTS_SOLID);
-               if (bestfrac > frac)
+               trace = CL_TraceBox(org, vec3_origin, vec3_origin, org2, true, &hitent, SUPERCONTENTS_SOLID, false);
+               if (bestfrac > trace.fraction)
                {
-                       bestfrac = frac;
+                       bestfrac = trace.fraction;
                        besthitent = hitent;
-                       VectorCopy(v, bestorg);
-                       VectorCopy(normal, bestnormal);
+                       VectorCopy(trace.endpos, bestorg);
+                       VectorCopy(trace.plane.normal, bestnormal);
                }
        }
        if (bestfrac < 1)
@@ -655,6 +654,7 @@ CL_ParticleExplosion
 void CL_ParticleExplosion (vec3_t org)
 {
        int i;
+       trace_t trace;
        //vec3_t v;
        //vec3_t v2;
        if (cl_stainmaps.integer)
@@ -688,10 +688,11 @@ void CL_ParticleExplosion (vec3_t org)
                                        v[0] = org[0] + lhrandom(-48, 48);
                                        v[1] = org[1] + lhrandom(-48, 48);
                                        v[2] = org[2] + lhrandom(-48, 48);
-                                       if (CL_TraceLine(org, v, v2, NULL, true, NULL, SUPERCONTENTS_SOLID) >= 0.1)
+                                       trace = CL_TraceBox(org, vec3_origin, vec3_origin, v, true, NULL, SUPERCONTENTS_SOLID, false);
+                                       if (trace.fraction >= 0.1)
                                                break;
                                }
-                               VectorSubtract(v2, org, v2);
+                               VectorSubtract(trace.endpos, org, v2);
 #endif
                                VectorScale(v2, 2.0f, v2);
                                particle(particletype + pt_smoke, 0x202020, 0x404040, tex_smoke[rand()&7], 12, 32, 64, 0, 0, org[0], org[1], org[2], v2[0], v2[1], v2[2], 0);
@@ -796,8 +797,9 @@ void CL_SparkShower (vec3_t org, vec3_t dir, int count, vec_t gravityscale)
 
 void CL_Smoke (vec3_t org, vec3_t dir, int count)
 {
-       vec3_t org2, org3;
+       vec3_t org2;
        int k;
+       trace_t trace;
 
        if (!cl_particles.integer) return;
 
@@ -810,8 +812,8 @@ void CL_Smoke (vec3_t org, vec3_t dir, int count)
                        org2[0] = org[0] + 0.125f * lhrandom(-count, count);
                        org2[1] = org[1] + 0.125f * lhrandom(-count, count);
                        org2[2] = org[2] + 0.125f * lhrandom(-count, count);
-                       CL_TraceLine(org, org2, org3, NULL, true, NULL, SUPERCONTENTS_SOLID);
-                       particle(particletype + pt_smoke, 0x101010, 0x202020, tex_smoke[rand()&7], 3, (1.0f / cl_particles_quality.value) * 255, (1.0f / cl_particles_quality.value) * 1024, 0, 0, org3[0], org3[1], org3[2], lhrandom(-8, 8), lhrandom(-8, 8), lhrandom(-8, 8), 0);
+                       trace = CL_TraceBox(org, vec3_origin, vec3_origin, org2, true, NULL, SUPERCONTENTS_SOLID, false);
+                       particle(particletype + pt_smoke, 0x101010, 0x202020, tex_smoke[rand()&7], 3, (1.0f / cl_particles_quality.value) * 255, (1.0f / cl_particles_quality.value) * 1024, 0, 0, trace.endpos[0], trace.endpos[1], trace.endpos[2], lhrandom(-8, 8), lhrandom(-8, 8), lhrandom(-8, 8), 0);
                }
        }
 }
@@ -834,7 +836,8 @@ static float bloodcount = 0;
 void CL_BloodPuff (vec3_t org, vec3_t vel, int count)
 {
        float s;
-       vec3_t org2, org3;
+       vec3_t org2;
+       trace_t trace;
        // bloodcount is used to accumulate counts too small to cause a blood particle
        if (!cl_particles.integer) return;
        if (!cl_particles_blood.integer) return;
@@ -849,8 +852,8 @@ void CL_BloodPuff (vec3_t org, vec3_t vel, int count)
                org2[0] = org[0] + 0.125f * lhrandom(-bloodcount, bloodcount);
                org2[1] = org[1] + 0.125f * lhrandom(-bloodcount, bloodcount);
                org2[2] = org[2] + 0.125f * lhrandom(-bloodcount, bloodcount);
-               CL_TraceLine(org, org2, org3, NULL, true, NULL, SUPERCONTENTS_SOLID);
-               particle(particletype + pt_blood, 0xFFFFFF, 0xFFFFFF, tex_bloodparticle[rand()&7], 8, cl_particles_blood_alpha.value * 768 / cl_particles_quality.value, cl_particles_blood_alpha.value * 384 / cl_particles_quality.value, 0, -1, org3[0], org3[1], org3[2], vel[0] + lhrandom(-s, s), vel[1] + lhrandom(-s, s), vel[2] + lhrandom(-s, s), 1);
+               trace = CL_TraceBox(org, vec3_origin, vec3_origin, org2, true, NULL, SUPERCONTENTS_SOLID, false);
+               particle(particletype + pt_blood, 0xFFFFFF, 0xFFFFFF, tex_bloodparticle[rand()&7], 8, cl_particles_blood_alpha.value * 768 / cl_particles_quality.value, cl_particles_blood_alpha.value * 384 / cl_particles_quality.value, 0, -1, trace.endpos[0], trace.endpos[1], trace.endpos[2], vel[0] + lhrandom(-s, s), vel[1] + lhrandom(-s, s), vel[2] + lhrandom(-s, s), 1);
                bloodcount -= 16 / cl_particles_quality.value;
        }
 }
@@ -1266,8 +1269,9 @@ void CL_MoveParticles (void)
 {
        particle_t *p;
        int i, maxparticle, j, a, content;
-       float gravity, dvel, bloodwaterfade, frametime, f, dist, normal[3], v[3], org[3], oldorg[3];
+       float gravity, dvel, bloodwaterfade, frametime, f, dist, org[3], oldorg[3];
        int hitent;
+       trace_t trace;
 
        // LordHavoc: early out condition
        if (!cl_numparticles)
@@ -1312,17 +1316,17 @@ void CL_MoveParticles (void)
                                if (p->type == particletype + pt_rain)
                                {
                                        // raindrop - splash on solid/water/slime/lava
-                                       if (CL_TraceLine(oldorg, p->org, v, normal, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK) < 1)
+                                       trace = CL_TraceBox(oldorg, vec3_origin, vec3_origin, p->org, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK, false);
+                                       if (trace.fraction < 1)
                                        {
-                                               VectorCopy(v, p->org);
-                                               // splash
-                                               p->type = particletype + pt_raindecal;
                                                // convert from a raindrop particle to a rainsplash decal
+                                               VectorCopy(trace.endpos, p->org);
+                                               VectorCopy(trace.plane.normal, p->vel);
+                                               VectorAdd(p->org, p->vel, p->org);
+                                               p->type = particletype + pt_raindecal;
                                                p->texnum = tex_rainsplash[0];
                                                p->time2 = cl.time;
                                                p->alphafade = p->alpha / 0.4;
-                                               VectorCopy(normal, p->vel);
-                                               VectorAdd(p->org, normal, p->org);
                                                p->bounce = 0;
                                                p->friction = 0;
                                                p->gravity = 0;
@@ -1332,12 +1336,16 @@ void CL_MoveParticles (void)
                                else if (p->type == particletype + pt_blood)
                                {
                                        // blood - splash on solid
-                                       if (CL_TraceLine(oldorg, p->org, v, normal, true, &hitent, SUPERCONTENTS_SOLID) < 1)
+                                       trace = CL_TraceBox(oldorg, vec3_origin, vec3_origin, p->org, true, &hitent, SUPERCONTENTS_SOLID, false);
+                                       if (trace.fraction < 1)
                                        {
-                                               VectorCopy(v, p->org);
+                                               // convert from a blood particle to a blood decal
+                                               VectorCopy(trace.endpos, p->org);
+                                               VectorCopy(trace.plane.normal, p->vel);
+                                               VectorAdd(p->org, p->vel, p->org);
 #ifndef WORKINGLQUAKE
                                                if (cl_stainmaps.integer)
-                                                       R_Stain(v, 32, 32, 16, 16, p->alpha * p->size * (1.0f / 40.0f), 192, 48, 48, p->alpha * p->size * (1.0f / 40.0f));
+                                                       R_Stain(p->org, 32, 32, 16, 16, p->alpha * p->size * (1.0f / 40.0f), 192, 48, 48, p->alpha * p->size * (1.0f / 40.0f));
 #endif
                                                if (!cl_decals.integer)
                                                {
@@ -1346,19 +1354,15 @@ void CL_MoveParticles (void)
                                                }
 
                                                p->type = particletype + pt_decal;
-                                               // convert from a blood particle to a blood decal
                                                p->texnum = tex_blooddecal[rand()&7];
 #ifndef WORKINGLQUAKE
                                                p->owner = hitent;
                                                p->ownermodel = cl_entities[hitent].render.model;
-                                               Matrix4x4_Transform(&cl_entities[hitent].render.inversematrix, v, p->relativeorigin);
-                                               Matrix4x4_Transform3x3(&cl_entities[hitent].render.inversematrix, normal, p->relativedirection);
-                                               VectorAdd(p->relativeorigin, p->relativedirection, p->relativeorigin);
+                                               Matrix4x4_Transform(&cl_entities[hitent].render.inversematrix, p->org, p->relativeorigin);
+                                               Matrix4x4_Transform3x3(&cl_entities[hitent].render.inversematrix, p->vel, p->relativedirection);
 #endif
                                                p->time2 = cl.time;
                                                p->alphafade = 0;
-                                               VectorCopy(normal, p->vel);
-                                               VectorAdd(p->org, normal, p->org);
                                                p->bounce = 0;
                                                p->friction = 0;
                                                p->gravity = 0;
@@ -1367,9 +1371,10 @@ void CL_MoveParticles (void)
                                }
                                else
                                {
-                                       if (CL_TraceLine(oldorg, p->org, v, normal, true, NULL, SUPERCONTENTS_SOLID) < 1)
+                                       trace = CL_TraceBox(oldorg, vec3_origin, vec3_origin, p->org, true, NULL, SUPERCONTENTS_SOLID, false);
+                                       if (trace.fraction < 1)
                                        {
-                                               VectorCopy(v, p->org);
+                                               VectorCopy(trace.endpos, p->org);
                                                if (p->bounce < 0)
                                                {
                                                        p->type = NULL;
@@ -1377,8 +1382,8 @@ void CL_MoveParticles (void)
                                                }
                                                else
                                                {
-                                                       dist = DotProduct(p->vel, normal) * -p->bounce;
-                                                       VectorMA(p->vel, dist, normal, p->vel);
+                                                       dist = DotProduct(p->vel, trace.plane.normal) * -p->bounce;
+                                                       VectorMA(p->vel, dist, trace.plane.normal, p->vel);
                                                        if (DotProduct(p->vel, p->vel) < 0.03)
                                                                VectorClear(p->vel);
                                                }
index 5164516..425f4a8 100644 (file)
--- a/client.h
+++ b/client.h
@@ -455,6 +455,16 @@ client_static_t;
 
 extern client_static_t cls;
 
+typedef struct client_movementqueue_s
+{
+       double time;
+       float viewangles[3];
+       float move[3];
+       qboolean jump;
+       qboolean crouch;
+}
+client_movementqueue_t;
+
 //
 // the client_state_t structure is wiped completely at every
 // server signon
@@ -510,6 +520,16 @@ typedef struct
        // update by server, can be used by mods for zooming
        vec_t mviewzoom[2], viewzoom;
 
+       // client movement simulation
+       // these fields are only updated by CL_ClientMovement (called by CL_SendMove after parsing each network packet)
+       qboolean movement;
+       // simulated origin
+       vec3_t movement_origin;
+       vec3_t movement_oldorigin;
+       // queue of proposed moves
+       int movement_numqueue;
+       client_movementqueue_t movement_queue[256];
+
 // pitch drifting vars
        float idealpitch;
        float pitchvel;
@@ -636,6 +656,11 @@ extern cvar_t cl_stainmaps_clearonload;
 
 extern cvar_t cl_prydoncursor;
 
+extern vec3_t cl_playerstandmins;
+extern vec3_t cl_playerstandmaxs;
+extern vec3_t cl_playercrouchmins;
+extern vec3_t cl_playercrouchmaxs;
+
 // these are updated by CL_ClearState
 extern int cl_num_entities;
 extern int cl_num_static_entities;
index 9e8200f..368c1c3 100644 (file)
@@ -30,8 +30,8 @@ cvar_t r_mipskins = {CVAR_SAVE, "r_mipskins", "0"};
 
 model_t *loadmodel;
 
-// LordHavoc: increased from 512 to 2048
-#define        MAX_MOD_KNOWN   2048
+// LordHavoc: was 512
+#define MAX_MOD_KNOWN (MAX_MODELS + 256)
 static model_t mod_known[MAX_MOD_KNOWN];
 
 rtexturepool_t *mod_shared_texturepool;
index b1f6992..5f64acd 100755 (executable)
--- a/netconn.c
+++ b/netconn.c
@@ -1167,13 +1167,15 @@ void NetConn_ClientFrame(void)
        if (cls.connect_trying && cls.connect_nextsendtime < realtime)
        {
                if (cls.connect_remainingtries == 0)
+                       M_Update_Return_Reason("Connect: Waiting 10 seconds for reply");
+               cls.connect_nextsendtime = realtime + 1;
+               cls.connect_remainingtries--;
+               if (cls.connect_remainingtries <= -10)
                {
                        cls.connect_trying = false;
                        M_Update_Return_Reason("Connect: Failed");
                        return;
                }
-               cls.connect_nextsendtime = realtime + 1;
-               cls.connect_remainingtries--;
                // try challenge first (newer server)
                NetConn_WriteString(cls.connect_mysocket, "\377\377\377\377getchallenge", &cls.connect_address);
                // then try netquake as a fallback (old server, or netquake)
index 20e5d63..0f73611 100644 (file)
@@ -1480,7 +1480,7 @@ void EntityState5_WriteUpdate(int number, const entity_state_t *s, int changedbi
        else
        {
                bits = changedbits;
-               if ((bits & E5_ORIGIN) && (s->origin[0] < -4096 || s->origin[0] >= 4096 || s->origin[1] < -4096 || s->origin[1] >= 4096 || s->origin[2] < -4096 || s->origin[2] >= 4096))
+               if ((bits & E5_ORIGIN) && (!(s->flags & RENDER_LOWPRECISION) || s->origin[0] < -4096 || s->origin[0] >= 4096 || s->origin[1] < -4096 || s->origin[1] >= 4096 || s->origin[2] < -4096 || s->origin[2] >= 4096))
                        bits |= E5_ORIGIN32;
                if ((bits & E5_ANGLES) && !(s->flags & RENDER_LOWPRECISION))
                        bits |= E5_ANGLES16;
index 8bb73b4..1af4627 100644 (file)
@@ -62,6 +62,7 @@ void R_DrawWorldCrosshair(void)
        vec3_t v1, v2, spriteorigin;
        vec_t spritescale;
        vec4_t color;
+       trace_t trace;
        if (r_letterbox.value)
                return;
        if (crosshair_static.integer)
@@ -84,7 +85,9 @@ void R_DrawWorldCrosshair(void)
        AngleVectors(cl.viewangles, v2, NULL, NULL);
        //VectorCopy(r_vieworigin, v1);
        VectorMA(v1, 8192, v2, v2);
-       spritescale = CL_TraceLine(v1, v2, spriteorigin, NULL, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY) * (8192.0f / 40.0f) * crosshair_size.value;
+       trace = CL_TraceBox(v1, vec3_origin, vec3_origin, v2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, false);
+       spritescale = trace.fraction * (8192.0f / 40.0f) * crosshair_size.value;
+       VectorCopy(trace.endpos, spriteorigin);
 
        // draw the sprite
        R_DrawSprite(GL_SRC_ALPHA, GL_ONE, pic->tex, true, spriteorigin, r_viewright, r_viewup, spritescale, -spritescale, -spritescale, spritescale, color[0], color[1], color[2], color[3]);
index 800c910..74d63bf 100644 (file)
@@ -145,8 +145,8 @@ void R_NewExplosion(vec3_t org)
 {
        int i, j;
        float dist, n;
-       vec3_t impact;
        explosion_t *e;
+       trace_t trace;
        qbyte noise[EXPLOSIONGRID*EXPLOSIONGRID];
        fractalnoisequick(noise, EXPLOSIONGRID, 4); // adjust noise grid size according to explosion
        for (i = 0, e = explosion;i < MAX_EXPLOSIONS;i++, e++)
@@ -171,8 +171,8 @@ void R_NewExplosion(vec3_t org)
                                // clip start origin
                                if (e->clipping)
                                {
-                                       CL_TraceLine(e->origin, e->vert[j], impact, NULL, true, NULL, SUPERCONTENTS_SOLID);
-                                       VectorCopy(impact, e->vert[i]);
+                                       trace = CL_TraceBox(e->origin, vec3_origin, vec3_origin, e->vert[j], true, NULL, SUPERCONTENTS_SOLID, false);
+                                       VectorCopy(trace.endpos, e->vert[i]);
                                }
                        }
                        break;
@@ -213,7 +213,8 @@ void R_DrawExplosionCallback(const void *calldata1, int calldata2)
 void R_MoveExplosion(explosion_t *e)
 {
        int i;
-       float dot, end[3], impact[3], normal[3], frametime;
+       float dot, end[3], frametime;
+       trace_t trace;
 
        frametime = cl.time - e->time;
        e->time = cl.time;
@@ -225,13 +226,14 @@ void R_MoveExplosion(explosion_t *e)
                        VectorMA(e->vert[i], frametime, e->vertvel[i], end);
                        if (e->clipping)
                        {
-                               if (CL_TraceLine(e->vert[i], end, impact, normal, true, NULL, SUPERCONTENTS_SOLID) < 1)
+                               trace = CL_TraceBox(e->vert[i], vec3_origin, vec3_origin, end, true, NULL, SUPERCONTENTS_SOLID, false);
+                               if (trace.fraction < 1)
                                {
                                        // clip velocity against the wall
-                                       dot = -DotProduct(e->vertvel[i], normal);
-                                       VectorMA(e->vertvel[i], dot, normal, e->vertvel[i]);
+                                       dot = -DotProduct(e->vertvel[i], trace.plane.normal);
+                                       VectorMA(e->vertvel[i], dot, trace.plane.normal, e->vertvel[i]);
                                }
-                               VectorCopy(impact, e->vert[i]);
+                               VectorCopy(trace.endpos, e->vert[i]);
                        }
                        else
                                VectorCopy(end, e->vert[i]);
index cebe80b..83d9630 100644 (file)
--- a/r_light.c
+++ b/r_light.c
@@ -138,7 +138,7 @@ void R_DrawCoronas(void)
        flag = r_rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
        for (lnum = 0, light = r_shadow_worldlightchain;light;light = light->next, lnum++)
        {
-               if ((light->flags & flag) && light->corona * r_coronas.value > 0 && (r_shadow_debuglight.integer < 0 || r_shadow_debuglight.integer == lnum) && (dist = (DotProduct(light->rtlight.shadoworigin, r_viewforward) - viewdist)) >= 24.0f && CL_TraceLine(light->rtlight.shadoworigin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1)
+               if ((light->flags & flag) && light->corona * r_coronas.value > 0 && (r_shadow_debuglight.integer < 0 || r_shadow_debuglight.integer == lnum) && (dist = (DotProduct(light->rtlight.shadoworigin, r_viewforward) - viewdist)) >= 24.0f && CL_TraceBox(light->rtlight.shadoworigin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1)
                {
                        cscale = light->rtlight.corona * r_coronas.value * 0.25f;
                        scale = light->rtlight.radius * light->rtlight.coronasizescale;
@@ -147,7 +147,7 @@ void R_DrawCoronas(void)
        }
        for (i = 0, light = r_dlight;i < r_numdlights;i++, light++)
        {
-               if ((light->flags & flag) && light->corona * r_coronas.value > 0 && (dist = (DotProduct(light->origin, r_viewforward) - viewdist)) >= 24.0f && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1)
+               if ((light->flags & flag) && light->corona * r_coronas.value > 0 && (dist = (DotProduct(light->origin, r_viewforward) - viewdist)) >= 24.0f && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1)
                {
                        cscale = light->corona * r_coronas.value * 0.25f;
                        scale = light->rtlight.radius * light->rtlight.coronasizescale;
@@ -196,7 +196,7 @@ void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffu
                        {
                                VectorSubtract (p, sl->origin, v);
                                f = ((1.0f / (DotProduct(v, v) * sl->falloff + sl->distbias)) - sl->subtract);
-                               if (f > 0 && CL_TraceLine(p, sl->origin, NULL, NULL, false, NULL, SUPERCONTENTS_SOLID) == 1)
+                               if (f > 0 && CL_TraceBox(p, vec3_origin, vec3_origin, sl->origin, false, NULL, SUPERCONTENTS_SOLID, false).fraction == 1)
                                {
                                        f *= d_lightstylevalue[sl->style] * (1.0f / 65536.0f);
                                        VectorMA(ambientcolor, f, sl->light, ambientcolor);
@@ -216,7 +216,7 @@ void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffu
                        light = r_dlight + i;
                        VectorSubtract(p, light->origin, v);
                        f = DotProduct(v, v);
-                       if (f < light->rtlight.lightmap_cullradius2 && CL_TraceLine(p, light->origin, NULL, NULL, false, NULL, SUPERCONTENTS_SOLID) == 1)
+                       if (f < light->rtlight.lightmap_cullradius2 && CL_TraceBox(p, vec3_origin, vec3_origin, light->origin, false, NULL, SUPERCONTENTS_SOLID, false).fraction == 1)
                        {
                                f = (1.0f / (f + LIGHTOFFSET)) - light->rtlight.lightmap_subtract;
                                VectorMA(ambientcolor, f, light->rtlight.lightmap_light, ambientcolor);
@@ -344,7 +344,7 @@ int R_LightModel(float *ambient4f, float *diffusecolor, float *diffusenormal, co
                        VectorSubtract (v, light->origin, v);
                        if (DotProduct(v, v) < light->rtlight.lightmap_cullradius2)
                        {
-                               if (CL_TraceLine(ent->origin, light->origin, NULL, NULL, false, NULL, SUPERCONTENTS_SOLID) != 1)
+                               if (CL_TraceBox(ent->origin, vec3_origin, vec3_origin, light->origin, false, NULL, SUPERCONTENTS_SOLID, false).fraction != 1)
                                        continue;
                                VectorSubtract (ent->origin, light->origin, v);
                                f = ((1.0f / (DotProduct(v, v) + LIGHTOFFSET)) - light->rtlight.lightmap_subtract);
@@ -483,7 +483,7 @@ void R_UpdateEntLights(entity_render_t *ent)
                ent->numentlights = 0;
                if (r_refdef.worldmodel)
                        for (i = 0, sl = r_refdef.worldmodel->brushq1.lights;i < r_refdef.worldmodel->brushq1.numlights && ent->numentlights < MAXENTLIGHTS;i++, sl++)
-                               if (CL_TraceLine(ent->origin, sl->origin, NULL, NULL, false, NULL, SUPERCONTENTS_SOLID) == 1)
+                               if (CL_TraceBox(ent->origin, vec3_origin, vec3_origin, sl->origin, false, NULL, SUPERCONTENTS_SOLID, false).fraction == 1)
                                        ent->entlights[ent->numentlights++] = i;
        }
        ent->entlightsframe = r_framecount;
index 08e2dc8..b8127bd 100644 (file)
@@ -3297,7 +3297,7 @@ void R_Shadow_SelectLightInView(void)
                if (rating >= 0.95)
                {
                        rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
-                       if (bestrating < rating && CL_TraceLine(light->origin, r_vieworigin, NULL, NULL, true, NULL, SUPERCONTENTS_SOLID) == 1.0f)
+                       if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_vieworigin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
                        {
                                bestrating = rating;
                                best = light;
@@ -3722,19 +3722,20 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
 
 void R_Shadow_SetCursorLocationForView(void)
 {
-       vec_t dist, push, frac;
-       vec3_t dest, endpos, normal;
+       vec_t dist, push;
+       vec3_t dest, endpos;
+       trace_t trace;
        VectorMA(r_vieworigin, r_editlights_cursordistance.value, r_viewforward, dest);
-       frac = CL_TraceLine(r_vieworigin, dest, endpos, normal, true, NULL, SUPERCONTENTS_SOLID);
-       if (frac < 1)
+       trace = CL_TraceBox(r_vieworigin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
+       if (trace.fraction < 1)
        {
-               dist = frac * r_editlights_cursordistance.value;
+               dist = trace.fraction * r_editlights_cursordistance.value;
                push = r_editlights_cursorpushback.value;
                if (push > dist)
                        push = dist;
                push = -push;
-               VectorMA(endpos, push, r_viewforward, endpos);
-               VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
+               VectorMA(trace.endpos, push, r_viewforward, endpos);
+               VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
        }
        r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
        r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
diff --git a/view.c b/view.c
index 36176d6..b1e2a98 100644 (file)
--- a/view.c
+++ b/view.c
@@ -313,6 +313,7 @@ void V_CalcRefdef (void)
        static float oldz;
        entity_t *ent;
        float vieworg[3], viewangles[3];
+       trace_t trace;
        Matrix4x4_CreateIdentity(&viewmodelmatrix);
        Matrix4x4_CreateIdentity(&r_refdef.viewentitymatrix);
        if (cls.state == ca_connected && cls.signon == SIGNONS)
@@ -352,7 +353,7 @@ void V_CalcRefdef (void)
                        if (chase_active.value)
                        {
                                // observing entity from third person
-                               vec_t camback, camup, dist, forward[3], stop[3], chase_dest[3], normal[3];
+                               vec_t camback, camup, dist, forward[3], chase_dest[3];
 
                                camback = bound(0, chase_back.value, 128);
                                if (chase_back.value != camback)
@@ -377,10 +378,8 @@ void V_CalcRefdef (void)
                                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;
-                               CL_TraceLine(vieworg, chase_dest, stop, normal, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY);
-                               vieworg[0] = stop[0] + forward[0] * 8 + normal[0] * 4;
-                               vieworg[1] = stop[1] + forward[1] * 8 + normal[1] * 4;
-                               vieworg[2] = stop[2] + forward[2] * 8 + normal[2] * 4;
+                               trace = CL_TraceBox(vieworg, vec3_origin, vec3_origin, chase_dest, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, false);
+                               VectorMAMAM(1, trace.endpos, 8, forward, 4, trace.plane.normal, vieworg);
                        }
                        else
                        {