X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=sv_phys.c;h=ee0239084cad2839d1bf1ad9229464e51337b3e8;hp=06e1f40ee68b52382bcce35cb07bc97847acee2c;hb=5bdc0879026939f551a3ff217064732d59731be2;hpb=2275e4d0cab079f4a0849ba55b8f92023d6f3eab diff --git a/sv_phys.c b/sv_phys.c index 06e1f40e..ee023908 100644 --- a/sv_phys.c +++ b/sv_phys.c @@ -8,7 +8,7 @@ of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -26,7 +26,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. pushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal objects when they move. -onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects +onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS @@ -39,16 +39,30 @@ solid_edge items only clip against bsp models. */ -cvar_t sv_friction = {"sv_friction","4",false,true}; -cvar_t sv_stopspeed = {"sv_stopspeed","100"}; -cvar_t sv_gravity = {"sv_gravity","800",false,true}; -cvar_t sv_maxvelocity = {"sv_maxvelocity","2000"}; -cvar_t sv_nostep = {"sv_nostep","0"}; +cvar_t sv_friction = {CVAR_NOTIFY, "sv_friction","4"}; +cvar_t sv_stopspeed = {CVAR_NOTIFY, "sv_stopspeed","100"}; +cvar_t sv_gravity = {CVAR_NOTIFY, "sv_gravity","800"}; +cvar_t sv_maxvelocity = {CVAR_NOTIFY, "sv_maxvelocity","2000"}; +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 void SV_Physics_Toss (edict_t *ent); +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); +} + /* ================ SV_CheckAllEnts @@ -56,23 +70,23 @@ SV_CheckAllEnts */ void SV_CheckAllEnts (void) { - int e; - edict_t *check; + int e; + edict_t *check; -// see if any solid entities are inside the final position + // see if any solid entities are inside the final position check = NEXT_EDICT(sv.edicts); - for (e=1 ; efree) + 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) + if (check->v->movetype == MOVETYPE_PUSH + || check->v->movetype == MOVETYPE_NONE + || check->v->movetype == MOVETYPE_FOLLOW + || check->v->movetype == MOVETYPE_NOCLIP) continue; if (SV_TestEntityPosition (check)) - Con_Printf ("entity in invalid position\n"); + Con_Print("entity in invalid position\n"); } } @@ -83,42 +97,34 @@ SV_CheckVelocity */ void SV_CheckVelocity (edict_t *ent) { - int i; - float wishspeed; + int i; + float wishspeed; // // bound velocity // for (i=0 ; i<3 ; i++) { - if (IS_NAN(ent->v.velocity[i])) + if (IS_NAN(ent->v->velocity[i])) { - Con_Printf ("Got a NaN velocity on %s\n", pr_strings + ent->v.classname); - ent->v.velocity[i] = 0; + 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])) + if (IS_NAN(ent->v->origin[i])) { - Con_Printf ("Got a NaN origin on %s\n", pr_strings + ent->v.classname); - ent->v.origin[i] = 0; + Con_Printf("Got a NaN origin on %s\n", PR_GetString(ent->v->classname)); + ent->v->origin[i] = 0; } - // LordHavoc: maxvelocity fix, see below -/* - if (ent->v.velocity[i] > sv_maxvelocity.value) - ent->v.velocity[i] = sv_maxvelocity.value; - else if (ent->v.velocity[i] < -sv_maxvelocity.value) - ent->v.velocity[i] = -sv_maxvelocity.value; -*/ } // LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster - wishspeed = DotProduct(ent->v.velocity, ent->v.velocity); + wishspeed = DotProduct(ent->v->velocity, ent->v->velocity); if (wishspeed > sv_maxvelocity.value * sv_maxvelocity.value) { wishspeed = sv_maxvelocity.value / sqrt(wishspeed); - ent->v.velocity[0] *= wishspeed; - ent->v.velocity[1] *= wishspeed; - ent->v.velocity[2] *= wishspeed; - wishspeed = sv_maxvelocity.value; + ent->v->velocity[0] *= wishspeed; + ent->v->velocity[1] *= wishspeed; + ent->v->velocity[2] *= wishspeed; } } @@ -134,22 +140,23 @@ Returns false if the entity removed itself. */ qboolean SV_RunThink (edict_t *ent) { - float thinktime; + float thinktime; - thinktime = ent->v.nextthink; - if (thinktime <= 0 || thinktime > sv.time + host_frametime) + thinktime = ent->v->nextthink; + if (thinktime <= 0 || thinktime > sv.time + sv.frametime) return true; - + + // don't let things stay in the past. + // it is possible to start that way by a trigger with a local time. if (thinktime < sv.time) - thinktime = sv.time; // don't let things stay in the past. - // it is possible to start that way - // by a trigger with a local time. - ent->v.nextthink = 0; + thinktime = sv.time; + + ent->v->nextthink = 0; 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); - return !ent->free; + PR_ExecuteProgram (ent->v->think, "QC function self.think is missing"); + return !ent->e->free; } /* @@ -161,24 +168,24 @@ Two entities have touched, so run their touch functions */ void SV_Impact (edict_t *e1, edict_t *e2) { - int old_self, old_other; - + int old_self, old_other; + old_self = pr_global_struct->self; old_other = pr_global_struct->other; - + pr_global_struct->time = sv.time; - if (e1->v.touch && e1->v.solid != SOLID_NOT) + if (e1->v->touch && e1->v->solid != SOLID_NOT) { 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) + + 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; @@ -194,31 +201,18 @@ Slide off of the impacting object 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) +#define STOP_EPSILON 0.1 +void ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce) { - float backoff; - float change; - int i, blocked; - - blocked = 0; - if (normal[2] > 0) - blocked |= 1; // floor - if (!normal[2]) - blocked |= 2; // step - - backoff = DotProduct (in, normal) * overbounce; + int i; + float backoff; - for (i=0 ; i<3 ; i++) - { - change = normal[i]*backoff; - out[i] = in[i] - change; + backoff = -DotProduct (in, normal) * overbounce; + VectorMA(in, backoff, normal, out); + + for (i = 0;i < 3;i++) if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON) out[i] = 0; - } - - return blocked; } @@ -231,145 +225,268 @@ 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 ============ */ -#define MAX_CLIP_PLANES 5 -int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace) +// LordHavoc: increased from 5 to 20 +#define MAX_CLIP_PLANES 20 +int SV_FlyMove (edict_t *ent, float time, float *stepnormal) { - int bumpcount, numbumps; - vec3_t dir; - float d; - int numplanes; - vec3_t planes[MAX_CLIP_PLANES]; - vec3_t primal_velocity, original_velocity, new_velocity; - int i, j; - trace_t trace; - vec3_t end; - float time_left; - int blocked; - - numbumps = 4; - + 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); + VectorCopy(ent->v->velocity, original_velocity); + VectorCopy(ent->v->velocity, primal_velocity); numplanes = 0; - time_left = time; - - for (bumpcount=0 ; bumpcountv.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_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 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))) + { + Con_Printf("got further (new %f > old %f)\n", testtrace.fraction, trace.fraction); + trace = testtrace; + } +#endif +#if 0 + //j = -1; + for (i = 0;i < numplanes;i++) + { + 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) + { + trace = testtrace; + VectorCopy(start, ent->v->origin); + //j = i; + } + } + //if (j >= 0) + // VectorAdd(ent->v->origin, planes[j], start); +#endif + } +#endif - trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent); +#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 - if (trace.allsolid) - { // entity is trapped in another solid - VectorCopy (vec3_origin, ent->v.velocity); + /* + 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; // moved the entire distance + { + VectorCopy(trace.endpos, ent->v->origin); + break; + } if (!trace.ent) - Host_Error ("SV_FlyMove: !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 (trace.plane.normal[2] > 0.7) + if (trace.plane.normal[2]) { - blocked |= 1; // floor - if (trace.ent->v.solid == SOLID_BSP) + if (trace.plane.normal[2] > 0.7) { - ent->v.flags = (int)ent->v.flags | FL_ONGROUND; - ent->v.groundentity = EDICT_TO_PROG(trace.ent); + // 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; } - if (!trace.plane.normal[2]) + else { - blocked |= 2; // step - if (steptrace) - *steptrace = trace; // save for player extrafriction + // step + blocked |= 2; + // save the trace for player extrafriction + if (stepnormal) + VectorCopy(trace.plane.normal, stepnormal); } -// -// run the impact function -// - SV_Impact (ent, trace.ent); - if (ent->free) - break; // removed by the impact function + if (trace.fraction >= 0.001) + { + // actually covered some distance + VectorCopy(trace.endpos, ent->v->origin); + VectorCopy(ent->v->velocity, original_velocity); + numplanes = 0; + } + + // 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 *= 1 - trace.fraction; - - time_left -= time_left * trace.fraction; - - // cliped to another plane + // clipped to another plane if (numplanes >= MAX_CLIP_PLANES) - { // this shouldn't really happen - VectorCopy (vec3_origin, ent->v.velocity); - return 3; + { + // this shouldn't really happen + VectorClear(ent->v->velocity); + blocked = 3; + break; } - VectorCopy (trace.plane.normal, planes[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++; -// -// modify original_velocity so it parallels all of the clip planes -// - for (i=0 ; iv->velocity, trace.plane.normal, ent->v->velocity, 1); + else { - ClipVelocity (original_velocity, planes[i], new_velocity, 1); - for (j=0 ; jv.velocity); - } - else - { // go along the crease - if (numplanes != 2) + if (j == numplanes) + break; + } + + if (i != numplanes) { -// Con_Printf ("clip velocity, numplanes == %i\n",numplanes); - VectorCopy (vec3_origin, ent->v.velocity); - return 7; + // go along this plane + VectorCopy(new_velocity, ent->v->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); } - CrossProduct (planes[0], planes[1], 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) + // 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) { - VectorCopy (vec3_origin, ent->v.velocity); - return blocked; + 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; } +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; +} /* ============ @@ -379,16 +496,15 @@ SV_AddGravity */ void SV_AddGravity (edict_t *ent) { - float ent_gravity; - - eval_t *val; + float ent_gravity; + eval_t *val; val = GETEDICTFIELDVALUE(ent, eval_gravity); if (val!=0 && val->_float) ent_gravity = val->_float; else ent_gravity = 1.0; - ent->v.velocity[2] -= ent_gravity * sv_gravity.value * host_frametime; + ent->v->velocity[2] -= ent_gravity * sv_gravity.value * sv.frametime; } @@ -409,27 +525,28 @@ Does not change the entities velocity at all */ trace_t SV_PushEntity (edict_t *ent, vec3_t push) { - 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); - 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); + int type; + trace_t trace; + vec3_t end; + + VectorAdd (ent->v->origin, push, end); + + if (ent->v->movetype == MOVETYPE_FLYMISSILE) + type = MOVE_MISSILE; + else if (ent->v->solid == SOLID_TRIGGER || ent->v->solid == SOLID_NOT) + type = MOVE_NOMONSTERS; // only clip against bmodels else - trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent); - - VectorCopy (trace.endpos, ent->v.origin); - SV_LinkEdict (ent, true); + type = MOVE_NORMAL; - if (trace.ent) - SV_Impact (ent, trace.ent); + trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, type, ent); + VectorCopy (trace.endpos, ent->v->origin); + SV_LinkEdict (ent, true); + + if (trace.ent && (!((int)ent->v->flags & FL_ONGROUND) || ent->v->groundentity != EDICT_TO_PROG(trace.ent))) + SV_Impact (ent, trace.ent); return trace; -} +} /* @@ -438,18 +555,24 @@ SV_PushMove ============ */ +trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end); void SV_PushMove (edict_t *pusher, float movetime) { - int i, e; - edict_t *check; - vec3_t mins, maxs, move; - vec3_t entorig, pushorig; - int num_moved; - edict_t *moved_edict[MAX_EDICTS]; - vec3_t moved_from[MAX_EDICTS]; - float savesolid; - - switch ((int) pusher->v.solid) + int i, e, index; + edict_t *check, *ed; + float savesolid, movetime2, pushltime; + 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) { // LordHavoc: valid pusher types case SOLID_BSP: @@ -460,279 +583,201 @@ void SV_PushMove (edict_t *pusher, float movetime) // LordHavoc: no collisions case SOLID_NOT: case SOLID_TRIGGER: - VectorMA (pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin); - pusher->v.ltime += movetime; + 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); + Con_Printf("SV_PushMove: unrecognized solid type %f\n", pusher->v->solid); + return; } - if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2]) + index = (int) pusher->v->modelindex; + if (index < 1 || index >= MAX_MODELS) { - pusher->v.ltime += movetime; + Con_Printf("SV_PushMove: invalid modelindex %f\n", pusher->v->modelindex); return; } + pushermodel = sv.models[index]; - for (i=0 ; i<3 ; i++) + movetime2 = movetime; + VectorScale(pusher->v->velocity, movetime2, move1); + VectorScale(pusher->v->avelocity, movetime2, moveangle); + if (moveangle[0] || moveangle[2]) { - move[i] = pusher->v.velocity[i] * movetime; - mins[i] = pusher->v.absmin[i] + move[i]; - maxs[i] = pusher->v.absmax[i] + move[i]; + for (i = 0;i < 3;i++) + { + if (move1[i] > 0) + { + mins[i] = pushermodel->rotatedmins[i] + pusher->v->origin[i] - 1; + maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + pusher->v->origin[i] + 1; + } + else + { + mins[i] = pushermodel->rotatedmins[i] + move1[i] + pusher->v->origin[i] - 1; + maxs[i] = pushermodel->rotatedmaxs[i] + pusher->v->origin[i] + 1; + } + } + } + else if (moveangle[1]) + { + for (i = 0;i < 3;i++) + { + if (move1[i] > 0) + { + mins[i] = pushermodel->yawmins[i] + pusher->v->origin[i] - 1; + maxs[i] = pushermodel->yawmaxs[i] + move1[i] + pusher->v->origin[i] + 1; + } + else + { + mins[i] = pushermodel->yawmins[i] + move1[i] + pusher->v->origin[i] - 1; + maxs[i] = pushermodel->yawmaxs[i] + pusher->v->origin[i] + 1; + } + } + } + else + { + for (i = 0;i < 3;i++) + { + if (move1[i] > 0) + { + mins[i] = pushermodel->normalmins[i] + pusher->v->origin[i] - 1; + maxs[i] = pushermodel->normalmaxs[i] + move1[i] + pusher->v->origin[i] + 1; + } + else + { + mins[i] = pushermodel->normalmins[i] + move1[i] + pusher->v->origin[i] - 1; + maxs[i] = pushermodel->normalmaxs[i] + pusher->v->origin[i] + 1; + } + } } - VectorCopy (pusher->v.origin, pushorig); - + VectorNegate (moveangle, a); + AngleVectorsFLU (a, forward, left, up); + + VectorCopy (pusher->v->origin, pushorig); + VectorCopy (pusher->v->angles, pushang); + pushltime = pusher->v->ltime; + // move the pusher to it's final position - VectorAdd (pusher->v.origin, move, pusher->v.origin); - pusher->v.ltime += movetime; + VectorMA (pusher->v->origin, movetime, pusher->v->velocity, pusher->v->origin); + VectorMA (pusher->v->angles, movetime, pusher->v->avelocity, pusher->v->angles); + pusher->v->ltime += movetime; SV_LinkEdict (pusher, false); + savesolid = pusher->v->solid; // 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)) { - 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) + 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_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 (!(((int)check->v->flags & FL_ONGROUND) && PROG_TO_EDICT(check->v->groundentity) == pusher)) { - if (check->v.absmin[0] >= maxs[0] - || check->v.absmin[1] >= maxs[1] - || check->v.absmin[2] >= maxs[2] - || check->v.absmax[0] <= mins[0] - || check->v.absmax[1] <= mins[1] - || check->v.absmax[2] <= mins[2]) + 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]) continue; - // see if the ent's bbox is inside the pusher's final position - if (!SV_TestEntityPosition (check)) + if (!SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid) continue; } + 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); + org2[1] = DotProduct (org, left); + org2[2] = DotProduct (org, up); + VectorSubtract (org2, org, move); + VectorAdd (move, move1, move); + } + else + VectorCopy (move1, move); + // remove the onground flag for non-players - if (check->v.movetype != MOVETYPE_WALK) - check->v.flags = (int)check->v.flags & ~FL_ONGROUND; - - VectorCopy (check->v.origin, entorig); - VectorCopy (check->v.origin, moved_from[num_moved]); - moved_edict[num_moved] = check; - num_moved++; - - // LordHavoc: pusher fixes (teleport train bug, etc) - savesolid = pusher->v.solid; - if (savesolid == SOLID_BSP || savesolid == SOLID_BBOX || savesolid == SOLID_SLIDEBOX) + if (check->v->movetype != MOVETYPE_WALK) + check->v->flags = (int)check->v->flags & ~FL_ONGROUND; + + 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); + // 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_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid) { - // try moving the contacted entity - pusher->v.solid = SOLID_NOT; + // try moving the contacted entity a tiny bit further to account for precision errors + pusher->v->solid = SOLID_NOT; + VectorScale(move, 0.1, move); SV_PushEntity (check, move); - pusher->v.solid = savesolid; // was SOLID_BSP + pusher->v->solid = savesolid; + 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 - // if it is still inside the pusher, block - if (SV_TestEntityPosition (check)) - { // fail the move - if (check->v.mins[0] == check->v.maxs[0]) + // fail the move + if (check->v->mins[0] == check->v->maxs[0]) continue; - if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER) - { // corpse - check->v.mins[0] = check->v.mins[1] = 0; - VectorCopy (check->v.mins, check->v.maxs); + if (check->v->solid == SOLID_NOT || check->v->solid == SOLID_TRIGGER) + { + // corpse + check->v->mins[0] = check->v->mins[1] = 0; + VectorCopy (check->v->mins, check->v->maxs); continue; } - - VectorCopy (entorig, check->v.origin); - SV_LinkEdict (check, true); - VectorCopy (pushorig, pusher->v.origin); + VectorCopy (pushorig, pusher->v->origin); + VectorCopy (pushang, pusher->v->angles); + pusher->v->ltime = pushltime; SV_LinkEdict (pusher, false); - pusher->v.ltime -= movetime; + + // move back any entities we already moved + for (i = 0;i < num_moved;i++) + { + ed = sv.moved_edicts[i]; + VectorCopy (ed->e->moved_from, ed->v->origin); + VectorCopy (ed->e->moved_fromangles, ed->v->angles); + SV_LinkEdict (ed, false); + } // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone - if (pusher->v.blocked) + if (pusher->v->blocked) { pr_global_struct->self = EDICT_TO_PROG(pusher); pr_global_struct->other = EDICT_TO_PROG(check); - PR_ExecuteProgram (pusher->v.blocked); - } - - // move back any entities we already moved - num_moved--; // LordHavoc: pop off check, because it was already restored - for (i=0 ; iv.origin); - SV_LinkEdict (moved_edict[i], false); + PR_ExecuteProgram (pusher->v->blocked, "QC function self.blocked is missing"); } - return; - } - } - } - - -} - -/* -============ -SV_PushRotate - -============ -*/ -void SV_PushRotate (edict_t *pusher, float movetime) -{ - int i, e; - edict_t *check; - vec3_t move, a, amove; - vec3_t entorigin, entangles, pushorigin, pushangles; - int num_moved; - edict_t *moved_edict[MAX_EDICTS]; - vec3_t moved_from[MAX_EDICTS]; - vec3_t angled_from[MAX_EDICTS]; - vec3_t org, org2; - vec3_t forward, right, up; - float savesolid; - - switch ((int) pusher->v.solid) - { - // LordHavoc: valid pusher types - case SOLID_BSP: - case SOLID_BBOX: - case SOLID_SLIDEBOX: - case SOLID_CORPSE: // LordHavoc: this would be weird... - break; - // LordHavoc: no collisions - case SOLID_NOT: - case SOLID_TRIGGER: - VectorMA (pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles); - pusher->v.ltime += movetime; - SV_LinkEdict (pusher, false); - return; - default: - Host_Error("SV_PushRotate: unrecognized solid type %f\n", pusher->v.solid); - } - if (!pusher->v.avelocity[0] && !pusher->v.avelocity[1] && !pusher->v.avelocity[2]) - { - pusher->v.ltime += movetime; - return; - } - - for (i=0 ; i<3 ; i++) - amove[i] = pusher->v.avelocity[i] * movetime; - - VectorSubtract (vec3_origin, amove, a); - AngleVectors (a, forward, right, up); - - VectorCopy (pusher->v.origin, pushorigin); - VectorCopy (pusher->v.angles, pushangles); - -// move the pusher to it's final position - - VectorAdd (pusher->v.angles, amove, pusher->v.angles); - pusher->v.ltime += movetime; - SV_LinkEdict (pusher, false); - - -// see if any solid entities are inside the final position - num_moved = 0; - check = NEXT_EDICT(sv.edicts); - for (e=1 ; efree) - continue; - if (check->v.movetype == MOVETYPE_PUSH - || check->v.movetype == MOVETYPE_NONE - || check->v.movetype == MOVETYPE_FOLLOW - || check->v.movetype == MOVETYPE_NOCLIP) - continue; - - // if the entity is standing on the pusher, it will definately be moved - if (!(((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher)) - { - if (check->v.absmin[0] >= pusher->v.absmax[0] - || check->v.absmin[1] >= pusher->v.absmax[1] - || check->v.absmin[2] >= pusher->v.absmax[2] - || check->v.absmax[0] <= pusher->v.absmin[0] - || check->v.absmax[1] <= pusher->v.absmin[1] - || check->v.absmax[2] <= pusher->v.absmin[2]) - continue; - - // see if the ent's bbox is inside the pusher's final position - if (!SV_TestEntityPosition (check)) - continue; - } - - // remove the onground flag for non-players - if (check->v.movetype != MOVETYPE_WALK) - check->v.flags = (int)check->v.flags & ~FL_ONGROUND; - - VectorCopy (check->v.origin, entorigin); - VectorCopy (check->v.origin, moved_from[num_moved]); - VectorCopy (check->v.angles, entangles); - VectorCopy (check->v.angles, angled_from[num_moved]); - moved_edict[num_moved] = check; - num_moved++; - - // calculate destination position - VectorSubtract (check->v.origin, pusher->v.origin, org); - org2[0] = DotProduct (org, forward); - org2[1] = -DotProduct (org, right); - org2[2] = DotProduct (org, up); - VectorSubtract (org2, org, move); - - // try moving the contacted entity - savesolid = pusher->v.solid; // LordHavoc: restore to correct solid type - pusher->v.solid = SOLID_NOT; - SV_PushEntity (check, move); - pusher->v.solid = savesolid; // LordHavoc: restore to correct solid type - - VectorAdd (check->v.angles, amove, check->v.angles); - - // if it is still inside the pusher, block - if (SV_TestEntityPosition (check)) - { // fail the move - if (check->v.mins[0] == check->v.maxs[0]) - continue; - if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER) - { // corpse - check->v.mins[0] = check->v.mins[1] = 0; - VectorCopy (check->v.mins, check->v.maxs); - continue; - } - - VectorCopy (entorigin, check->v.origin); - VectorCopy (entangles, check->v.angles); - SV_LinkEdict (check, true); - - VectorCopy (pushorigin, pusher->v.origin); - VectorCopy (pushangles, pusher->v.angles); - SV_LinkEdict (pusher, false); - pusher->v.ltime -= movetime; - - // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone - if (pusher->v.blocked) - { - pr_global_struct->self = EDICT_TO_PROG(pusher); - pr_global_struct->other = EDICT_TO_PROG(check); - PR_ExecuteProgram (pusher->v.blocked); - } - - // move back any entities we already moved - num_moved--; // LordHavoc: pop off check, because it was already restored - for (i=0 ; iv.origin); - VectorCopy (angled_from[i], moved_edict[i]->v.angles); - SV_LinkEdict (moved_edict[i], false); + break; } - return; } } + 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)); } /* @@ -743,41 +788,32 @@ SV_Physics_Pusher */ void SV_Physics_Pusher (edict_t *ent) { - float thinktime; - float oldltime; - float movetime; + float thinktime, oldltime, movetime; - oldltime = ent->v.ltime; - - thinktime = ent->v.nextthink; - if (thinktime < ent->v.ltime + host_frametime) + oldltime = ent->v->ltime; + + thinktime = ent->v->nextthink; + if (thinktime < ent->v->ltime + sv.frametime) { - movetime = thinktime - ent->v.ltime; + movetime = thinktime - ent->v->ltime; if (movetime < 0) movetime = 0; } else - movetime = host_frametime; + movetime = sv.frametime; if (movetime) + // advances ent->v->ltime if not blocked + SV_PushMove (ent, movetime); + + if (thinktime > oldltime && thinktime <= ent->v->ltime) { - if (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2]) - SV_PushRotate (ent, movetime); - else - SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked - } - - if (thinktime > oldltime && thinktime <= ent->v.ltime) - { - ent->v.nextthink = 0; + ent->v->nextthink = 0; 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); - if (ent->free) - return; + PR_ExecuteProgram (ent->v->think, "QC function self.think is missing"); } - } @@ -799,42 +835,41 @@ clipping hull. */ void SV_CheckStuck (edict_t *ent) { - int i, j; - int z; - vec3_t org; + int i, j, z; + vec3_t org; if (!SV_TestEntityPosition(ent)) { - VectorCopy (ent->v.origin, ent->v.oldorigin); + VectorCopy (ent->v->origin, ent->v->oldorigin); return; } - VectorCopy (ent->v.origin, org); - VectorCopy (ent->v.oldorigin, ent->v.origin); + VectorCopy (ent->v->origin, org); + VectorCopy (ent->v->oldorigin, ent->v->origin); if (!SV_TestEntityPosition(ent)) { - Con_DPrintf ("Unstuck.\n"); + Con_DPrint("Unstuck.\n"); SV_LinkEdict (ent, true); return; } - + for (z=0 ; z< 18 ; z++) for (i=-1 ; i <= 1 ; i++) for (j=-1 ; j <= 1 ; j++) { - ent->v.origin[0] = org[0] + i; - ent->v.origin[1] = org[1] + j; - ent->v.origin[2] = org[2] + z; + ent->v->origin[0] = org[0] + i; + ent->v->origin[1] = org[1] + j; + 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"); + + VectorCopy (org, ent->v->origin); + Con_DPrint("player is stuck.\n"); } @@ -845,33 +880,33 @@ SV_CheckWater */ qboolean SV_CheckWater (edict_t *ent) { - vec3_t point; - int cont; + int cont; + vec3_t point; - point[0] = ent->v.origin[0]; - point[1] = ent->v.origin[1]; - point[2] = ent->v.origin[2] + ent->v.mins[2] + 1; - - ent->v.waterlevel = 0; - ent->v.watertype = CONTENTS_EMPTY; - cont = SV_PointContents (point); + point[0] = ent->v->origin[0]; + point[1] = ent->v->origin[1]; + point[2] = ent->v->origin[2] + ent->v->mins[2] + 1; + + ent->v->waterlevel = 0; + ent->v->watertype = CONTENTS_EMPTY; + 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 = SV_PointContents (point); + 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 = SV_PointQ1Contents(point); if (cont <= CONTENTS_WATER) { - ent->v.waterlevel = 2; - point[2] = ent->v.origin[2] + ent->v.view_ofs[2]; - cont = SV_PointContents (point); + ent->v->waterlevel = 2; + point[2] = ent->v->origin[2] + ent->v->view_ofs[2]; + cont = SV_PointQ1Contents(point); if (cont <= CONTENTS_WATER) - ent->v.waterlevel = 3; + ent->v->waterlevel = 3; } } - - return ent->v.waterlevel > 1; + + return ent->v->waterlevel > 1; } /* @@ -880,26 +915,21 @@ SV_WallFriction ============ */ -void SV_WallFriction (edict_t *ent, trace_t *trace) +void SV_WallFriction (edict_t *ent, float *stepnormal) { - vec3_t forward, right, up; - float d, i; - vec3_t into, side; - - AngleVectors (ent->v.v_angle, forward, right, up); - 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); + float d, i; + vec3_t forward, into, side; + + AngleVectors (ent->v->v_angle, forward, NULL, NULL); + 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); + } } /* @@ -916,51 +946,50 @@ This is a hack, but in the interest of good gameplay... */ int SV_TryUnstick (edict_t *ent, vec3_t oldvel) { - int i; - vec3_t oldorg; - vec3_t dir; - int clip; - trace_t steptrace; - - VectorCopy (ent->v.origin, oldorg); - VectorCopy (vec3_origin, dir); + int i, clip; + vec3_t oldorg, dir; + + VectorCopy (ent->v->origin, oldorg); + VectorClear (dir); for (i=0 ; i<8 ; i++) { -// try pushing a little in an axial direction + // try pushing a little in an axial direction switch (i) { - case 0: dir[0] = 2; dir[1] = 0; break; - case 1: dir[0] = 0; dir[1] = 2; break; - case 2: dir[0] = -2; dir[1] = 0; break; - case 3: dir[0] = 0; dir[1] = -2; break; - case 4: dir[0] = 2; dir[1] = 2; break; - case 5: dir[0] = -2; dir[1] = 2; break; - case 6: dir[0] = 2; dir[1] = -2; break; - case 7: dir[0] = -2; dir[1] = -2; break; + case 0: dir[0] = 2; dir[1] = 0; break; + case 1: dir[0] = 0; dir[1] = 2; break; + case 2: dir[0] = -2; dir[1] = 0; break; + case 3: dir[0] = 0; dir[1] = -2; break; + case 4: dir[0] = 2; dir[1] = 2; break; + case 5: dir[0] = -2; dir[1] = 2; break; + case 6: dir[0] = 2; dir[1] = -2; break; + case 7: dir[0] = -2; dir[1] = -2; break; } - + SV_PushEntity (ent, dir); -// retry the original move - ent->v.velocity[0] = oldvel[0]; - ent->v. velocity[1] = oldvel[1]; - ent->v. velocity[2] = 0; - clip = SV_FlyMove (ent, 0.1, &steptrace); + // retry the original move + ent->v->velocity[0] = oldvel[0]; + ent->v->velocity[1] = oldvel[1]; + ent->v->velocity[2] = 0; + clip = SV_FlyMove (ent, 0.1, NULL); - if ( fabs(oldorg[1] - ent->v.origin[1]) > 4 - || fabs(oldorg[0] - ent->v.origin[0]) > 4 ) + if (fabs(oldorg[1] - ent->v->origin[1]) > 4 + || fabs(oldorg[0] - ent->v->origin[0]) > 4) { -//Con_DPrintf ("unstuck!\n"); + Con_DPrint("TryUnstick - success.\n"); return clip; } - -// go back to the original pos and try again - VectorCopy (oldorg, ent->v.origin); + + // go back to the original pos and try again + VectorCopy (oldorg, ent->v->origin); } - - VectorCopy (vec3_origin, ent->v.velocity); - return 7; // still not moving + + // still not moving + VectorClear (ent->v->velocity); + Con_DPrint("TryUnstick - failure.\n"); + return 7; } /* @@ -970,190 +999,138 @@ SV_WalkMove Only used by players ====================== */ -#define STEPSIZE 18 void SV_WalkMove (edict_t *ent) { - vec3_t upmove, downmove; - vec3_t oldorg, oldvel; - vec3_t nosteporg, nostepvel; - int clip; - int oldonground; - trace_t steptrace, downtrace; - -// -// do a regular slide move unless it looks like you ran into a step -// - 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); - - clip = SV_FlyMove (ent, host_frametime, &steptrace); + 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; - if ( !(clip & 2) ) - return; // move didn't block on a step + SV_CheckVelocity(ent); - if (!oldonground && ent->v.waterlevel == 0) - return; // don't stair up while jumping - - if (ent->v.movetype != MOVETYPE_WALK) - return; // gibbed by a trigger - - if (sv_nostep.value) - return; - - if ( (int)sv_player->v.flags & FL_WATERJUMP ) - return; + // do a regular slide move unless it looks like you ran into a step + oldonground = (int)ent->v->flags & FL_ONGROUND; + ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND; - VectorCopy (ent->v.origin, nosteporg); - VectorCopy (ent->v.velocity, nostepvel); + VectorCopy (ent->v->origin, start_origin); + VectorCopy (ent->v->velocity, start_velocity); -// -// try moving up and forward to go up a step -// - VectorCopy (oldorg, ent->v.origin); // back to start pos + clip = SV_FlyMove (ent, sv.frametime, NULL); - VectorCopy (vec3_origin, upmove); - VectorCopy (vec3_origin, downmove); - upmove[2] = STEPSIZE; - downmove[2] = -STEPSIZE + oldvel[2]*host_frametime; + SV_SetOnGround (ent); + SV_CheckVelocity(ent); -// move up - SV_PushEntity (ent, upmove); // FIXME: don't link? + 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; -// move forward - ent->v.velocity[0] = oldvel[0]; - ent->v. velocity[1] = oldvel[1]; - ent->v. velocity[2] = 0; - clip = SV_FlyMove (ent, host_frametime, &steptrace); + if ((int)ent->v->flags & FL_WATERJUMP) + return; -// check for stuckness, possibly due to the limited precision of floats -// in the clipping hulls - if (clip) + if (sv_nostep.integer) + return; + + // if move didn't block on a step, return + if (clip & 2) { - if ( 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); + // 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_FLY) + { + // return if gibbed by a trigger + if (ent->v->movetype != MOVETYPE_WALK) + return; + + // only step up while jumping if that is enabled + if (!(sv_jumpstep.integer && sv_gameplayfix_stepwhilejumping.integer)) + if (!oldonground && ent->v->waterlevel == 0) + return; } - } -// extra friction based on view angle - if ( clip & 2 ) - SV_WallFriction (ent, &steptrace); + // 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); + + // move up + VectorClear (upmove); + upmove[2] = sv_stepheight.value; + // FIXME: don't link? + SV_PushEntity(ent, upmove); + + // move forward + ent->v->velocity[2] = 0; + clip = SV_FlyMove (ent, sv.frametime, stepnormal); + ent->v->velocity[2] += start_velocity[2]; + + SV_CheckVelocity(ent); + + // 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; + } -// move down - downtrace = SV_PushEntity (ent, downmove); // FIXME: don't link? + //Con_Printf("step - "); - if (downtrace.plane.normal[2] > 0.7) + // 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); + + if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7) { - if (ent->v.solid == SOLID_BSP) + // LordHavoc: disabled this check so you can walk on monsters/players + //if (ent->v->solid == SOLID_BSP) { - ent->v.flags = (int)ent->v.flags | FL_ONGROUND; - ent->v.groundentity = EDICT_TO_PROG(downtrace.ent); + //Con_Printf("onground\n"); + ent->v->flags = (int)ent->v->flags | FL_ONGROUND; + ent->v->groundentity = EDICT_TO_PROG(downtrace.ent); } } else { -// 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); + //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(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_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); - -// -// 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_FlyMove (ent, host_frametime, NULL); - break; - - case MOVETYPE_NOCLIP: - if (!SV_RunThink (ent)) - return; - VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin); - 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); + SV_SetOnGround (ent); + SV_CheckVelocity(ent); } //============================================================================ -/* -============= -SV_Physics_None - -Non moving objects can only think -============= -*/ -void SV_Physics_None (edict_t *ent) -{ -// regular thinking - SV_RunThink (ent); -} - /* ============= SV_Physics_Follow @@ -1163,57 +1140,41 @@ Entities that are "stuck" to another entity */ void SV_Physics_Follow (edict_t *ent) { - vec3_t vf, vr, vu, angles; + vec3_t vf, vr, vu, angles, v; edict_t *e; -// regular thinking + + // regular thinking if (!SV_RunThink (ent)) return; + // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects - e = PROG_TO_EDICT(ent->v.aiment); - if (e->v.angles[0] == ent->v.punchangle[0] && e->v.angles[1] == ent->v.punchangle[1] && e->v.angles[2] == ent->v.punchangle[2]) + e = PROG_TO_EDICT(ent->v->aiment); + if (e->v->angles[0] == ent->v->punchangle[0] && e->v->angles[1] == ent->v->punchangle[1] && e->v->angles[2] == ent->v->punchangle[2]) { // quick case for no rotation - VectorAdd(e->v.origin, ent->v.view_ofs, ent->v.origin); + VectorAdd(e->v->origin, ent->v->view_ofs, ent->v->origin); } else { - angles[0] = -(e->v.angles[0] - ent->v.punchangle[0]); - angles[1] = e->v.angles[1] - ent->v.punchangle[1]; - angles[2] = e->v.angles[2] - ent->v.punchangle[2]; + angles[0] = -ent->v->punchangle[0]; + angles[1] = ent->v->punchangle[1]; + angles[2] = ent->v->punchangle[2]; AngleVectors (angles, vf, vr, vu); - ent->v.origin[0] = ent->v.view_ofs[0] * vf[0] + ent->v.view_ofs[1] * vr[0] + ent->v.view_ofs[2] * vu[0] + e->v.origin[0]; - ent->v.origin[1] = ent->v.view_ofs[0] * vf[1] + ent->v.view_ofs[1] * vr[1] + ent->v.view_ofs[2] * vu[1] + e->v.origin[1]; - ent->v.origin[2] = ent->v.view_ofs[0] * vf[2] + ent->v.view_ofs[1] * vr[2] + ent->v.view_ofs[2] * vu[2] + e->v.origin[2]; - /* - ent->v.origin[0] = ent->v.view_ofs[0] * vf[0] + ent->v.view_ofs[0] * vf[1] + ent->v.view_ofs[0] * vf[2] + e->v.origin[0]; - ent->v.origin[1] = ent->v.view_ofs[1] * vr[0] + ent->v.view_ofs[1] * vr[1] + ent->v.view_ofs[1] * vr[2] + e->v.origin[1]; - ent->v.origin[2] = ent->v.view_ofs[2] * vu[0] + ent->v.view_ofs[2] * vu[1] + ent->v.view_ofs[2] * vu[2] + e->v.origin[2]; - */ + v[0] = ent->v->view_ofs[0] * vf[0] + ent->v->view_ofs[1] * vr[0] + ent->v->view_ofs[2] * vu[0]; + v[1] = ent->v->view_ofs[0] * vf[1] + ent->v->view_ofs[1] * vr[1] + ent->v->view_ofs[2] * vu[1]; + v[2] = ent->v->view_ofs[0] * vf[2] + ent->v->view_ofs[1] * vr[2] + ent->v->view_ofs[2] * vu[2]; + angles[0] = -e->v->angles[0]; + angles[1] = e->v->angles[1]; + angles[2] = e->v->angles[2]; + AngleVectors (angles, vf, vr, vu); + ent->v->origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v->origin[0]; + ent->v->origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v->origin[1]; + ent->v->origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v->origin[2]; } - VectorAdd (e->v.angles, ent->v.v_angle, ent->v.angles); -// VectorAdd (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin); + VectorAdd (e->v->angles, ent->v->v_angle, ent->v->angles); 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, host_frametime, ent->v.avelocity, ent->v.angles); - VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin); - - SV_LinkEdict (ent, false); -} - /* ============================================================================== @@ -1230,32 +1191,29 @@ SV_CheckWaterTransition */ void SV_CheckWaterTransition (edict_t *ent) { - int cont; - cont = SV_PointContents (ent->v.origin); - if (!ent->v.watertype) - { // just spawned here - ent->v.watertype = cont; - ent->v.waterlevel = 1; + int cont; + cont = SV_PointQ1Contents(ent->v->origin); + if (!ent->v->watertype) + { + // just spawned here + ent->v->watertype = cont; + ent->v->waterlevel = 1; 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) - { // just crossed into water - SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1); - } - ent->v.watertype = cont; - ent->v.waterlevel = 1; + ent->v->watertype = cont; + ent->v->waterlevel = 1; } else { - if (ent->v.watertype != CONTENTS_EMPTY) - { // just crossed into water - SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1); - } - ent->v.watertype = CONTENTS_EMPTY; - ent->v.waterlevel = cont; + ent->v->watertype = CONTENTS_EMPTY; + ent->v->waterlevel = 0; } } @@ -1268,57 +1226,111 @@ Toss, bounce, and fly movement. When onground, do nothing. */ void SV_Physics_Toss (edict_t *ent) { - trace_t trace; - vec3_t move; - float backoff; + trace_t trace; + 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) ) - return; + 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, + // and groundentity is now freed, set groundentity to 0 (floating) + groundentity = PROG_TO_EDICT(ent->v->groundentity); + if (groundentity->v->solid == SOLID_BSP) + { + ent->e->suspendedinairflag = true; + return; + } + else if (ent->e->suspendedinairflag && groundentity->e->free) + { + // leave it suspended in the air + ent->v->groundentity = 0; + ent->e->suspendedinairflag = false; + return; + } + } + ent->e->suspendedinairflag = false; SV_CheckVelocity (ent); // add gravity - if (ent->v.movetype != MOVETYPE_FLY - && ent->v.movetype != MOVETYPE_BOUNCEMISSILE // LordHavoc: enabled MOVETYPE_BOUNCEMISSILE - && ent->v.movetype != MOVETYPE_FLYMISSILE) + if (ent->v->movetype == MOVETYPE_TOSS || ent->v->movetype == MOVETYPE_BOUNCE) SV_AddGravity (ent); // move angles - VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles); + VectorMA (ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles); // move origin - VectorScale (ent->v.velocity, host_frametime, move); + VectorScale (ent->v->velocity, sv.frametime, move); trace = SV_PushEntity (ent, move); - if (trace.fraction == 1) - return; - if (ent->free) + if (ent->e->free) return; - - if (ent->v.movetype == MOVETYPE_BOUNCE) - backoff = 1.5; - else if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE) - backoff = 2.0; - else - backoff = 1; - - ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff); -// stop if on ground - if (trace.plane.normal[2] > 0.7) - { - if (ent->v.velocity[2] < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE)) + if (trace.fraction < 1) + { + if (ent->v->movetype == MOVETYPE_BOUNCEMISSILE) { - ent->v.flags = (int)ent->v.flags | FL_ONGROUND; - ent->v.groundentity = EDICT_TO_PROG(trace.ent); - VectorCopy (vec3_origin, ent->v.velocity); - VectorCopy (vec3_origin, ent->v.avelocity); + ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 2.0); + ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND; + } + 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 (sv_gameplayfix_grenadebouncedownslopes.integer) + { + 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 + { + 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 + { + ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.0); + if (trace.plane.normal[2] > 0.7) + { + 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; } } - + // check for in water SV_CheckWaterTransition (ent); } @@ -1344,32 +1356,29 @@ will fall if the floor is pulled out from under them. */ void SV_Physics_Step (edict_t *ent) { - qboolean hitsound; + // 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 - if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) ) + // freefall if not onground/fly/swim + if (!((int)ent->v->flags & (FL_ONGROUND | FL_FLY | FL_SWIM))) { - if (ent->v.velocity[2] < sv_gravity.value*-0.1) - hitsound = true; - else - hitsound = false; + int hitsound = ent->v->velocity[2] < sv_gravity.value * -0.1; - SV_AddGravity (ent); - SV_CheckVelocity (ent); - SV_FlyMove (ent, host_frametime, NULL); - SV_LinkEdict (ent, true); + SV_AddGravity(ent); + SV_CheckVelocity(ent); + SV_FlyMove(ent, sv.frametime, NULL); + SV_LinkEdict(ent, true); - if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground - { - if (hitsound) - SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1); - } + // just hit ground + if (hitsound && (int)ent->v->flags & FL_ONGROUND) + SV_StartSound(ent, 0, "demon/dland2.wav", 255, 1); } // regular thinking - SV_RunThink (ent); - - SV_CheckWaterTransition (ent); + SV_RunThink(ent); + + SV_CheckWaterTransition(ent); } //============================================================================ @@ -1380,19 +1389,16 @@ SV_Physics ================ */ -extern dfunction_t *EndFrameQC; void SV_Physics (void) { - int i; - edict_t *ent; + int i; + edict_t *ent; // let the progs know that a new frame has started 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 (pr_global_struct->StartFrame); - -//SV_CheckAllEnts (); + PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing"); // // treat each object in turn @@ -1400,60 +1406,106 @@ 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 >= 1 && i <= svs.maxclients && svs.clients[i-1].spawned) { - SV_Physics_Client (ent, i); - 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; - switch ((int) ent->v.movetype) + // 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: - SV_Physics_None (ent); + // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects + if (ent->v->nextthink > 0 && ent->v->nextthink <= sv.time + sv.frametime) + SV_RunThink (ent); break; case MOVETYPE_FOLLOW: 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)) { - if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) ) + if (!SV_CheckWater (ent) && ! ((int)ent->v->flags & FL_WATERJUMP) ) SV_AddGravity (ent); SV_CheckStuck (ent); SV_WalkMove (ent); + // 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); + Host_Error ("SV_Physics: bad movetype %i", (int)ent->v->movetype); break; } + + if (i >= 1 && i <= svs.maxclients && svs.clients[i-1].spawned) + { + 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) - pr_global_struct->force_retouch--; + pr_global_struct->force_retouch--; // LordHavoc: endframe support if (EndFrameQC) @@ -1461,42 +1513,56 @@ 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 += host_frametime; + if (!sv_freezenonclients.integer) + sv.time += sv.frametime; } -trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore) +trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore) { int i; - edict_t tempent, *tent; - trace_t trace; - vec3_t move; - vec3_t end; - double save_frametime; + float gravity, savesolid; + vec3_t move, end; + edict_t tempent, *tent; + entvars_t vars; + eval_t *val; + trace_t trace; + + // copy the vars over + memcpy(&vars, tossent->v, sizeof(entvars_t)); + // set up the temp entity to point to the copied vars + tent = &tempent; + tent->v = &vars; - save_frametime = host_frametime; - host_frametime = 0.05; + savesolid = tossent->v->solid; + tossent->v->solid = SOLID_NOT; - memcpy(&tempent, ent, sizeof(edict_t)); - tent = &tempent; + // this has to fetch the field from the original edict, since our copy is truncated + val = GETEDICTFIELDVALUE(tossent, eval_gravity); + if (val != NULL && val->_float != 0) + gravity = val->_float; + else + gravity = 1.0; + gravity *= sv_gravity.value * 0.05; for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds { SV_CheckVelocity (tent); - SV_AddGravity (tent); - VectorMA (tent->v.angles, host_frametime, tent->v.avelocity, tent->v.angles); - VectorScale (tent->v.velocity, host_frametime, move); - VectorAdd (tent->v.origin, move, end); - trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent); - VectorCopy (trace.endpos, tent->v.origin); - - if (trace.ent) - if (trace.ent != ignore) - break; + tent->v->velocity[2] -= gravity; + VectorMA (tent->v->angles, 0.05, tent->v->avelocity, tent->v->angles); + VectorScale (tent->v->velocity, 0.05, move); + VectorAdd (tent->v->origin, move, end); + 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 && trace.ent != ignore) + break; } - host_frametime = save_frametime; + tossent->v->solid = savesolid; + trace.fraction = 0; // not relevant return trace; } +