X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=sv_phys.c;h=59c02e1e804403b2ecb503c717f6f8a41ead2791;hp=5b3e29653f76a7c31c9567895669012b10717737;hb=221bb70d6ec2aab6d29b5f5184f00e3636add70a;hpb=a4bc6f57b4b1b2e7e73ec3aa1b64d3366bcff97c diff --git a/sv_phys.c b/sv_phys.c index 5b3e2965..59c02e1e 100644 --- a/sv_phys.c +++ b/sv_phys.c @@ -48,6 +48,7 @@ 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 @@ -59,6 +60,7 @@ void SV_Phys_Init (void) Cvar_RegisterVariable(&sv_jumpstep); Cvar_RegisterVariable(&sv_wallfriction); Cvar_RegisterVariable(&sv_newflymove); + Cvar_RegisterVariable(&sv_freezenonclients); } /* @@ -84,7 +86,7 @@ void SV_CheckAllEnts (void) continue; if (SV_TestEntityPosition (check)) - Con_Printf ("entity in invalid position\n"); + Con_Print("entity in invalid position\n"); } } @@ -105,12 +107,12 @@ void SV_CheckVelocity (edict_t *ent) { if (IS_NAN(ent->v->velocity[i])) { - Con_Printf ("Got a NaN velocity on %s\n", PR_GetString(ent->v->classname)); + Con_Printf("Got a NaN velocity on %s\n", PR_GetString(ent->v->classname)); ent->v->velocity[i] = 0; } if (IS_NAN(ent->v->origin[i])) { - Con_Printf ("Got a NaN origin on %s\n", PR_GetString(ent->v->classname)); + Con_Printf("Got a NaN origin on %s\n", PR_GetString(ent->v->classname)); ent->v->origin[i] = 0; } } @@ -153,7 +155,7 @@ qboolean SV_RunThink (edict_t *ent) pr_global_struct->time = thinktime; 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"); + PR_ExecuteProgram (ent->v->think, "QC function self.think is missing"); return !ent->e->free; } @@ -176,14 +178,14 @@ void SV_Impact (edict_t *e1, edict_t *e2) { pr_global_struct->self = EDICT_TO_PROG(e1); pr_global_struct->other = EDICT_TO_PROG(e2); - PR_ExecuteProgram (e1->v->touch, ""); + PR_ExecuteProgram (e1->v->touch, "QC function self.touch is missing"); } if (e2->v->touch && e2->v->solid != SOLID_NOT) { pr_global_struct->self = EDICT_TO_PROG(e2); pr_global_struct->other = EDICT_TO_PROG(e1); - PR_ExecuteProgram (e2->v->touch, ""); + PR_ExecuteProgram (e2->v->touch, "QC function self.touch is missing"); } pr_global_struct->self = old_self; @@ -230,220 +232,185 @@ If stepnormal is not NULL, the plane normal of any vertical wall hit will be sto #define MAX_CLIP_PLANES 20 int SV_FlyMove (edict_t *ent, float time, float *stepnormal) { - if (sv_newflymove.integer) + int blocked, bumpcount; + edict_t *hackongroundentity; + 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; + hackongroundentity = NULL; + for (bumpcount = 0;bumpcount < 8;bumpcount++) { - int blocked, impact, bumpcount; - vec3_t end, primal_velocity; - trace_t trace; - - blocked = 0; - VectorCopy (ent->v->velocity, primal_velocity); + if (!ent->v->velocity[0] && !ent->v->velocity[1] && !ent->v->velocity[2]) + break; - for (bumpcount = 0;bumpcount < 4;bumpcount++) + VectorMA(ent->v->origin, time_left, ent->v->velocity, end); + trace = SV_Move(ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent); +#if 0 + //if (trace.fraction < 0.002) { - if (!ent->v->velocity[0] && !ent->v->velocity[1] && !ent->v->velocity[2]) - break; - - 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]); -#ifdef COLLISIONPARANOID +#if 1 + vec3_t start; + trace_t testtrace; + VectorCopy(ent->v->origin, start); + start[2] += 3;//0.03125; + VectorMA(ent->v->origin, time_left, ent->v->velocity, end); + end[2] += 3;//0.03125; + testtrace = SV_Move(start, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent); + if (trace.fraction < testtrace.fraction && !testtrace.startsolid && (testtrace.fraction == 1 || DotProduct(trace.plane.normal, ent->v->velocity) < DotProduct(testtrace.plane.normal, ent->v->velocity))) { - int endstuck; - vec3_t temp; - VectorCopy(trace.endpos, temp); - endstuck = SV_Move(temp, ent->v->mins, ent->v->maxs, temp, MOVE_WORLDONLY, ent).startsolid; - Con_Printf("%s{%i:%f %f %f:%f %f %f:%f:%f %f %f%s%s}\n", (trace.startsolid || endstuck) ? "\002" : "", bumpcount, ent->v->origin[0], ent->v->origin[1], ent->v->origin[2], end[0] - ent->v->origin[0], end[1] - ent->v->origin[1], end[2] - ent->v->origin[2], trace.fraction, trace.endpos[0] - ent->v->origin[0], trace.endpos[1] - ent->v->origin[1], trace.endpos[2] - ent->v->origin[2], trace.startsolid ? " startstuck" : "", endstuck ? " endstuck" : ""); - //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]); - if (endstuck) - Cbuf_AddText("disconnect\n"); + Con_Printf("got further (new %f > old %f)\n", testtrace.fraction, trace.fraction); + trace = testtrace; } #endif - - /* - 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.001) +#if 0 + //j = -1; + for (i = 0;i < numplanes;i++) { - // actually covered some distance - VectorCopy (trace.endpos, ent->v->origin); - } - - // 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 + VectorCopy(ent->v->origin, start); + VectorMA(ent->v->origin, time_left, ent->v->velocity, end); + VectorMA(start, 3, planes[i], start); + VectorMA(end, 3, planes[i], end); + testtrace = SV_Move(start, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent); + if (trace.fraction < testtrace.fraction) { - ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND; - impact = true; + trace = testtrace; + VectorCopy(start, ent->v->origin); + //j = i; } } - 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 (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 *= 1 - trace.fraction; - - ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1); + //if (j >= 0) + // VectorAdd(ent->v->origin, planes[j], start); +#endif } +#endif - return blocked; - } - else - { - 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; - - time_left = time; +#if 0 + Con_Printf("entity %i bump %i: velocity %f %f %f trace %f", ent - sv.edicts, bumpcount, ent->v->velocity[0], ent->v->velocity[1], ent->v->velocity[2], trace.fraction); + if (trace.fraction < 1) + Con_Printf(" : %f %f %f", trace.plane.normal[0], trace.plane.normal[1], trace.plane.normal[2]); + Con_Print("\n"); +#endif - for (bumpcount=0 ; bumpcountv->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]; - - 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.fraction > 0) - { - // actually covered some distance - VectorCopy (trace.endpos, ent->v->origin); - VectorCopy (ent->v->velocity, original_velocity); - numplanes = 0; - } + // 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; + } + */ - // break if it moved the entire distance - if (trace.fraction == 1) - break; + // break if it moved the entire distance + if (trace.fraction == 1) + { + VectorCopy(trace.endpos, ent->v->origin); + 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; - } - } + 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 (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->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 (stepnormal) - VectorCopy(trace.plane.normal, stepnormal); - } + 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); + if (trace.fraction >= 0.001) + { + // actually covered some distance + VectorCopy(trace.endpos, ent->v->origin); + VectorCopy(ent->v->velocity, original_velocity); + numplanes = 0; + } - // break if removed by the impact function - if (ent->e->free) - break; - } + // 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; + time_left *= 1 - trace.fraction; - // clipped to another plane - if (numplanes >= MAX_CLIP_PLANES) - { - // this shouldn't really happen - VectorClear(ent->v->velocity); - return 3; - } + // clipped to another plane + if (numplanes >= MAX_CLIP_PLANES) + { + // this shouldn't really happen + VectorClear(ent->v->velocity); + blocked = 3; + break; + } - VectorCopy (trace.plane.normal, planes[numplanes]); - numplanes++; + /* + for (i = 0;i < numplanes;i++) + if (DotProduct(trace.plane.normal, planes[i]) > 0.99) + break; + if (i < numplanes) + { + VectorAdd(ent->v->velocity, trace.plane.normal, ent->v->velocity); + continue; + } + */ + VectorCopy(trace.plane.normal, planes[numplanes]); + numplanes++; + + if (sv_newflymove.integer) + ClipVelocity(ent->v->velocity, trace.plane.normal, ent->v->velocity, 1); + else + { // modify original_velocity so it parallels all of the clip planes - for (i=0 ; iv->velocity); + VectorCopy(new_velocity, ent->v->velocity); } else { @@ -459,28 +426,67 @@ int SV_FlyMove (edict_t *ent, float time, float *stepnormal) if (numplanes != 2) { VectorClear(ent->v->velocity); - return 7; + blocked = 7; + break; } - CrossProduct (planes[0], planes[1], dir); + 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); + 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; - } + // 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]); - return blocked; + /* + // 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; } +int SV_SetOnGround (edict_t *ent) +{ + vec3_t end; + trace_t trace; + if ((int)ent->v->flags & FL_ONGROUND) + return 1; + VectorSet(end, ent->v->origin[0], ent->v->origin[1], ent->v->origin[2] - 1); + trace = SV_Move(ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent); + if (trace.fraction < 1 && trace.plane.normal[2] >= 0.7) + { + ent->v->flags = (int)ent->v->flags | FL_ONGROUND; + ent->v->groundentity = EDICT_TO_PROG(trace.ent); + return 1; + } + return 0; +} /* ============ @@ -517,27 +523,27 @@ SV_PushEntity Does not change the entities velocity at all ============ */ -trace_t SV_PushEntity (edict_t *ent, vec3_t push, vec3_t pushangles) +trace_t SV_PushEntity (edict_t *ent, vec3_t push) { + int type; trace_t trace; vec3_t end; VectorAdd (ent->v->origin, push, end); if (ent->v->movetype == MOVETYPE_FLYMISSILE) - trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_MISSILE, ent); + type = MOVE_MISSILE; else if (ent->v->solid == SOLID_TRIGGER || ent->v->solid == SOLID_NOT) - // only clip against bmodels - trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NOMONSTERS, ent); + type = MOVE_NOMONSTERS; // only clip against bmodels else - trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent); + type = MOVE_NORMAL; + + trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, type, ent); VectorCopy (trace.endpos, ent->v->origin); - // FIXME: turn players specially - ent->v->angles[1] += trace.fraction * pushangles[1]; SV_LinkEdict (ent, true); - if (trace.fraction < 1 && trace.ent && (!((int)ent->v->flags & FL_ONGROUND) || ent->v->groundentity != EDICT_TO_PROG(trace.ent))) + if (trace.ent && (!((int)ent->v->flags & FL_ONGROUND) || ent->v->groundentity != EDICT_TO_PROG(trace.ent))) SV_Impact (ent, trace.ent); return trace; } @@ -557,9 +563,17 @@ void SV_PushMove (edict_t *pusher, float movetime) float savesolid, movetime2, pushltime; vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org, org2; int num_moved; + int numcheckentities; + static edict_t *checkentities[MAX_EDICTS]; 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) { // LordHavoc: valid pusher types @@ -573,20 +587,22 @@ 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; + Con_Printf("SV_PushMove: unrecognized solid type %f\n", pusher->v->solid); return; } index = (int) pusher->v->modelindex; if (index < 1 || index >= MAX_MODELS) - Host_Error("SV_PushMove: invalid modelindex %f\n", pusher->v->modelindex); + { + Con_Printf("SV_PushMove: invalid modelindex %f\n", pusher->v->modelindex); + return; + } pushermodel = sv.models[index]; movetime2 = movetime; @@ -659,34 +675,24 @@ void SV_PushMove (edict_t *pusher, float movetime) // see if any solid entities are inside the final position num_moved = 0; - check = NEXT_EDICT(sv.edicts); - for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check)) + + numcheckentities = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, checkentities); + for (e = 1;e < numcheckentities;e++) { - if (check->e->free) - continue; + check = checkentities[e]; 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 if (!(((int)check->v->flags & FL_ONGROUND) && PROG_TO_EDICT(check->v->groundentity) == pusher)) - { - if (check->v->absmin[0] >= maxs[0] - || check->v->absmax[0] <= mins[0] - || check->v->absmin[1] >= maxs[1] - || check->v->absmax[1] <= mins[1] - || check->v->absmin[2] >= maxs[2] - || check->v->absmax[2] <= mins[2]) + if (!SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid) continue; - trace = SV_ClipMoveToEntity (pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin); - if (!trace.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); @@ -708,18 +714,20 @@ void SV_PushMove (edict_t *pusher, float movetime) // try moving the contacted entity pusher->v->solid = SOLID_NOT; - trace = SV_PushEntity (check, move, moveangle); + trace = SV_PushEntity (check, move); + // FIXME: turn players specially + check->v->angles[1] += trace.fraction * moveangle[1]; 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); 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 @@ -753,12 +761,15 @@ void SV_PushMove (edict_t *pusher, float movetime) { pr_global_struct->self = EDICT_TO_PROG(pusher); pr_global_struct->other = EDICT_TO_PROG(check); - PR_ExecuteProgram (pusher->v->blocked, ""); + PR_ExecuteProgram (pusher->v->blocked, "QC function self.blocked is missing"); } - 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)); } /* @@ -793,7 +804,7 @@ void SV_Physics_Pusher (edict_t *ent) pr_global_struct->time = sv.time; 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"); + PR_ExecuteProgram (ent->v->think, "QC function self.think is missing"); } } @@ -829,7 +840,7 @@ void SV_CheckStuck (edict_t *ent) VectorCopy (ent->v->oldorigin, ent->v->origin); if (!SV_TestEntityPosition(ent)) { - Con_DPrintf ("Unstuck.\n"); + Con_DPrint("Unstuck.\n"); SV_LinkEdict (ent, true); return; } @@ -843,14 +854,14 @@ void SV_CheckStuck (edict_t *ent) ent->v->origin[2] = org[2] + z; if (!SV_TestEntityPosition(ent)) { - Con_DPrintf ("Unstuck.\n"); + Con_DPrint("Unstuck.\n"); SV_LinkEdict (ent, true); return; } } VectorCopy (org, ent->v->origin); - Con_DPrintf ("player is stuck.\n"); + Con_DPrint("player is stuck.\n"); } @@ -870,19 +881,17 @@ qboolean SV_CheckWater (edict_t *ent) ent->v->waterlevel = 0; ent->v->watertype = CONTENTS_EMPTY; - cont = SV_PointQ1Contents(point); - if (cont <= CONTENTS_WATER) + cont = SV_PointSuperContents(point); + if (cont & (SUPERCONTENTS_LIQUIDSMASK)) { - ent->v->watertype = cont; + ent->v->watertype = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, cont); ent->v->waterlevel = 1; point[2] = ent->v->origin[2] + (ent->v->mins[2] + ent->v->maxs[2])*0.5; - cont = SV_PointQ1Contents(point); - if (cont <= CONTENTS_WATER) + if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK)) { ent->v->waterlevel = 2; point[2] = ent->v->origin[2] + ent->v->view_ofs[2]; - cont = SV_PointQ1Contents(point); - if (cont <= CONTENTS_WATER) + if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK)) ent->v->waterlevel = 3; } } @@ -948,7 +957,7 @@ int SV_TryUnstick (edict_t *ent, vec3_t oldvel) case 7: dir[0] = -2; dir[1] = -2; break; } - SV_PushEntity (ent, dir, vec3_origin); + SV_PushEntity (ent, dir); // retry the original move ent->v->velocity[0] = oldvel[0]; @@ -958,7 +967,10 @@ int SV_TryUnstick (edict_t *ent, vec3_t oldvel) if (fabs(oldorg[1] - ent->v->origin[1]) > 4 || fabs(oldorg[0] - ent->v->origin[0]) > 4) + { + Con_DPrint("TryUnstick - success.\n"); return clip; + } // go back to the original pos and try again VectorCopy (oldorg, ent->v->origin); @@ -966,6 +978,7 @@ int SV_TryUnstick (edict_t *ent, vec3_t oldvel) // still not moving VectorClear (ent->v->velocity); + Con_DPrint("TryUnstick - failure.\n"); return 7; } @@ -978,8 +991,8 @@ Only used by players */ void SV_WalkMove (edict_t *ent) { - int clip, oldonground; - vec3_t upmove, downmove, oldorg, oldvel, nosteporg, nostepvel, stepnormal; + int clip, oldonground, originalmove_clip, originalmove_flags, originalmove_groundentity; + vec3_t upmove, downmove, start_origin, start_velocity, stepnormal, originalmove_origin, originalmove_velocity; trace_t downtrace; SV_CheckVelocity(ent); @@ -988,90 +1001,121 @@ void SV_WalkMove (edict_t *ent) oldonground = (int)ent->v->flags & FL_ONGROUND; ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND; - VectorCopy (ent->v->origin, oldorg); - VectorCopy (ent->v->velocity, oldvel); + VectorCopy (ent->v->origin, start_origin); + VectorCopy (ent->v->velocity, start_velocity); clip = SV_FlyMove (ent, sv.frametime, NULL); + SV_SetOnGround (ent); SV_CheckVelocity(ent); - // if move didn't block on a step, return - if ( !(clip & 2) ) + 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; + + if ((int)ent->v->flags & FL_WATERJUMP) return; - if (ent->v->movetype != MOVETYPE_FLY) + if (sv_nostep.integer) + return; + + // if move didn't block on a step, return + if (clip & 2) { - if (!oldonground && ent->v->waterlevel == 0 && !sv_jumpstep.integer) - // don't stair up while jumping + // if move was not trying to move into the step, return + if (fabs(start_velocity[0]) < 0.03125 && fabs(start_velocity[1]) < 0.03125) return; - if (ent->v->movetype != MOVETYPE_WALK) - // gibbed by a trigger - return; - } + if (ent->v->movetype != MOVETYPE_FLY) + { + // return if gibbed by a trigger + if (ent->v->movetype != MOVETYPE_WALK) + return; - SV_CheckVelocity(ent); + // only step up while jumping if that is enabled + if (!(sv_jumpstep.integer && sv_gameplayfix_stepwhilejumping.integer)) + if (!oldonground && ent->v->waterlevel == 0) + return; + } - if (sv_nostep.integer || (int)ent->v->flags & FL_WATERJUMP ) - return; + // try moving up and forward to go up a step + // back to start pos + VectorCopy (start_origin, ent->v->origin); + VectorCopy (start_velocity, ent->v->velocity); - VectorCopy (ent->v->origin, nosteporg); - VectorCopy (ent->v->velocity, nostepvel); + // move up + VectorClear (upmove); + upmove[2] = sv_stepheight.value; + // FIXME: don't link? + SV_PushEntity(ent, upmove); - // try moving up and forward to go up a step - // back to start pos - VectorCopy (oldorg, ent->v->origin); + // move forward + ent->v->velocity[2] = 0; + clip = SV_FlyMove (ent, sv.frametime, stepnormal); + ent->v->velocity[2] += start_velocity[2]; - VectorClear (upmove); - VectorClear (downmove); - upmove[2] = sv_stepheight.value; - downmove[2] = -sv_stepheight.value + oldvel[2]*sv.frametime; + SV_CheckVelocity(ent); - // move up - // FIXME: don't link? - 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, stepnormal); - ent->v->velocity[2] += oldvel[2]; - - // check for stuckness, possibly due to the limited precision of floats - // in the clipping hulls - 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); - - // extra friction based on view angle - if (clip & 2 && sv_wallfriction.integer) - SV_WallFriction (ent, stepnormal); + // check for stuckness, possibly due to the limited precision of floats + // in the clipping hulls + if (clip + && fabs(originalmove_origin[1] - ent->v->origin[1]) < 0.03125 + && fabs(originalmove_origin[0] - ent->v->origin[0]) < 0.03125) + { + //Con_Printf("wall\n"); + // 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; + } + + //Con_Printf("step - "); + + // extra friction based on view angle + if (clip & 2 && sv_wallfriction.integer) + SV_WallFriction (ent, stepnormal); + } + // skip out if stepdown is enabled, moving downward, not in water, and the move started onground and ended offground + else if (!(sv_gameplayfix_stepdown.integer && ent->v->waterlevel < 2 && start_velocity[2] < (1.0 / 32.0) && oldonground && !((int)ent->v->flags & FL_ONGROUND))) + return; // move down + VectorClear (downmove); + downmove[2] = -sv_stepheight.value + start_velocity[2]*sv.frametime; // FIXME: don't link? - downtrace = SV_PushEntity (ent, downmove, vec3_origin); + downtrace = SV_PushEntity (ent, downmove); - if (downtrace.plane.normal[2] > 0.7) + if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7) { - // LordHavoc: disabled this so you can walk on monsters/players + // LordHavoc: disabled this check so you can walk on monsters/players //if (ent->v->solid == SOLID_BSP) { + //Con_Printf("onground\n"); ent->v->flags = (int)ent->v->flags | FL_ONGROUND; ent->v->groundentity = EDICT_TO_PROG(downtrace.ent); } } else { + //Con_Printf("slope\n"); // if the push down didn't end up on good ground, use the move without // the step up. This happens near wall / slope combinations, and can // cause the player to hop up higher on a slope too steep to climb - VectorCopy (nosteporg, ent->v->origin); - VectorCopy (nostepvel, ent->v->velocity); + 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; } + SV_SetOnGround (ent); SV_CheckVelocity(ent); } @@ -1176,13 +1220,15 @@ void SV_Physics_Toss (edict_t *ent) vec3_t move; edict_t *groundentity; - // regular thinking - if (!SV_RunThink (ent)) - return; + // don't stick to ground if onground and moving upward + if (ent->v->velocity[2] >= (1.0 / 32.0) && ((int)ent->v->flags & FL_ONGROUND)) + ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND; // if onground, return without moving if ((int)ent->v->flags & FL_ONGROUND) { + if (!sv_gameplayfix_noairborncorpse.integer) + return; if (ent->v->groundentity == 0) return; // if ent was supported by a brush model on previous frame, @@ -1214,7 +1260,7 @@ void SV_Physics_Toss (edict_t *ent) // move origin VectorScale (ent->v->velocity, sv.frametime, move); - trace = SV_PushEntity (ent, move, vec3_origin); + trace = SV_PushEntity (ent, move); if (ent->e->free) return; @@ -1227,17 +1273,34 @@ 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) + if (sv_gameplayfix_grenadebouncedownslopes.integer) { - ent->v->flags = (int)ent->v->flags | FL_ONGROUND; - ent->v->groundentity = EDICT_TO_PROG(trace.ent); - VectorClear (ent->v->velocity); - VectorClear (ent->v->avelocity); + 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); + VectorClear (ent->v->velocity); + VectorClear (ent->v->avelocity); + } + else + ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND; } else - ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND; + { + if (trace.plane.normal[2] > 0.7 && ent->v->velocity[2] < 60) + { + ent->v->flags = (int)ent->v->flags | FL_ONGROUND; + ent->v->groundentity = EDICT_TO_PROG(trace.ent); + VectorClear (ent->v->velocity); + VectorClear (ent->v->avelocity); + } + else + ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND; + } } else { @@ -1279,6 +1342,10 @@ will fall if the floor is pulled out from under them. */ void SV_Physics_Step (edict_t *ent) { + // don't stick to ground if onground and moving upward + if (ent->v->velocity[2] >= (1.0 / 32.0) && ((int)ent->v->flags & FL_ONGROUND)) + ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND; + // freefall if not onground/fly/swim if (!((int)ent->v->flags & (FL_ONGROUND | FL_FLY | FL_SWIM))) { @@ -1287,7 +1354,7 @@ void SV_Physics_Step (edict_t *ent) SV_AddGravity(ent); SV_CheckVelocity(ent); SV_FlyMove(ent, sv.frametime, NULL); - SV_LinkEdict(ent, false); + SV_LinkEdict(ent, true); // just hit ground if (hitsound && (int)ent->v->flags & FL_ONGROUND) @@ -1310,8 +1377,9 @@ SV_Physics */ void SV_Physics (void) { - int i; + int i, newnum_edicts; edict_t *ent; + qbyte runmove[MAX_EDICTS]; // let the progs know that a new frame has started pr_global_struct->self = EDICT_TO_PROG(sv.edicts); @@ -1319,11 +1387,17 @@ void SV_Physics (void) pr_global_struct->time = sv.time; PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing"); + newnum_edicts = 0; + for (i = 0, ent = sv.edicts;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent)) + if ((runmove[i] = !ent->e->free)) + newnum_edicts = i + 1; + sv.num_edicts = max(svs.maxclients + 1, newnum_edicts); + // // treat each object in turn // - ent = sv.edicts; - for (i=0 ; ie->free) continue; @@ -1331,10 +1405,8 @@ void SV_Physics (void) if (pr_global_struct->force_retouch) SV_LinkEdict (ent, true); // force retouch even for stationary - if (i > 0 && i <= svs.maxclients) + if (i >= 1 && i <= svs.maxclients && svs.clients[i-1].spawned) { - if (!svs.clients[i-1].spawned) - continue; // connected slot // call standard client pre-think SV_CheckVelocity (ent); @@ -1343,11 +1415,14 @@ void SV_Physics (void) 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: @@ -1379,33 +1454,37 @@ 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_FLYMISSILE: - SV_Physics_Toss (ent); + // regular thinking + if (SV_RunThink (ent) && runmove[i]) + SV_Physics_Toss (ent); break; case MOVETYPE_FLY: - if (i > 0 && i <= svs.maxclients) + if (SV_RunThink (ent) && runmove[i]) { - if (SV_RunThink (ent)) + if (i > 0 && i <= svs.maxclients) { SV_CheckWater (ent); SV_WalkMove (ent); } + else + SV_Physics_Toss (ent); } - else - SV_Physics_Toss (ent); break; default: Host_Error ("SV_Physics: bad movetype %i", (int)ent->v->movetype); break; } - if (i > 0 && i <= svs.maxclients && !ent->e->free) + if (i >= 1 && i <= svs.maxclients && svs.clients[i-1].spawned) { SV_CheckVelocity (ent); @@ -1420,8 +1499,8 @@ void SV_Physics (void) } } - if (pr_global_struct->force_retouch) - pr_global_struct->force_retouch--; + if (pr_global_struct->force_retouch > 0) + pr_global_struct->force_retouch = max(0, pr_global_struct->force_retouch - 1); // LordHavoc: endframe support if (EndFrameQC) @@ -1429,10 +1508,11 @@ void SV_Physics (void) pr_global_struct->self = EDICT_TO_PROG(sv.edicts); pr_global_struct->other = EDICT_TO_PROG(sv.edicts); pr_global_struct->time = sv.time; - PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), ""); + PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "QC function EndFrame is missing"); } - sv.time += sv.frametime; + if (!sv_freezenonclients.integer) + sv.time += sv.frametime; } @@ -1473,9 +1553,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