X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=sv_phys.c;h=66eec8e2fe1fdd61094b74ff6597af0842b40d99;hb=e704ef9206641ea061bbedfcff48a929734371e8;hp=5ed7426f80ec359c2436c6d21d18c27319319d45;hpb=b29b9e54dee7965354aede860e187c6f6276a758;p=xonotic%2Fdarkplaces.git diff --git a/sv_phys.c b/sv_phys.c index 5ed7426f..66eec8e2 100644 --- a/sv_phys.c +++ b/sv_phys.c @@ -47,6 +47,8 @@ cvar_t sv_nostep = {CVAR_NOTIFY, "sv_nostep","0"}; cvar_t sv_stepheight = {CVAR_NOTIFY, "sv_stepheight", "18"}; cvar_t sv_jumpstep = {CVAR_NOTIFY, "sv_jumpstep", "1"}; cvar_t sv_wallfriction = {CVAR_NOTIFY, "sv_wallfriction", "1"}; +cvar_t sv_newflymove = {CVAR_NOTIFY, "sv_newflymove", "1"}; +cvar_t sv_freezenonclients = {CVAR_NOTIFY, "sv_freezenonclients", "0"}; #define MOVE_EPSILON 0.01 @@ -57,6 +59,8 @@ void SV_Phys_Init (void) Cvar_RegisterVariable(&sv_stepheight); Cvar_RegisterVariable(&sv_jumpstep); Cvar_RegisterVariable(&sv_wallfriction); + Cvar_RegisterVariable(&sv_newflymove); + Cvar_RegisterVariable(&sv_freezenonclients); } /* @@ -73,7 +77,7 @@ void SV_CheckAllEnts (void) check = NEXT_EDICT(sv.edicts); for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check)) { - if (check->free) + if (check->e->free) continue; if (check->v->movetype == MOVETYPE_PUSH || check->v->movetype == MOVETYPE_NONE @@ -152,7 +156,7 @@ qboolean SV_RunThink (edict_t *ent) pr_global_struct->self = EDICT_TO_PROG(ent); pr_global_struct->other = EDICT_TO_PROG(sv.edicts); PR_ExecuteProgram (ent->v->think, "NULL think function"); - return !ent->free; + return !ent->e->free; } /* @@ -198,30 +202,17 @@ returns the blocked flags (1 = floor, 2 = step / wall) ================== */ #define STOP_EPSILON 0.1 -int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce) +void ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce) { - int i, blocked; - float backoff, change; - - blocked = 0; - // flag if it's a floor - if (normal[2] > 0) - blocked |= 1; - // flag if it's a step - if (!normal[2]) - blocked |= 2; + int i; + float backoff; - backoff = DotProduct (in, normal) * overbounce; + backoff = -DotProduct (in, normal) * overbounce; + VectorMA(in, backoff, normal, out); for (i = 0;i < 3;i++) - { - change = normal[i] * backoff; - out[i] = in[i] - change; if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON) out[i] = 0; - } - - return blocked; } @@ -234,157 +225,292 @@ Returns the clipflags if the velocity was modified (hit something solid) 1 = floor 2 = wall / step 4 = dead stop -If steptrace is not NULL, the trace of any vertical wall hit will be stored +If stepnormal is not NULL, the plane normal of any vertical wall hit will be stored ============ */ // LordHavoc: increased from 5 to 20 #define MAX_CLIP_PLANES 20 -int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace) +int SV_FlyMove (edict_t *ent, float time, float *stepnormal) { - int i, j, blocked, impact, numplanes, bumpcount, numbumps; - float d, time_left; - vec3_t dir, end, planes[MAX_CLIP_PLANES], primal_velocity, original_velocity, new_velocity; - trace_t trace; - - numbumps = 4; - - blocked = 0; - VectorCopy (ent->v->velocity, original_velocity); - VectorCopy (ent->v->velocity, primal_velocity); - numplanes = 0; + int blocked, bumpcount; + edict_t *hackongroundentity; + hackongroundentity = NULL; + if (sv_newflymove.integer) + { + int impact; + vec3_t end, primal_velocity; + trace_t trace; - time_left = time; + blocked = 0; + VectorCopy (ent->v->velocity, primal_velocity); - for (bumpcount=0 ; bumpcountv->velocity[0] && !ent->v->velocity[1] && !ent->v->velocity[2]) - break; + for (bumpcount = 0;bumpcount < 8;bumpcount++) + { + //Con_Printf("entity %i bump %i: blocked %i velocity %f %f %f\n", ent - sv.edicts, bumpcount, blocked, ent->v->velocity[0], ent->v->velocity[1], ent->v->velocity[2]); + if (!ent->v->velocity[0] && !ent->v->velocity[1] && !ent->v->velocity[2]) + break; - for (i=0 ; i<3 ; i++) - end[i] = ent->v->origin[i] + time_left * ent->v->velocity[i]; + VectorMA(ent->v->origin, time, ent->v->velocity, end); + trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent); + //Con_Printf("trace %f %f %f : %f : %f %f %f\n", trace.endpos[0], trace.endpos[1], trace.endpos[2], trace.fraction, trace.plane.normal[0], trace.plane.normal[1], trace.plane.normal[2]); - trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent); + /* + if (trace.startsolid) + { + // LordHavoc: note: this code is what makes entities stick in place if embedded in another object (which can be the world) + // entity is trapped in another solid + VectorClear(ent->v->velocity); + return 3; + } + */ - if (trace.allsolid) - { - // LordHavoc: note: this code is what makes entities stick in place if embedded in another object (which can be the world) - // entity is trapped in another solid - VectorClear(ent->v->velocity); - return 3; - } + if (trace.fraction >= 0.001) + { + // actually covered some distance + VectorCopy (trace.endpos, ent->v->origin); + } - if (trace.fraction > 0) - { - // actually covered some distance - VectorCopy (trace.endpos, ent->v->origin); - VectorCopy (ent->v->velocity, original_velocity); - numplanes = 0; - } + // break if it moved the entire distance + if (trace.fraction == 1) + break; - // break if it moved the entire distance - if (trace.fraction == 1) - break; + if (!trace.ent) + Host_Error ("SV_FlyMove: !trace.ent"); - if (!trace.ent) - Host_Error ("SV_FlyMove: !trace.ent"); + if ((int) ent->v->flags & FL_ONGROUND) + { + if (ent->v->groundentity == EDICT_TO_PROG(trace.ent)) + impact = false; + else + { + ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND; + impact = true; + } + } + else + impact = true; - if ((int) ent->v->flags & FL_ONGROUND) - { - if (ent->v->groundentity == EDICT_TO_PROG(trace.ent)) - impact = false; + if (trace.plane.normal[2]) + { + if (trace.plane.normal[2] > 0.7) + { + // floor + blocked |= 1; + ent->v->flags = (int)ent->v->flags | FL_ONGROUND; + ent->v->groundentity = EDICT_TO_PROG(trace.ent); + } + else if (trace.fraction < 0.001) + hackongroundentity = trace.ent; + } else { - ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND; - impact = true; + // step + blocked |= 2; + // save the trace for player extrafriction + if (stepnormal) + VectorCopy(trace.plane.normal, stepnormal); } - } - else - impact = true; - if (trace.plane.normal[2] > 0.7) - { - // floor - blocked |= 1; - ent->v->flags = (int)ent->v->flags | FL_ONGROUND; - ent->v->groundentity = EDICT_TO_PROG(trace.ent); - } - if (!trace.plane.normal[2]) - { - // step - blocked |= 2; - // save the trace for player extrafriction - if (steptrace) - *steptrace = trace; - } + // run the impact function + if (impact) + { + SV_Impact (ent, trace.ent); - // run the impact function - if (impact) - { - SV_Impact (ent, trace.ent); + // break if removed by the impact function + if (ent->e->free) + break; + } + + time *= 1 - trace.fraction; - // break if removed by the impact function - if (ent->free) + ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1); + + // if original velocity is against the original velocity, + // stop dead to avoid tiny occilations in sloping corners + if (DotProduct (ent->v->velocity, primal_velocity) < 0) + { + VectorClear(ent->v->velocity); break; + } } + } + else + { + int i, j, impact, numplanes; + float d, time_left; + vec3_t dir, end, planes[MAX_CLIP_PLANES], primal_velocity, original_velocity, new_velocity; + trace_t trace; + blocked = 0; + VectorCopy (ent->v->velocity, original_velocity); + VectorCopy (ent->v->velocity, primal_velocity); + numplanes = 0; - time_left -= time_left * trace.fraction; + time_left = time; - // clipped to another plane - if (numplanes >= MAX_CLIP_PLANES) + for (bumpcount = 0;bumpcount < 8;bumpcount++) { - // this shouldn't really happen - VectorClear(ent->v->velocity); - return 3; - } + //Con_Printf("entity %i bump %i: blocked %i velocity %f %f %f\n", ent - sv.edicts, bumpcount, blocked, ent->v->velocity[0], ent->v->velocity[1], ent->v->velocity[2]); + if (!ent->v->velocity[0] && !ent->v->velocity[1] && !ent->v->velocity[2]) + break; - VectorCopy (trace.plane.normal, planes[numplanes]); - numplanes++; + for (i=0 ; i<3 ; i++) + end[i] = ent->v->origin[i] + time_left * ent->v->velocity[i]; - // modify original_velocity so it parallels all of the clip planes - for (i=0 ; iv->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent); + + /* + if (trace.startsolid) + { + // LordHavoc: note: this code is what makes entities stick in place if embedded in another object (which can be the world) + // entity is trapped in another solid + VectorClear(ent->v->velocity); + return 3; + } + */ + + if (trace.fraction > 0) + { + // actually covered some distance + VectorCopy (trace.endpos, ent->v->origin); + VectorCopy (ent->v->velocity, original_velocity); + numplanes = 0; + } + + // break if it moved the entire distance + if (trace.fraction == 1) + break; + + if (!trace.ent) + Host_Error ("SV_FlyMove: !trace.ent"); + + if ((int) ent->v->flags & FL_ONGROUND) + { + if (ent->v->groundentity == EDICT_TO_PROG(trace.ent)) + impact = false; + else { - // not ok - if (DotProduct (new_velocity, planes[j]) < 0) - break; + ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND; + impact = true; } - if (j == numplanes) - break; - } + } + else + impact = true; - if (i != numplanes) - { - // go along this plane - VectorCopy (new_velocity, ent->v->velocity); - } - else - { - // go along the crease - if (numplanes != 2) + if (trace.plane.normal[2]) + { + if (trace.plane.normal[2] > 0.7) + { + // floor + blocked |= 1; + ent->v->flags = (int)ent->v->flags | FL_ONGROUND; + ent->v->groundentity = EDICT_TO_PROG(trace.ent); + } + else if (trace.fraction < 0.001) + hackongroundentity = trace.ent; + } + else + { + // step + blocked |= 2; + // save the trace for player extrafriction + if (stepnormal) + VectorCopy(trace.plane.normal, stepnormal); + } + + // run the impact function + if (impact) + { + SV_Impact (ent, trace.ent); + + // break if removed by the impact function + if (ent->e->free) + break; + } + + + time_left -= time_left * trace.fraction; + + // clipped to another plane + if (numplanes >= MAX_CLIP_PLANES) { + // this shouldn't really happen VectorClear(ent->v->velocity); - return 7; + blocked = 3; + break; } - CrossProduct (planes[0], planes[1], dir); - // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners - VectorNormalize(dir); - d = DotProduct (dir, ent->v->velocity); - VectorScale (dir, d, ent->v->velocity); - } - // if original velocity is against the original velocity, - // stop dead to avoid tiny occilations in sloping corners - if (DotProduct (ent->v->velocity, primal_velocity) <= 0) - { - VectorClear(ent->v->velocity); - return blocked; + VectorCopy (trace.plane.normal, planes[numplanes]); + numplanes++; + + // modify original_velocity so it parallels all of the clip planes + for (i=0 ; iv->velocity); + } + else + { + // go along the crease + if (numplanes != 2) + { + VectorClear(ent->v->velocity); + blocked = 7; + break; + } + CrossProduct (planes[0], planes[1], dir); + // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners + VectorNormalize(dir); + d = DotProduct (dir, ent->v->velocity); + VectorScale (dir, d, ent->v->velocity); + } + + // if original velocity is against the original velocity, + // stop dead to avoid tiny occilations in sloping corners + if (DotProduct (ent->v->velocity, primal_velocity) <= 0) + { + VectorClear(ent->v->velocity); + break; + } } } + //Con_Printf("entity %i final: blocked %i velocity %f %f %f\n", ent - sv.edicts, blocked, ent->v->velocity[0], ent->v->velocity[1], ent->v->velocity[2]); + + /* + // FIXME: this doesn't work well at all, find another solution + // if player is ontop of a non-onground floor and made no progress, + // set onground anyway (this tends to happen if standing in a wedge) + if (bumpcount == 8 && hackongroundentity) + { + blocked |= 1; + ent->v->flags = (int)ent->v->flags | FL_ONGROUND; + ent->v->groundentity = EDICT_TO_PROG(hackongroundentity); + } + */ + + /* + if ((blocked & 1) == 0 && bumpcount > 1) + { + // LordHavoc: fix the 'fall to your death in a wedge corner' glitch + // flag ONGROUND if there's ground under it + trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent); + } + */ return blocked; } @@ -465,7 +591,12 @@ void SV_PushMove (edict_t *pusher, float movetime) vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org, org2; int num_moved; model_t *pushermodel; - trace_t trace; + + if (!pusher->v->velocity[0] && !pusher->v->velocity[1] && !pusher->v->velocity[2] && !pusher->v->avelocity[0] && !pusher->v->avelocity[1] && !pusher->v->avelocity[2]) + { + pusher->v->ltime += movetime; + return; + } switch ((int) pusher->v->solid) { @@ -480,17 +611,15 @@ void SV_PushMove (edict_t *pusher, float movetime) case SOLID_TRIGGER: VectorMA (pusher->v->origin, movetime, pusher->v->velocity, pusher->v->origin); VectorMA (pusher->v->angles, movetime, pusher->v->avelocity, pusher->v->angles); + pusher->v->angles[0] -= 360.0 * floor(pusher->v->angles[0] * (1.0 / 360.0)); + pusher->v->angles[1] -= 360.0 * floor(pusher->v->angles[1] * (1.0 / 360.0)); + pusher->v->angles[2] -= 360.0 * floor(pusher->v->angles[2] * (1.0 / 360.0)); pusher->v->ltime += movetime; SV_LinkEdict (pusher, false); return; default: Host_Error("SV_PushMove: unrecognized solid type %f\n", pusher->v->solid); } - if (!pusher->v->velocity[0] && !pusher->v->velocity[1] && !pusher->v->velocity[2] && !pusher->v->avelocity[0] && !pusher->v->avelocity[1] && !pusher->v->avelocity[2]) - { - pusher->v->ltime += movetime; - return; - } index = (int) pusher->v->modelindex; if (index < 1 || index >= MAX_MODELS) Host_Error("SV_PushMove: invalid modelindex %f\n", pusher->v->modelindex); @@ -569,12 +698,13 @@ void SV_PushMove (edict_t *pusher, float movetime) check = NEXT_EDICT(sv.edicts); for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check)) { - if (check->free) + if (check->e->free) continue; if (check->v->movetype == MOVETYPE_PUSH || check->v->movetype == MOVETYPE_NONE || check->v->movetype == MOVETYPE_FOLLOW - || check->v->movetype == MOVETYPE_NOCLIP) + || check->v->movetype == MOVETYPE_NOCLIP + || check->v->movetype == MOVETYPE_FAKEPUSH) continue; // if the entity is standing on the pusher, it will definitely be moved @@ -588,12 +718,11 @@ void SV_PushMove (edict_t *pusher, float movetime) || check->v->absmax[2] <= mins[2]) continue; - trace = SV_ClipMoveToEntity (pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin); - if (!trace.startsolid) + if (!SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid) continue; } - if (forward[0] < 0.999f) // quick way to check if any rotation is used + if (forward[0] != 1) // quick way to check if any rotation is used { VectorSubtract (check->v->origin, pusher->v->origin, org); org2[0] = DotProduct (org, forward); @@ -609,24 +738,24 @@ void SV_PushMove (edict_t *pusher, float movetime) if (check->v->movetype != MOVETYPE_WALK) check->v->flags = (int)check->v->flags & ~FL_ONGROUND; - VectorCopy (check->v->origin, check->moved_from); - VectorCopy (check->v->angles, check->moved_fromangles); + VectorCopy (check->v->origin, check->e->moved_from); + VectorCopy (check->v->angles, check->e->moved_fromangles); sv.moved_edicts[num_moved++] = check; // try moving the contacted entity pusher->v->solid = SOLID_NOT; - trace = SV_PushEntity (check, move, moveangle); + SV_PushEntity (check, move, moveangle); pusher->v->solid = savesolid; // was SOLID_BSP // if it is still inside the pusher, block - if (SV_TestEntityPosition (check)) + if (SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid) { // try moving the contacted entity a tiny bit further to account for precision errors pusher->v->solid = SOLID_NOT; VectorScale(move, 0.1, move); - trace = SV_PushEntity (check, move, vec3_origin); + SV_PushEntity (check, move, vec3_origin); pusher->v->solid = savesolid; - if (SV_TestEntityPosition (check)) + if (SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid) { // still inside pusher, so it's really blocked @@ -650,8 +779,8 @@ void SV_PushMove (edict_t *pusher, float movetime) for (i = 0;i < num_moved;i++) { ed = sv.moved_edicts[i]; - VectorCopy (ed->moved_from, ed->v->origin); - VectorCopy (ed->moved_fromangles, ed->v->angles); + VectorCopy (ed->e->moved_from, ed->v->origin); + VectorCopy (ed->e->moved_fromangles, ed->v->angles); SV_LinkEdict (ed, false); } @@ -662,10 +791,13 @@ void SV_PushMove (edict_t *pusher, float movetime) pr_global_struct->other = EDICT_TO_PROG(check); PR_ExecuteProgram (pusher->v->blocked, ""); } - return; + break; } } } + pusher->v->angles[0] -= 360.0 * floor(pusher->v->angles[0] * (1.0 / 360.0)); + pusher->v->angles[1] -= 360.0 * floor(pusher->v->angles[1] * (1.0 / 360.0)); + pusher->v->angles[2] -= 360.0 * floor(pusher->v->angles[2] * (1.0 / 360.0)); } /* @@ -701,10 +833,7 @@ void SV_Physics_Pusher (edict_t *ent) pr_global_struct->self = EDICT_TO_PROG(ent); pr_global_struct->other = EDICT_TO_PROG(sv.edicts); PR_ExecuteProgram (ent->v->think, "NULL think function"); - if (ent->free) - return; } - } @@ -780,18 +909,18 @@ qboolean SV_CheckWater (edict_t *ent) ent->v->waterlevel = 0; ent->v->watertype = CONTENTS_EMPTY; - cont = Mod_PointContents(point, sv.worldmodel); + cont = SV_PointQ1Contents(point); if (cont <= CONTENTS_WATER) { ent->v->watertype = cont; ent->v->waterlevel = 1; point[2] = ent->v->origin[2] + (ent->v->mins[2] + ent->v->maxs[2])*0.5; - cont = Mod_PointContents(point, sv.worldmodel); + cont = SV_PointQ1Contents(point); if (cont <= CONTENTS_WATER) { ent->v->waterlevel = 2; point[2] = ent->v->origin[2] + ent->v->view_ofs[2]; - cont = Mod_PointContents(point, sv.worldmodel); + cont = SV_PointQ1Contents(point); if (cont <= CONTENTS_WATER) ent->v->waterlevel = 3; } @@ -806,25 +935,21 @@ SV_WallFriction ============ */ -void SV_WallFriction (edict_t *ent, trace_t *trace) +void SV_WallFriction (edict_t *ent, float *stepnormal) { float d, i; vec3_t forward, into, side; AngleVectors (ent->v->v_angle, forward, NULL, NULL); - d = DotProduct (trace->plane.normal, forward); - - d += 0.5; - if (d >= 0) - return; - - // cut the tangential velocity - i = DotProduct (trace->plane.normal, ent->v->velocity); - VectorScale (trace->plane.normal, i, into); - VectorSubtract (ent->v->velocity, into, side); - - ent->v->velocity[0] = side[0] * (1 + d); - ent->v->velocity[1] = side[1] * (1 + d); + if ((d = DotProduct (stepnormal, forward) + 0.5) < 0) + { + // cut the tangential velocity + i = DotProduct (stepnormal, ent->v->velocity); + VectorScale (stepnormal, i, into); + VectorSubtract (ent->v->velocity, into, side); + ent->v->velocity[0] = side[0] * (1 + d); + ent->v->velocity[1] = side[1] * (1 + d); + } } /* @@ -843,7 +968,6 @@ int SV_TryUnstick (edict_t *ent, vec3_t oldvel) { int i, clip; vec3_t oldorg, dir; - trace_t steptrace; VectorCopy (ent->v->origin, oldorg); VectorClear (dir); @@ -869,11 +993,14 @@ int SV_TryUnstick (edict_t *ent, vec3_t oldvel) ent->v->velocity[0] = oldvel[0]; ent->v->velocity[1] = oldvel[1]; ent->v->velocity[2] = 0; - clip = SV_FlyMove (ent, 0.1, &steptrace); + clip = SV_FlyMove (ent, 0.1, NULL); if (fabs(oldorg[1] - ent->v->origin[1]) > 4 || fabs(oldorg[0] - ent->v->origin[0]) > 4) + { + Con_DPrintf("TryUnstick - success.\n"); return clip; + } // go back to the original pos and try again VectorCopy (oldorg, ent->v->origin); @@ -881,6 +1008,7 @@ int SV_TryUnstick (edict_t *ent, vec3_t oldvel) // still not moving VectorClear (ent->v->velocity); + Con_DPrintf("TryUnstick - failure.\n"); return 7; } @@ -893,9 +1021,11 @@ Only used by players */ void SV_WalkMove (edict_t *ent) { - int clip, oldonground; - vec3_t upmove, downmove, oldorg, oldvel, nosteporg, nostepvel; - trace_t steptrace, downtrace; + int clip, oldonground, originalmove_clip, originalmove_flags, originalmove_groundentity; + vec3_t upmove, downmove, oldorg, oldvel, nosteporg, nostepvel, stepnormal, originalmove_origin, originalmove_velocity; + trace_t downtrace; + + SV_CheckVelocity(ent); // do a regular slide move unless it looks like you ran into a step oldonground = (int)ent->v->flags & FL_ONGROUND; @@ -904,12 +1034,23 @@ void SV_WalkMove (edict_t *ent) VectorCopy (ent->v->origin, oldorg); VectorCopy (ent->v->velocity, oldvel); - clip = SV_FlyMove (ent, sv.frametime, &steptrace); + clip = SV_FlyMove (ent, sv.frametime, NULL); + VectorCopy(ent->v->origin, originalmove_origin); + VectorCopy(ent->v->velocity, originalmove_velocity); + originalmove_clip = clip; + originalmove_flags = (int)ent->v->flags; + originalmove_groundentity = ent->v->groundentity; + + SV_CheckVelocity(ent); // if move didn't block on a step, return if ( !(clip & 2) ) return; + // if move was not trying to move into the step, return + if (fabs(oldvel[0]) < 0.03125 && fabs(oldvel[1]) < 0.03125) + return; + if (ent->v->movetype != MOVETYPE_FLY) { if (!oldonground && ent->v->waterlevel == 0 && !sv_jumpstep.integer) @@ -921,10 +1062,9 @@ void SV_WalkMove (edict_t *ent) return; } - if (sv_nostep.integer) - return; + SV_CheckVelocity(ent); - if ( (int)sv_player->v->flags & FL_WATERJUMP ) + if (sv_nostep.integer || (int)ent->v->flags & FL_WATERJUMP ) return; VectorCopy (ent->v->origin, nosteporg); @@ -941,13 +1081,13 @@ void SV_WalkMove (edict_t *ent) // move up // FIXME: don't link? - SV_PushEntity (ent, upmove, vec3_origin); + SV_PushEntity(ent, upmove, vec3_origin); // move forward ent->v->velocity[0] = oldvel[0]; ent->v->velocity[1] = oldvel[1]; ent->v->velocity[2] = 0; - clip = SV_FlyMove (ent, sv.frametime, &steptrace); + clip = SV_FlyMove (ent, sv.frametime, stepnormal); ent->v->velocity[2] += oldvel[2]; // check for stuckness, possibly due to the limited precision of floats @@ -955,12 +1095,21 @@ void SV_WalkMove (edict_t *ent) if (clip && fabs(oldorg[1] - ent->v->origin[1]) < 0.03125 && fabs(oldorg[0] - ent->v->origin[0]) < 0.03125) - // stepping up didn't make any progress - clip = SV_TryUnstick (ent, oldvel); + { + // stepping up didn't make any progress, revert to original move + VectorCopy(originalmove_origin, ent->v->origin); + VectorCopy(originalmove_velocity, ent->v->velocity); + clip = originalmove_clip; + ent->v->flags = originalmove_flags; + ent->v->groundentity = originalmove_groundentity; + // now try to unstick if needed + //clip = SV_TryUnstick (ent, oldvel); + return; + } // extra friction based on view angle if (clip & 2 && sv_wallfriction.integer) - SV_WallFriction (ent, &steptrace); + SV_WallFriction (ent, stepnormal); // move down // FIXME: don't link? @@ -983,77 +1132,8 @@ void SV_WalkMove (edict_t *ent) VectorCopy (nosteporg, ent->v->origin); VectorCopy (nostepvel, ent->v->velocity); } -} - - -/* -================ -SV_Physics_Client - -Player character actions -================ -*/ -void SV_Physics_Client (edict_t *ent, int num) -{ - if (!svs.clients[num-1].active) - return; // unconnected slot - - // call standard client pre-think - pr_global_struct->time = sv.time; - pr_global_struct->self = EDICT_TO_PROG(ent); - PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing"); - - // do a move - SV_CheckVelocity (ent); - - // decide which move function to call - switch ((int)ent->v->movetype) - { - case MOVETYPE_NONE: - if (!SV_RunThink (ent)) - return; - break; - - case MOVETYPE_WALK: - if (!SV_RunThink (ent)) - return; - if (!SV_CheckWater (ent) && ! ((int)ent->v->flags & FL_WATERJUMP) ) - SV_AddGravity (ent); - SV_CheckStuck (ent); - SV_WalkMove (ent); - break; - case MOVETYPE_TOSS: - case MOVETYPE_BOUNCE: - SV_Physics_Toss (ent); - break; - - case MOVETYPE_FLY: - if (!SV_RunThink (ent)) - return; - SV_CheckWater (ent); - //SV_FlyMove (ent, sv.frametime, NULL); - SV_WalkMove (ent); - break; - - case MOVETYPE_NOCLIP: - if (!SV_RunThink (ent)) - return; - SV_CheckWater (ent); - VectorMA (ent->v->origin, sv.frametime, ent->v->velocity, ent->v->origin); - VectorMA (ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles); - break; - - default: - Host_Error ("SV_Physics_client: bad movetype %i", (int)ent->v->movetype); - } - - // call standard player post-think - SV_LinkEdict (ent, true); - - pr_global_struct->time = sv.time; - pr_global_struct->self = EDICT_TO_PROG(ent); - PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing"); + SV_CheckVelocity(ent); } //============================================================================ @@ -1102,25 +1182,6 @@ void SV_Physics_Follow (edict_t *ent) SV_LinkEdict (ent, true); } -/* -============= -SV_Physics_Noclip - -A moving object that doesn't obey physics -============= -*/ -void SV_Physics_Noclip (edict_t *ent) -{ - // regular thinking - if (!SV_RunThink (ent)) - return; - - VectorMA (ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles); - VectorMA (ent->v->origin, sv.frametime, ent->v->velocity, ent->v->origin); - - SV_LinkEdict (ent, false); -} - /* ============================================================================== @@ -1138,7 +1199,7 @@ SV_CheckWaterTransition void SV_CheckWaterTransition (edict_t *ent) { int cont; - cont = Mod_PointContents(ent->v->origin, sv.worldmodel); + cont = SV_PointQ1Contents(ent->v->origin); if (!ent->v->watertype) { // just spawned here @@ -1147,23 +1208,19 @@ void SV_CheckWaterTransition (edict_t *ent) return; } + // check if the entity crossed into or out of water + if ((ent->v->watertype == CONTENTS_WATER || ent->v->watertype == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME)) + SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1); + if (cont <= CONTENTS_WATER) { - if (ent->v->watertype == CONTENTS_EMPTY && cont != CONTENTS_LAVA) - // just crossed into water - SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1); - ent->v->watertype = cont; ent->v->waterlevel = 1; } else { - if (ent->v->watertype != CONTENTS_EMPTY && ent->v->watertype != CONTENTS_LAVA) - // just crossed into water - SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1); - ent->v->watertype = CONTENTS_EMPTY; - ent->v->waterlevel = cont; + ent->v->waterlevel = 0; } } @@ -1187,7 +1244,6 @@ void SV_Physics_Toss (edict_t *ent) // if onground, return without moving if ((int)ent->v->flags & FL_ONGROUND) { - VectorClear(ent->v->velocity); if (ent->v->groundentity == 0) return; // if ent was supported by a brush model on previous frame, @@ -1195,18 +1251,18 @@ void SV_Physics_Toss (edict_t *ent) groundentity = PROG_TO_EDICT(ent->v->groundentity); if (groundentity->v->solid == SOLID_BSP) { - ent->suspendedinairflag = true; + ent->e->suspendedinairflag = true; return; } - else if (ent->suspendedinairflag && groundentity->free) + else if (ent->e->suspendedinairflag && groundentity->e->free) { // leave it suspended in the air ent->v->groundentity = 0; - ent->suspendedinairflag = false; + ent->e->suspendedinairflag = false; return; } } - ent->suspendedinairflag = false; + ent->e->suspendedinairflag = false; SV_CheckVelocity (ent); @@ -1220,7 +1276,7 @@ void SV_Physics_Toss (edict_t *ent) // move origin VectorScale (ent->v->velocity, sv.frametime, move); trace = SV_PushEntity (ent, move, vec3_origin); - if (ent->free) + if (ent->e->free) return; if (trace.fraction < 1) @@ -1232,9 +1288,11 @@ void SV_Physics_Toss (edict_t *ent) } else if (ent->v->movetype == MOVETYPE_BOUNCE) { + float d; ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.5); // LordHavoc: fixed grenades not bouncing when fired down a slope - if (trace.plane.normal[2] > 0.7 && DotProduct(trace.plane.normal, ent->v->velocity) < 60) + d = DotProduct(trace.plane.normal, ent->v->velocity); + if (trace.plane.normal[2] > 0.7 && fabs(d) < 60) { ent->v->flags = (int)ent->v->flags | FL_ONGROUND; ent->v->groundentity = EDICT_TO_PROG(trace.ent); @@ -1284,50 +1342,25 @@ will fall if the floor is pulled out from under them. */ void SV_Physics_Step (edict_t *ent) { - int flags, fall, hitsound; - - // freefall if not fly/swim - fall = true; - flags = (int)ent->v->flags; - if (flags & (FL_FLY | FL_SWIM)) + // freefall if not onground/fly/swim + if (!((int)ent->v->flags & (FL_ONGROUND | FL_FLY | FL_SWIM))) { - if (flags & FL_FLY) - fall = false; - else if ((flags & FL_SWIM) && Mod_PointContents(ent->v->origin, sv.worldmodel) != CONTENTS_EMPTY) - fall = false; - } - if (fall && (flags & FL_ONGROUND) && ent->v->groundentity == 0) - fall = false; - - if (fall) - { - if (ent->v->velocity[2] < sv_gravity.value*-0.1) - { - hitsound = true; - if (flags & FL_ONGROUND) - hitsound = false; - } - else - hitsound = false; + int hitsound = ent->v->velocity[2] < sv_gravity.value * -0.1; - SV_AddGravity (ent); - SV_CheckVelocity (ent); - SV_FlyMove (ent, sv.frametime, NULL); - SV_LinkEdict (ent, false); + SV_AddGravity(ent); + SV_CheckVelocity(ent); + SV_FlyMove(ent, sv.frametime, NULL); + SV_LinkEdict(ent, true); // just hit ground - if ((int)ent->v->flags & FL_ONGROUND) - { - VectorClear(ent->v->velocity); - if (hitsound) - SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1); - } + if (hitsound && (int)ent->v->flags & FL_ONGROUND) + SV_StartSound(ent, 0, "demon/dland2.wav", 255, 1); } // regular thinking - SV_RunThink (ent); + SV_RunThink(ent); - SV_CheckWaterTransition (ent); + SV_CheckWaterTransition(ent); } //============================================================================ @@ -1355,21 +1388,35 @@ void SV_Physics (void) ent = sv.edicts; for (i=0 ; ifree) + if (ent->e->free) continue; if (pr_global_struct->force_retouch) SV_LinkEdict (ent, true); // force retouch even for stationary - if (i > 0 && i <= svs.maxclients) + if (i <= svs.maxclients) { - SV_Physics_Client (ent, i); - continue; + if (i > 0) + { + if (!svs.clients[i-1].spawned) + continue; + // connected slot + // call standard client pre-think + SV_CheckVelocity (ent); + pr_global_struct->time = sv.time; + pr_global_struct->self = EDICT_TO_PROG(ent); + PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing"); + SV_CheckVelocity (ent); + } } + else if (sv_freezenonclients.integer) + continue; + // LordHavoc: merged client and normal entity physics switch ((int) ent->v->movetype) { case MOVETYPE_PUSH: + case MOVETYPE_FAKEPUSH: SV_Physics_Pusher (ent); break; case MOVETYPE_NONE: @@ -1381,12 +1428,19 @@ void SV_Physics (void) SV_Physics_Follow (ent); break; case MOVETYPE_NOCLIP: - SV_Physics_Noclip (ent); + if (SV_RunThink(ent)) + { + SV_CheckWater(ent); + VectorMA(ent->v->origin, sv.frametime, ent->v->velocity, ent->v->origin); + VectorMA(ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles); + } + // relink normal entities here, players always get relinked so don't relink twice + if (!(i > 0 && i <= svs.maxclients)) + SV_LinkEdict(ent, false); break; case MOVETYPE_STEP: SV_Physics_Step (ent); break; - // LordHavoc: added support for MOVETYPE_WALK on normal entities! :) case MOVETYPE_WALK: if (SV_RunThink (ent)) { @@ -1394,20 +1448,47 @@ void SV_Physics (void) SV_AddGravity (ent); SV_CheckStuck (ent); SV_WalkMove (ent); - SV_LinkEdict (ent, true); + // relink normal entities here, players always get relinked so don't relink twice + if (!(i > 0 && i <= svs.maxclients)) + SV_LinkEdict (ent, true); } break; case MOVETYPE_TOSS: case MOVETYPE_BOUNCE: case MOVETYPE_BOUNCEMISSILE: - case MOVETYPE_FLY: case MOVETYPE_FLYMISSILE: SV_Physics_Toss (ent); break; + case MOVETYPE_FLY: + if (i > 0 && i <= svs.maxclients) + { + if (SV_RunThink (ent)) + { + SV_CheckWater (ent); + SV_WalkMove (ent); + } + } + else + SV_Physics_Toss (ent); + break; default: Host_Error ("SV_Physics: bad movetype %i", (int)ent->v->movetype); break; } + + if (i <= svs.maxclients && i > 0 && !ent->e->free) + { + SV_CheckVelocity (ent); + + // call standard player post-think + SV_LinkEdict (ent, true); + + SV_CheckVelocity (ent); + + pr_global_struct->time = sv.time; + pr_global_struct->self = EDICT_TO_PROG(ent); + PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing"); + } } if (pr_global_struct->force_retouch) @@ -1422,7 +1503,8 @@ void SV_Physics (void) PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), ""); } - sv.time += sv.frametime; + if (!sv_freezenonclients.integer) + sv.time += sv.frametime; } @@ -1463,9 +1545,8 @@ trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore) trace = SV_Move (tent->v->origin, tent->v->mins, tent->v->maxs, end, MOVE_NORMAL, tent); VectorCopy (trace.endpos, tent->v->origin); - if (trace.fraction < 1 && trace.ent) - if (trace.ent != ignore) - break; + if (trace.fraction < 1 && trace.ent && trace.ent != ignore) + break; } tossent->v->solid = savesolid; trace.fraction = 0; // not relevant