X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=sv_phys.c;h=09ec4653e5b7df58d5965028270fd3a8cfeb55e4;hp=ffe1ce9c2b667086abbede91b1852bc94c4c4ac9;hb=9bd66d924bdc25d7e7d6885e9d5056b520509c4c;hpb=9ba80c169d244d56e90f437c512f827953cc1208 diff --git a/sv_phys.c b/sv_phys.c index ffe1ce9c..09ec4653 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,11 +39,11 @@ 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 = {0, "sv_stopspeed","100"}; +cvar_t sv_gravity = {CVAR_NOTIFY, "sv_gravity","800"}; +cvar_t sv_maxvelocity = {0, "sv_maxvelocity","2000"}; +cvar_t sv_nostep = {0, "sv_nostep","0"}; #define MOVE_EPSILON 0.01 @@ -118,7 +118,6 @@ void SV_CheckVelocity (edict_t *ent) ent->v.velocity[0] *= wishspeed; ent->v.velocity[1] *= wishspeed; ent->v.velocity[2] *= wishspeed; - wishspeed = sv_maxvelocity.value; } } @@ -137,7 +136,7 @@ qboolean SV_RunThink (edict_t *ent) float thinktime; thinktime = ent->v.nextthink; - if (thinktime <= 0 || thinktime > sv.time + host_frametime) + if (thinktime <= 0 || thinktime > sv.time + sv.frametime) return true; if (thinktime < sv.time) @@ -148,7 +147,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); + PR_ExecuteProgram (ent->v.think, "NULL think function"); return !ent->free; } @@ -162,23 +161,23 @@ Two entities have touched, so run their touch functions void SV_Impact (edict_t *e1, edict_t *e2) { 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) { 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, ""); } - + 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, ""); } pr_global_struct->self = old_self; @@ -201,13 +200,13 @@ int 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; for (i=0 ; i<3 ; i++) @@ -217,7 +216,7 @@ int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce) if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON) out[i] = 0; } - + return blocked; } @@ -234,7 +233,8 @@ Returns the clipflags if the velocity was modified (hit something solid) If steptrace is not NULL, the trace of any vertical wall hit will be stored ============ */ -#define MAX_CLIP_PLANES 5 +// LordHavoc: increased from 5 to 20 +#define MAX_CLIP_PLANES 20 int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace) { int bumpcount, numbumps; @@ -247,15 +247,15 @@ int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace) trace_t trace; vec3_t end; float time_left; - int blocked; - + int blocked, impact; + numbumps = 4; - + blocked = 0; VectorCopy (ent->v.velocity, original_velocity); VectorCopy (ent->v.velocity, primal_velocity); numplanes = 0; - + time_left = time; for (bumpcount=0 ; bumpcountv.origin[i] + time_left * ent->v.velocity[i]; - trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent); + trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent); + /* if (trace.allsolid) { // entity is trapped in another solid - VectorCopy (vec3_origin, ent->v.velocity); + VectorClear(ent->v.velocity); return 3; } + */ if (trace.fraction > 0) { // actually covered some distance @@ -287,10 +289,23 @@ int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace) if (!trace.ent) Host_Error ("SV_FlyMove: !trace.ent"); + if ((int) ent->v.flags & FL_ONGROUND) + { + if (ent->v.groundentity == EDICT_TO_PROG(trace.ent)) + impact = false; + else + { + ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND; + impact = true; + } + } + else + impact = true; + if (trace.plane.normal[2] > 0.7) { blocked |= 1; // floor - if (trace.ent->v.solid == SOLID_BSP) + //if (trace.ent->v.solid == SOLID_BSP) { ent->v.flags = (int)ent->v.flags | FL_ONGROUND; ent->v.groundentity = EDICT_TO_PROG(trace.ent); @@ -306,17 +321,18 @@ int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace) // // run the impact function // - SV_Impact (ent, trace.ent); + if (impact) + SV_Impact (ent, trace.ent); if (ent->free) break; // removed by the impact function - + time_left -= time_left * trace.fraction; - + // cliped to another plane if (numplanes >= MAX_CLIP_PLANES) { // this shouldn't really happen - VectorCopy (vec3_origin, ent->v.velocity); + VectorClear(ent->v.velocity); return 3; } @@ -338,7 +354,7 @@ int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace) if (j == numplanes) break; } - + if (i != numplanes) { // go along this plane VectorCopy (new_velocity, ent->v.velocity); @@ -348,10 +364,12 @@ int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace) if (numplanes != 2) { // Con_Printf ("clip velocity, numplanes == %i\n",numplanes); - VectorCopy (vec3_origin, ent->v.velocity); + VectorClear(ent->v.velocity); return 7; } 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); } @@ -362,7 +380,7 @@ int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace) // if (DotProduct (ent->v.velocity, primal_velocity) <= 0) { - VectorCopy (vec3_origin, ent->v.velocity); + VectorClear(ent->v.velocity); return blocked; } } @@ -388,7 +406,7 @@ void SV_AddGravity (edict_t *ent) 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; } @@ -407,11 +425,11 @@ SV_PushEntity Does not change the entities velocity at all ============ */ -trace_t SV_PushEntity (edict_t *ent, vec3_t push) +trace_t SV_PushEntity (edict_t *ent, vec3_t push, vec3_t pushangles) { trace_t trace; vec3_t end; - + VectorAdd (ent->v.origin, push, end); if (ent->v.movetype == MOVETYPE_FLYMISSILE) @@ -420,16 +438,17 @@ trace_t SV_PushEntity (edict_t *ent, vec3_t push) // only clip against bmodels trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent); else - trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent); - + trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, 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.ent) - SV_Impact (ent, 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; -} +} /* @@ -438,16 +457,18 @@ 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; + int i, e, index; edict_t *check; - vec3_t mins, maxs, move; - vec3_t entorig, pushorig; + float savesolid, movetime2, pushltime; + vec3_t mins, maxs, move, move1, moveangle, /*entorig, entang, */pushorig, pushang, a, forward, left, up, org, org2; int num_moved; edict_t *moved_edict[MAX_EDICTS]; - vec3_t moved_from[MAX_EDICTS]; - float savesolid; + vec3_t moved_from[MAX_EDICTS], moved_fromangles[MAX_EDICTS]; + model_t *pushermodel; + trace_t trace; switch ((int) pusher->v.solid) { @@ -461,33 +482,91 @@ void SV_PushMove (edict_t *pusher, float movetime) case SOLID_NOT: 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.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]) + 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; } - - for (i=0 ; i<3 ; i++) + index = (int) pusher->v.modelindex; + if (index < 1 || index >= MAX_MODELS) + Host_Error("SV_PushMove: invalid modelindex %f\n", pusher->v.modelindex); + pushermodel = sv.models[index]; + + // LordHavoc: round up by a small epsilon + movetime2 = movetime; // + (1.0 / 256.0); + VectorScale(pusher->v.velocity, movetime2, move1); + VectorScale(pusher->v.avelocity, movetime2, moveangle); + if (moveangle[0] || moveangle[2]) + { + 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 { - 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->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; + } + } } + 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); + 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; @@ -506,211 +585,116 @@ void SV_PushMove (edict_t *pusher, float movetime) 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.absmin[1] >= maxs[1] || check->v.absmax[1] <= mins[1] + || check->v.absmin[2] >= maxs[2] || check->v.absmax[2] <= mins[2]) continue; + /* + if (forward[0] < 0.999f) // 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); + //VectorSubtract(check->v.origin, move, a); + a[0] = check->v.origin[0] + (org[0] - org2[0]) - move1[0]; + a[1] = check->v.origin[1] + (org[1] - org2[1]) - move1[1]; + a[2] = check->v.origin[2] + (org[2] - org2[2]) - move1[2]; + } + else + VectorSubtract (check->v.origin, move1, a); + + trace = SV_ClipMoveToEntity (pusher, a, check->v.mins, check->v.maxs, check->v.origin); + if (trace.fraction == 1 && !trace.startsolid) + continue; + */ + trace = SV_ClipMoveToEntity (pusher, check->v.origin, check->v.mins, check->v.maxs, check->v.origin); + if (!trace.startsolid) + 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, 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 (forward[0] < 0.999f) // quick way to check if any rotation is used { - // try moving the contacted entity - pusher->v.solid = SOLID_NOT; - SV_PushEntity (check, move); - pusher->v.solid = savesolid; // was SOLID_BSP - - // 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 (entorig, check->v.origin); - SV_LinkEdict (check, true); - - VectorCopy (pushorig, pusher->v.origin); - 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); - SV_LinkEdict (moved_edict[i], false); - } - return; - } + 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); } - } - - -} - -/* -============ -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; - - 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; + else + VectorCopy (move1, move); - // 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; + // LordHavoc: debugging + //VectorAdd(entorig, move, org2); + //CL_RocketTrail2 (entorig, org2, 238, NULL); - // 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 + // 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, entorig); + //VectorCopy (check->v.angles, entang); 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 + VectorCopy (check->v.angles, moved_fromangles[num_moved]); + moved_edict[num_moved++] = check; - VectorAdd (check->v.angles, amove, check->v.angles); + // try moving the contacted entity + pusher->v.solid = SOLID_NOT; + trace = SV_PushEntity (check, move, moveangle); + pusher->v.solid = savesolid; // was SOLID_BSP - // if it is still inside the pusher, block - if (SV_TestEntityPosition (check)) - { // fail the move + // if it is still inside the pusher, block + // LordHavoc: cleanup - check trace.fraction and startsolid + if (/*trace.fraction != 1 || trace.startsolid || */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 + { + // 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); + + /* + VectorCopy (entorig, check->v.origin); + VectorCopy (entang, check->v.angles); SV_LinkEdict (check, true); + */ - VectorCopy (pushorigin, pusher->v.origin); - VectorCopy (pushangles, pusher->v.angles); + 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 + //num_moved--; // LordHavoc: pop off check, because it was already restored + for (i=0 ; iv.origin); + VectorCopy (moved_fromangles[i], moved_edict[i]->v.angles); + SV_LinkEdict (moved_edict[i], false); + } // 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); + PR_ExecuteProgram (pusher->v.blocked, ""); } return; } @@ -730,50 +714,27 @@ void SV_Physics_Pusher (edict_t *ent) float movetime; oldltime = ent->v.ltime; - - /* + thinktime = ent->v.nextthink; - if (thinktime < ent->v.ltime + host_frametime) + if (thinktime < ent->v.ltime + sv.frametime) { movetime = thinktime - ent->v.ltime; if (movetime < 0) movetime = 0; } else - movetime = host_frametime; + movetime = sv.frametime; if (movetime) - { - 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 (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2]) - SV_PushRotate (ent, host_frametime); - else - { - thinktime = ent->v.nextthink; - if (thinktime < ent->v.ltime + host_frametime) - { - movetime = thinktime - ent->v.ltime; - if (movetime < 0) - movetime = 0; - } - else - movetime = host_frametime; - if (movetime) - SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked - } - + SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked + if (thinktime > oldltime && thinktime <= ent->v.ltime) { 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); + PR_ExecuteProgram (ent->v.think, "NULL think function"); if (ent->free) return; } @@ -850,7 +811,7 @@ qboolean SV_CheckWater (edict_t *ent) point[0] = ent->v.origin[0]; point[1] = ent->v.origin[1]; - point[2] = ent->v.origin[2] + ent->v.mins[2] + 1; + point[2] = ent->v.origin[2] + ent->v.mins[2] + 1; ent->v.waterlevel = 0; ent->v.watertype = CONTENTS_EMPTY; @@ -882,17 +843,17 @@ SV_WallFriction */ void SV_WallFriction (edict_t *ent, trace_t *trace) { - vec3_t forward, right, up; + vec3_t forward; float d, i; vec3_t into, side; - - AngleVectors (ent->v.v_angle, forward, right, up); + + AngleVectors (ent->v.v_angle, forward, NULL, NULL); d = DotProduct (trace->plane.normal, forward); d += 0.5; if (d >= 0) return; - + // cut the tangential velocity i = DotProduct (trace->plane.normal, ent->v.velocity); VectorScale (trace->plane.normal, i, into); @@ -921,9 +882,9 @@ int SV_TryUnstick (edict_t *ent, vec3_t oldvel) vec3_t dir; int clip; trace_t steptrace; - + VectorCopy (ent->v.origin, oldorg); - VectorCopy (vec3_origin, dir); + VectorClear (dir); for (i=0 ; i<8 ; i++) { @@ -939,13 +900,13 @@ int SV_TryUnstick (edict_t *ent, vec3_t oldvel) case 6: dir[0] = 2; dir[1] = -2; break; case 7: dir[0] = -2; dir[1] = -2; break; } - - SV_PushEntity (ent, dir); + + SV_PushEntity (ent, dir, vec3_origin); // retry the original move ent->v.velocity[0] = oldvel[0]; - ent->v. velocity[1] = oldvel[1]; - ent->v. velocity[2] = 0; + ent->v.velocity[1] = oldvel[1]; + ent->v.velocity[2] = 0; clip = SV_FlyMove (ent, 0.1, &steptrace); if ( fabs(oldorg[1] - ent->v.origin[1]) > 4 @@ -954,12 +915,12 @@ int SV_TryUnstick (edict_t *ent, vec3_t oldvel) //Con_DPrintf ("unstuck!\n"); return clip; } - + // go back to the original pos and try again VectorCopy (oldorg, ent->v.origin); } - VectorCopy (vec3_origin, ent->v.velocity); + VectorClear (ent->v.velocity); return 7; // still not moving } @@ -979,30 +940,30 @@ void SV_WalkMove (edict_t *ent) 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); + + clip = SV_FlyMove (ent, sv.frametime, &steptrace); if ( !(clip & 2) ) return; // move didn't block on a step 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) + + if (sv_nostep.integer) return; - + if ( (int)sv_player->v.flags & FL_WATERJUMP ) return; @@ -1014,19 +975,19 @@ void SV_WalkMove (edict_t *ent) // VectorCopy (oldorg, ent->v.origin); // back to start pos - VectorCopy (vec3_origin, upmove); - VectorCopy (vec3_origin, downmove); + VectorClear (upmove); + VectorClear (downmove); upmove[2] = STEPSIZE; - downmove[2] = -STEPSIZE + oldvel[2]*host_frametime; + downmove[2] = -STEPSIZE + oldvel[2]*sv.frametime; // move up - SV_PushEntity (ent, upmove); // FIXME: don't link? + SV_PushEntity (ent, upmove, vec3_origin); // FIXME: don't link? // 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); + clip = SV_FlyMove (ent, sv.frametime, &steptrace); // check for stuckness, possibly due to the limited precision of floats // in the clipping hulls @@ -1038,13 +999,13 @@ void SV_WalkMove (edict_t *ent) clip = SV_TryUnstick (ent, oldvel); } } - + // extra friction based on view angle if ( clip & 2 ) SV_WallFriction (ent, &steptrace); // move down - downtrace = SV_PushEntity (ent, downmove); // FIXME: don't link? + downtrace = SV_PushEntity (ent, downmove, vec3_origin); // FIXME: don't link? if (downtrace.plane.normal[2] > 0.7) { @@ -1058,7 +1019,7 @@ void SV_WalkMove (edict_t *ent) { // 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 +// cause the player to hop up higher on a slope too steep to climb VectorCopy (nosteporg, ent->v.origin); VectorCopy (nostepvel, ent->v.velocity); } @@ -1079,11 +1040,11 @@ void SV_Physics_Client (edict_t *ent, int num) // // 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); - + PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing"); + // // do a move // @@ -1107,7 +1068,7 @@ void SV_Physics_Client (edict_t *ent, int num) SV_CheckStuck (ent); SV_WalkMove (ent); break; - + case MOVETYPE_TOSS: case MOVETYPE_BOUNCE: SV_Physics_Toss (ent); @@ -1116,27 +1077,29 @@ void SV_Physics_Client (edict_t *ent, int num) case MOVETYPE_FLY: if (!SV_RunThink (ent)) return; - SV_FlyMove (ent, host_frametime, NULL); + SV_CheckWater (ent); + SV_FlyMove (ent, sv.frametime, NULL); break; - + case MOVETYPE_NOCLIP: if (!SV_RunThink (ent)) return; - VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin); + SV_CheckWater (ent); + VectorMA (ent->v.origin, sv.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); + PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing"); } //============================================================================ @@ -1148,11 +1111,14 @@ SV_Physics_None Non moving objects can only think ============= */ +// LordHavoc: inlined manually because it was a real time waster +/* void SV_Physics_None (edict_t *ent) { // regular thinking SV_RunThink (ent); } +*/ /* ============= @@ -1163,19 +1129,40 @@ Entities that are "stuck" to another entity */ void SV_Physics_Follow (edict_t *ent) { - vec3_t vf, vu, vr, angles; + vec3_t vf, vr, vu, angles, v; edict_t *e; // regular thinking - SV_RunThink (ent); + if (!SV_RunThink (ent)) + return; // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects e = PROG_TO_EDICT(ent->v.aiment); - angles[0] = -e->v.angles[0]; - angles[1] = e->v.angles[1]; - angles[2] = e->v.angles[2]; - AngleVectors (angles, vf, vr, vu); - VectorMA (e->v.origin, ent->v.view_ofs[0], vf, ent->v.origin); - VectorMA (ent->v.origin, ent->v.view_ofs[1], vr, ent->v.origin); - VectorMA (ent->v.origin, ent->v.view_ofs[2], vu, ent->v.origin); + 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); + } + else + { + angles[0] = -ent->v.punchangle[0]; + angles[1] = ent->v.punchangle[1]; + angles[2] = ent->v.punchangle[2]; + AngleVectors (angles, vf, vr, vu); + 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]; + /* + 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]; + */ + } 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); SV_LinkEdict (ent, true); @@ -1193,9 +1180,9 @@ 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); + + VectorMA (ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles); + VectorMA (ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin); SV_LinkEdict (ent, false); } @@ -1224,13 +1211,13 @@ void SV_CheckWaterTransition (edict_t *ent) ent->v.waterlevel = 1; return; } - + 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; } @@ -1239,7 +1226,7 @@ void SV_CheckWaterTransition (edict_t *ent) 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; } @@ -1256,14 +1243,26 @@ void SV_Physics_Toss (edict_t *ent) { trace_t trace; vec3_t move; - float backoff; + //edict_t *groundentity; // regular thinking if (!SV_RunThink (ent)) return; // if onground, return without moving - if ( ((int)ent->v.flags & FL_ONGROUND) ) + if (((int)ent->v.flags & FL_ONGROUND) && ent->v.groundentity == 0) return; + /* + if ( ((int)ent->v.flags & FL_ONGROUND) ) + { + // LordHavoc: fall if the groundentity was removed + if (ent->v.groundentity) + { + groundentity = PROG_TO_EDICT(ent->v.groundentity); + if (groundentity && groundentity->v.solid != SOLID_NOT && groundentity->v.solid != SOLID_TRIGGER) + return; + } + } + */ SV_CheckVelocity (ent); @@ -1274,37 +1273,50 @@ void SV_Physics_Toss (edict_t *ent) 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); - trace = SV_PushEntity (ent, move); - if (trace.fraction == 1) - return; + VectorScale (ent->v.velocity, sv.frametime, move); + trace = SV_PushEntity (ent, move, vec3_origin); if (ent->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); + if (trace.fraction == 1) + return; -// 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 (ent->v.movetype == MOVETYPE_BOUNCEMISSILE) + { + 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) + { + 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 (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); - VectorCopy (vec3_origin, ent->v.velocity); - VectorCopy (vec3_origin, ent->v.avelocity); + 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); } @@ -1330,23 +1342,41 @@ will fall if the floor is pulled out from under them. */ void SV_Physics_Step (edict_t *ent) { - qboolean hitsound; + int flags, fall, hitsound; -// freefall if not onground - if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) ) + // freefall if not fly/swim + fall = true; + flags = (int)ent->v.flags; + if (flags & (FL_FLY | FL_SWIM)) + { + if (flags & FL_FLY) + fall = false; + else if ((flags & FL_SWIM) && SV_PointContents(ent->v.origin) != CONTENTS_EMPTY) + fall = false; + } + if (fall && (flags & FL_ONGROUND) && ent->v.groundentity == 0) + fall = false; + + if (fall) { if (ent->v.velocity[2] < sv_gravity.value*-0.1) + { hitsound = true; + if (flags & FL_ONGROUND) + hitsound = false; + } else hitsound = false; SV_AddGravity (ent); SV_CheckVelocity (ent); - SV_FlyMove (ent, host_frametime, NULL); - SV_LinkEdict (ent, true); + SV_FlyMove (ent, sv.frametime, NULL); + SV_LinkEdict (ent, false); - if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground + // just hit ground + if ((int)ent->v.flags & FL_ONGROUND) { + VectorClear(ent->v.velocity); if (hitsound) SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1); } @@ -1354,7 +1384,7 @@ void SV_Physics_Step (edict_t *ent) // regular thinking SV_RunThink (ent); - + SV_CheckWaterTransition (ent); } @@ -1366,7 +1396,6 @@ SV_Physics ================ */ -extern dfunction_t *EndFrameQC; void SV_Physics (void) { int i; @@ -1376,7 +1405,7 @@ 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 (pr_global_struct->StartFrame); + PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing"); //SV_CheckAllEnts (); @@ -1404,7 +1433,10 @@ void SV_Physics (void) SV_Physics_Pusher (ent); break; case MOVETYPE_NONE: - SV_Physics_None (ent); +// 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); @@ -1423,6 +1455,7 @@ void SV_Physics (void) SV_AddGravity (ent); SV_CheckStuck (ent); SV_WalkMove (ent); + SV_LinkEdict (ent, true); } break; case MOVETYPE_TOSS: @@ -1437,9 +1470,9 @@ void SV_Physics (void) break; } } - + if (pr_global_struct->force_retouch) - pr_global_struct->force_retouch--; + pr_global_struct->force_retouch--; // LordHavoc: endframe support if (EndFrameQC) @@ -1447,42 +1480,51 @@ 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), ""); } - sv.time += host_frametime; + 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; - - save_frametime = host_frametime; - host_frametime = 0.05; + float gravity, savesolid; + eval_t *val; - memcpy(&tempent, ent, sizeof(edict_t)); + memcpy(&tempent, tossent, sizeof(edict_t)); tent = &tempent; + savesolid = tossent->v.solid; + tossent->v.solid = SOLID_NOT; + + // 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); + 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); + 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.fraction < 1 && trace.ent) if (trace.ent != ignore) break; } - host_frametime = save_frametime; + tossent->v.solid = savesolid; + trace.fraction = 0; // not relevant return trace; }