/* Player has come to a dead stop, possibly due to the problem with limited float precision at some angle joins in the BSP hull. Try fixing by pushing one pixel in each direction. 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; Math_VectorCopy (ent->v.origin, oldorg); Math_VectorCopy (mv3Origin, dir); for (i=0 ; i<8 ; i++) { // 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; } 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.1f,&steptrace); if ( fabs(oldorg[1] - ent->v.origin[1]) > 4 || fabs(oldorg[0] - ent->v.origin[0]) > 4 ) return clip; // Go back to the original pos and try again Math_VectorCopy (oldorg, ent->v.origin); } Math_VectorCopy(mv3Origin,ent->v.velocity); return 7; // still not moving }
/* ============= SV_Physics_Toss Toss, bounce, and fly movement. When onground, do nothing. ============= */ TM_CALLABLE void SV_Physics_Toss (edict_t *ent) { trace_t trace; vec3_t move; float backoff; // regular thinking if (!SV_RunThink (ent)) return; if (ent->v.velocity[2] > 0) ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND; // if onground, return without moving if ( ((int)ent->v.flags & FL_ONGROUND) ) return; SV_CheckVelocity (ent); // add gravity if (ent->v.movetype != MOVETYPE_FLY && ent->v.movetype != MOVETYPE_FLYMISSILE) SV_AddGravity (ent, 1.0); // move angles VectorMA (ent->v.angles, host_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; if (ent->free) return; if (ent->v.movetype == MOVETYPE_BOUNCE) backoff = 1.5; 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.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); } } // check for in water SV_CheckWaterTransition (ent); }
/* Toss, bounce, and fly movement. When onground, do nothing. */ void Physics_Toss(edict_t *ent) { trace_t trace; vec3_t move; float backoff; // Regular thinking if(!Server_RunThink(ent) || (ent->v.flags & FL_ONGROUND)) return; Game->Physics_CheckVelocity(ent); // Add gravity if(ent->v.movetype != MOVETYPE_FLY && ent->v.movetype != MOVETYPE_FLYMISSILE && ent->v.movetype != MOVETYPE_FLYBOUNCE) Game->Physics_SetGravity(ent); // Move angles Math_VectorMA(ent->v.angles,host_frametime,ent->v.avelocity,ent->v.angles); // Move origin Math_VectorScale(ent->v.velocity,host_frametime,move); trace = SV_PushEntity(ent, move); if(trace.fraction == 1.0f || ent->free) return; if(ent->v.movetype == MOVETYPE_FLYBOUNCE) backoff = 2.0f; else if (ent->v.movetype == MOVETYPE_BOUNCE) backoff = 1.5f; else backoff = 1.0f; ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff); // Stop if on ground if(trace.plane.normal[2] > 0.7 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_FLYBOUNCE)) if(ent->v.velocity[2] < 60.0f) { ent->v.flags = ent->v.flags | FL_ONGROUND; ent->v.groundentity = trace.ent; Math_VectorCopy(mv3Origin,ent->v.velocity); Math_VectorCopy(mv3Origin,ent->v.avelocity); } Game->Physics_CheckWaterTransition(ent); }
// [18/5/2013] TODO: Merge with SV_PushMove ~hogsy static void Server_PushRotate(edict_t *pusher,float movetime) { int i,e,num_moved,slaves_moved; edict_t *check,*block,*moved_edict[MAX_EDICTS],*ground,*slave,*master; vec3_t move,a,amove,entorig,pushorig,moved_from[MAX_EDICTS],org,org2,forward,right,up; bool bMoveIt; for (i = 0; i < 3; i++) amove[i] = pusher->v.avelocity[i] * movetime; Math_VectorNegate(amove,a); Math_AngleVectors(a,forward,right,up); Math_VectorCopy(pusher->v.angles,pushorig); // move the pusher to it's final position Math_VectorAdd(pusher->v.angles,amove,pusher->v.angles); pusher->v.ltime += movetime; SV_LinkEdict (pusher, false); slaves_moved = 0; master = pusher; while(master->v.aiment) { slave = PROG_TO_EDICT(master->v.aiment); slaves_moved++; Math_VectorCopy (slave->v.angles, moved_from[MAX_EDICTS - slaves_moved]); moved_edict[MAX_EDICTS - slaves_moved] = slave; if (slave->v.movedir[PITCH]) slave->v.angles[PITCH] = master->v.angles[PITCH]; else slave->v.angles[PITCH] += slave->v.avelocity[PITCH] * movetime; if (slave->v.movedir[YAW]) slave->v.angles[YAW] = master->v.angles[YAW]; else slave->v.angles[YAW] += slave->v.avelocity[YAW] * movetime; if (slave->v.movedir[ROLL]) slave->v.angles[ROLL] = master->v.angles[ROLL]; else slave->v.angles[ROLL] += slave->v.avelocity[ROLL] * movetime; slave->v.ltime = master->v.ltime; SV_LinkEdict(slave,false); master = slave; } // 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) continue; if (check->v.movetype == MOVETYPE_PUSH || check->v.movetype == MOVETYPE_NONE || check->v.movetype == MOVETYPE_NOCLIP) continue; // if the entity is standing on the pusher, it will definitely be moved bMoveIt = false; ground = check->v.groundentity; if(check->v.flags & FL_ONGROUND) { if (ground == pusher) bMoveIt = true; else { for (i = 0; i < slaves_moved; i++) { if (ground == moved_edict[MAX_EDICTS - i - 1]) { bMoveIt = true; break; } } } } if(!bMoveIt) { 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]) { for (i = 0; i < slaves_moved; i++) { slave = moved_edict[MAX_EDICTS-i-1]; if( check->v.absmin[0] >= slave->v.absmax[0] || check->v.absmin[1] >= slave->v.absmax[1] || check->v.absmin[2] >= slave->v.absmax[2] || check->v.absmax[0] <= slave->v.absmin[0] || check->v.absmax[1] <= slave->v.absmin[1] || check->v.absmax[2] <= slave->v.absmin[2] ) continue; } if (i == slaves_moved) 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 = check->v.flags & ~FL_ONGROUND; Math_VectorCopy(check->v.origin,entorig); Math_VectorCopy(check->v.origin,moved_from[num_moved]); moved_edict[num_moved] = check; num_moved++; // calculate destination position Math_VectorSubtract(check->v.origin,pusher->v.origin,org); org2[0] = Math_DotProduct(org,forward); org2[1] = -Math_DotProduct(org,right); org2[2] = Math_DotProduct(org,up); Math_VectorSubtract (org2,org,move); // try moving the contacted entity pusher->Physics.iSolid = SOLID_NOT; SV_PushEntity (check, move); //@@TODO: do we ever want to do anybody's angles? maybe just yaw??? if(check->monster.iType != 1) { #if 0 vec3_t vYaw; vYaw[YAW] = Math_AngleMod(pusher->v.angles[YAW]+check->v.angles[YAW]); Con_Printf("%i %i\n",(int)check->v.angles[YAW],(int)vYaw[YAW]); //check->v.angles[YAW] = vYaw[YAW]; //check->v.angles[YAW] = Math_AngleMod(vYaw[YAW]); #endif // move back any entities we already moved for (i = 0; i < num_moved; i++) { Math_VectorAdd(moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles); moved_edict[i]->v.angles[YAW] += amove[YAW]/2.0f; SV_LinkEdict(moved_edict[i],false); } } pusher->Physics.iSolid = SOLID_BSP; // If it is still inside the pusher, block block = SV_TestEntityPosition (check); if (block) { // fail the move if (check->v.mins[0] == check->v.maxs[0]) continue; if (check->Physics.iSolid == SOLID_NOT || check->Physics.iSolid == SOLID_TRIGGER) { // corpse check->v.mins[0] = check->v.mins[1] = 0; Math_VectorCopy(check->v.mins,check->v.maxs); continue; } Math_VectorCopy(entorig,check->v.origin); SV_LinkEdict(check,true); Math_VectorCopy(pushorig,pusher->v.angles); SV_LinkEdict(pusher,false); pusher->v.ltime -= movetime; for(i = 0; i < slaves_moved; i++) { slave = moved_edict[MAX_EDICTS - i - 1]; Math_VectorCopy(moved_from[MAX_EDICTS - i - 1], slave->v.angles); SV_LinkEdict(slave,false); slave->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) pusher->v.blocked(pusher,check); // move back any entities we already moved for (i = 0; i < num_moved; i++) { Math_VectorCopy (moved_from[i], moved_edict[i]->v.origin); //@@TODO:: see above // if (!((int)moved_edict[i]->v.flags & (FL_CLIENT | FL_MONSTER))) Math_VectorSubtract (moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles); moved_edict[i]->v.angles[YAW] -= amove[YAW]; SV_LinkEdict(moved_edict[i],false); } return; } } }
void SV_PushMove (edict_t *pusher, float movetime) { int i, e; edict_t *check, *block; vec3_t mins, maxs, move; vec3_t entorig, pushorig; int num_moved; edict_t **moved_edict; //johnfitz -- dynamically allocate vec3_t *moved_from; //johnfitz -- dynamically allocate int mark; //johnfitz if(!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2]) { pusher->v.ltime += movetime; return; } for (i=0 ; i<3 ; i++) { move[i] = pusher->v.velocity[i] * movetime; mins[i] = pusher->v.absmin[i] + move[i]; maxs[i] = pusher->v.absmax[i] + move[i]; } Math_VectorCopy (pusher->v.origin, pushorig); // move the pusher to it's final position Math_VectorAdd (pusher->v.origin, move, pusher->v.origin); pusher->v.ltime += movetime; SV_LinkEdict(pusher,false); //johnfitz -- dynamically allocate mark = Hunk_LowMark (); moved_edict = (edict_t**)Hunk_Alloc(sv.num_edicts*sizeof(edict_t*)); moved_from = (vec3_t(*))Hunk_Alloc (sv.num_edicts*sizeof(vec3_t)); //johnfitz // 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) continue; if (check->v.movetype == MOVETYPE_PUSH || check->v.movetype == MOVETYPE_NONE || check->v.movetype == MOVETYPE_NOCLIP) continue; // if the entity is standing on the pusher, it will definately be moved if(!((check->v.flags & FL_ONGROUND) && 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] ) 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 = check->v.flags & ~FL_ONGROUND; Math_VectorCopy(check->v.origin,entorig); Math_VectorCopy(check->v.origin,moved_from[num_moved]); moved_edict[num_moved] = check; num_moved++; // try moving the contacted entity pusher->Physics.iSolid = SOLID_NOT; SV_PushEntity (check, move); pusher->Physics.iSolid = SOLID_BSP; // if it is still inside the pusher, block block = SV_TestEntityPosition (check); if (block) { // fail the move if (check->v.mins[0] == check->v.maxs[0]) continue; if (check->Physics.iSolid == SOLID_NOT || check->Physics.iSolid == SOLID_TRIGGER) { // corpse check->v.mins[0] = check->v.mins[1] = 0; Math_VectorCopy(check->v.mins,check->v.maxs); continue; } Math_VectorCopy(entorig,check->v.origin); SV_LinkEdict(check,true); Math_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.eOther = check; pusher->v.blocked(pusher,check); } // move back any entities we already moved for (i=0 ; i<num_moved ; i++) { Math_VectorCopy(moved_from[i],moved_edict[i]->v.origin); SV_LinkEdict (moved_edict[i], false); } Hunk_FreeToLowMark (mark); //johnfitz return; } } Hunk_FreeToLowMark (mark); //johnfitz }
/* ============ SV_PushMove ============ */ void SV_PushMove (edict_t *pusher, float movetime) { int i, e; edict_t *check, *block; vec3_t mins, maxs, move; vec3_t entorig, pushorig; int num_moved; edict_t *moved_edict[MAX_EDICTS]; vec3_t moved_from[MAX_EDICTS]; if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2]) { pusher->v.ltime += movetime; return; } for (i=0 ; i<3 ; i++) { move[i] = pusher->v.velocity[i] * movetime; mins[i] = pusher->v.absmin[i] + move[i]; maxs[i] = pusher->v.absmax[i] + move[i]; } VectorCopy (pusher->v.origin, pushorig); // move the pusher to it's final position VectorAdd (pusher->v.origin, move, pusher->v.origin); 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 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check)) { if (check->free) continue; if (check->v.movetype == MOVETYPE_PUSH || check->v.movetype == MOVETYPE_NONE || check->v.movetype == MOVETYPE_FOLLOW // Nehahra || 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] >= 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] ) 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++; // only check for types that can block if (pusher->v.solid == SOLID_BSP // everything that blocks: bsp models, map brushes, doors, plats etc. || pusher->v.solid == SOLID_BBOX // normally boxes || pusher->v.solid == SOLID_SLIDEBOX) // normally monsters { // store out the previous solid value because we're going to change it next float savepushervsolid = pusher->v.solid; // try moving the contacted entity pusher->v.solid = SOLID_NOT; SV_PushEntity (check, move); // restore from the stored solid pusher->v.solid = savepushervsolid; // if it is still inside the pusher, block block = SV_TestEntityPosition (check); } else { // not blocked block = NULL; } if (block) { // 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 for (i=0 ; i<num_moved ; i++) { VectorCopy (moved_from[i], moved_edict[i]->v.origin); SV_LinkEdict (moved_edict[i], false); } return; } } }
/* ============ SV_PushMove ============ */ void SV_PushMove (edict_t *pusher, float movetime) { int i, e; edict_t *check, *block; 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 solid_backup; //movetype_push error fix - Eradicator if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2]) { pusher->v.ltime += movetime; return; } for (i=0 ; i<3 ; i++) { move[i] = pusher->v.velocity[i] * movetime; mins[i] = pusher->v.absmin[i] + move[i]; maxs[i] = pusher->v.absmax[i] + move[i]; } VectorCopy (pusher->v.origin, pushorig); // move the pusher to it's final position VectorAdd (pusher->v.origin, move, pusher->v.origin); 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 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check)) { if (check->free) continue; if (check->v.movetype == MOVETYPE_PUSH || check->v.movetype == MOVETYPE_NONE #ifdef QUAKE2 || check->v.movetype == MOVETYPE_FOLLOW #endif || 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] >= 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] ) 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++; //START - movetype_push error fix - Eradicator solid_backup = pusher->v.solid; if ( solid_backup == SOLID_BSP || solid_backup == SOLID_BBOX || solid_backup == SOLID_SLIDEBOX ) { //END - movetype_push error fix - Eradicator // try moving the contacted entity pusher->v.solid = SOLID_NOT; SV_PushEntity (check, move); //pusher->v.solid = SOLID_BSP; //Old pusher->v.solid = solid_backup; //movetype_push error fix - Eradicator // if it is still inside the pusher, block block = SV_TestEntityPosition (check); } //movetype_push error fix - Eradicator else block = NULL; if (block) { // 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 = ((int)EDICT_TO_PROG(pusher)); pr_global_struct->other = ((int)EDICT_TO_PROG(check)); PR_ExecuteProgram (pusher->v.blocked); } // move back any entities we already moved for (i=0 ; i<num_moved ; i++) { VectorCopy (moved_from[i], moved_edict[i]->v.origin); SV_LinkEdict (moved_edict[i], false); } return; } } }
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); 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) return; if ( (int)sv_player->v.flags & FL_WATERJUMP ) return; VectorCopy (ent->v.origin, nosteporg); VectorCopy (ent->v.velocity, nostepvel); // // try moving up and forward to go up a step // VectorCopy (oldorg, ent->v.origin); // back to start pos VectorCopy (vec3_origin, upmove); VectorCopy (vec3_origin, downmove); upmove[2] = STEPSIZE; downmove[2] = -STEPSIZE + oldvel[2]*host_frametime; // move up SV_PushEntity (ent, upmove); // 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); // check for stuckness, possibly due to the limited precision of floats // in the clipping hulls if (clip) { 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); } } // extra friction based on view angle if ( clip & 2 ) SV_WallFriction (ent, &steptrace); // move down downtrace = SV_PushEntity (ent, downmove); // FIXME: don't link? if (downtrace.plane.normal[2] > 0.7) { if (ent->v.solid == SOLID_BSP) { ent->v.flags = (int)ent->v.flags | FL_ONGROUND; ent->v.groundentity = ((int)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); } }
/* ============= SV_Physics_Toss Toss, bounce, and fly movement. When onground, do nothing. ============= */ void SV_Physics_Toss( edict_t *ent ) { trace_t trace; vec3_t move; float backoff; edict_t *ground; SV_CheckWater( ent ); // regular thinking if( !SV_RunThink( ent )) return; ground = ent->v.groundentity; if( ent->v.velocity[2] > 0.0f || !SV_IsValidEdict( ground ) || ground->v.flags & (FL_MONSTER|FL_CLIENT) || svgame.globals->changelevel ) { ent->v.flags &= ~FL_ONGROUND; } // if on ground and not moving, return. if( ent->v.flags & FL_ONGROUND && VectorIsNull( ent->v.velocity )) { VectorClear( ent->v.avelocity ); if( VectorIsNull( ent->v.basevelocity )) return; // at rest } SV_CheckVelocity( ent ); // add gravity switch( ent->v.movetype ) { case MOVETYPE_FLY: case MOVETYPE_FLYMISSILE: case MOVETYPE_BOUNCEMISSILE: break; default: SV_AddGravity( ent ); break; } // move angles (with friction) switch( ent->v.movetype ) { case MOVETYPE_TOSS: case MOVETYPE_BOUNCE: SV_AngularMove( ent, host.frametime, ent->v.friction ); break; default: SV_AngularMove( ent, host.frametime, 0.0f ); break; } // move origin // Base velocity is not properly accounted for since this entity will move again // after the bounce without taking it into account VectorAdd( ent->v.velocity, ent->v.basevelocity, ent->v.velocity ); SV_CheckVelocity( ent ); VectorScale( ent->v.velocity, host.frametime, move ); VectorSubtract( ent->v.velocity, ent->v.basevelocity, ent->v.velocity ); trace = SV_PushEntity( ent, move, vec3_origin, NULL ); if( ent->free ) return; SV_CheckVelocity( ent ); if( trace.allsolid ) { // entity is trapped in another solid VectorClear( ent->v.avelocity ); VectorClear( ent->v.velocity ); return; } if( trace.fraction == 1.0f ) { SV_CheckWaterTransition( ent ); return; } if( ent->v.movetype == MOVETYPE_BOUNCE ) backoff = 2.0f - ent->v.friction; else if( ent->v.movetype == MOVETYPE_BOUNCEMISSILE ) backoff = 2.0f; else backoff = 1.0f; SV_ClipVelocity( ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff ); // stop if on ground if( trace.plane.normal[2] > 0.7f ) { float vel; VectorAdd( ent->v.velocity, ent->v.basevelocity, move ); vel = DotProduct( move, move ); if( ent->v.velocity[2] < sv_gravity->value * host.frametime ) { // we're rolling on the ground, add static friction. ent->v.groundentity = trace.ent; ent->v.flags |= FL_ONGROUND; ent->v.velocity[2] = 0.0f; } if( vel < 900.0f || ( ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE )) { ent->v.flags |= FL_ONGROUND; ent->v.groundentity = trace.ent; VectorClear( ent->v.avelocity ); VectorClear( ent->v.velocity ); } else { VectorScale( ent->v.velocity, (1.0f - trace.fraction) * host.frametime * 0.9f, move ); VectorMA( move, (1.0f - trace.fraction) * host.frametime * 0.9f, ent->v.basevelocity, move ); trace = SV_PushEntity( ent, move, vec3_origin, NULL ); if( ent->free ) return; } } // check for in water SV_CheckWaterTransition( ent ); }
/* ============ SV_PushMove ============ */ void SV_PushMove (edict_t *pusher, float movetime) { int i, e; edict_t *check, *block; vec3_t mins, maxs, move; vec3_t entorig, pushorig; int num_moved; // 2001-09-20 Configurable entity limits by Maddes start /* edict_t *moved_edict[MAX_EDICTS]; vec3_t moved_from[MAX_EDICTS]; */ // 2001-09-20 Configurable entity limits by Maddes end float solid_backup; // 1999-10-07 MOVETYPE_PUSH fix by LordHavoc/Maddes if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2]) { pusher->v.ltime += movetime; return; } // 2001-09-20 Configurable entity limits by Maddes start // FIXME: is this really necessary memset (moved_edict, 0, sv.max_edicts*sizeof(edict_t *)); memset (moved_from, 0, sv.max_edicts*sizeof(vec3_t)); // 2001-09-20 Configurable entity limits by Maddes end for (i=0 ; i<3 ; i++) { move[i] = pusher->v.velocity[i] * movetime; mins[i] = pusher->v.absmin[i] + move[i]; maxs[i] = pusher->v.absmax[i] + move[i]; } VectorCopy (pusher->v.origin, pushorig); // move the pusher to it's final position VectorAdd (pusher->v.origin, move, pusher->v.origin); 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 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check)) { if (check->free) 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] >= 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] ) 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++; // 1999-10-07 MOVETYPE_PUSH fix by LordHavoc/Maddes start solid_backup = pusher->v.solid; if ( solid_backup == SOLID_BSP // everything that blocks: bsp models==map brushes==doors,plats,etc. || solid_backup == SOLID_BBOX // normally boxes || solid_backup == SOLID_SLIDEBOX ) // normally monsters { // 1999-10-07 MOVETYPE_PUSH fix by LordHavoc/Maddes end // try moving the contacted entity pusher->v.solid = SOLID_NOT; SV_PushEntity (check, move); // 1999-10-07 MOVETYPE_PUSH fix by LordHavoc/Maddes start // pusher->v.solid = SOLID_BSP; pusher->v.solid = solid_backup; // 1999-10-07 MOVETYPE_PUSH fix by LordHavoc/Maddes end // if it is still inside the pusher, block // 1999-10-07 MOVETYPE_PUSH fix by LordHavoc/Maddes start block = SV_TestEntityPosition (check); } else block = NULL; // 1999-10-07 MOVETYPE_PUSH fix by LordHavoc/Maddes end if (block) { // 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 for (i=0 ; i<num_moved ; i++) { VectorCopy (moved_from[i], moved_edict[i]->v.origin); SV_LinkEdict (moved_edict[i], false); } return; } } }
void SV_Physics_Bounce (edict_t * ent) { trace_t trace; vec3_t move, planeVel, normalVel, temp; edict_t *slave; qboolean wasinwater; qboolean isinwater; vec3_t old_origin; float movetime; // regular thinking SV_RunThink (ent); if (!ent->inuse) return; // if not a team captain, so movement will be handled elsewhere if (ent->flags & FL_TEAMSLAVE) return; if (ent->velocity[2] > 0) ent->groundentity = NULL; // check for the groundentity going away if (ent->groundentity) if (!ent->groundentity->inuse) ent->groundentity = NULL; // if onground, return without moving if (ent->groundentity) return; VectorCopy (ent->s.origin, old_origin); SV_CheckVelocity (ent); // move angles VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles); // add gravity ent->velocity[2] -= ent->gravity * sv_gravity->value * FRAMETIME; movetime = FRAMETIME; while (movetime > 0) { // move origin VectorScale (ent->velocity, movetime, move); // do the move (checking to see if we hit anything) trace = SV_PushEntity (ent, move); // SV_PushEntity might have called touch() functions so its possible we disappeared if (!ent->inuse) return; // we hit something so calculate rebound velocity etc. if (trace.fraction < 1) { // find component of velocity in direction of normal VectorScale (trace.plane.normal, DotProduct (trace.plane.normal, ent->velocity), normalVel); // find component of velocity parallel to plane of impact VectorSubtract (ent->velocity, normalVel, planeVel); // apply friction (lose 25% of velocity parallel to impact plane) VectorScale (planeVel, 0.75, planeVel); // calculate final velocity (rebound with 60% of impact velocity) // negative since rebound causes direction reversal VectorMA (planeVel, -0.6, normalVel, ent->velocity); // stop if on ground // only consider stopping if impact plane is less than 45 degrees with respect to horizontal // arccos(0.7) ~ 45 degrees if (trace.plane.normal[2] > 0.7) { VectorCopy (ent->velocity, temp); // zero out z component (vertical) since we want to consider horizontal and vertical motion // separately temp[2] = 0; if ((VectorLength (temp) < 20) && (ent->velocity[2] < ent->gravity * sv_gravity->value * FRAMETIME * 1.5)) { ent->groundentity = trace.ent; ent->groundentity_linkcount = trace.ent->linkcount; VectorCopy (vec3_origin, ent->velocity); VectorCopy (vec3_origin, ent->avelocity); break; // stopped, so no further simulation is necessary } } } // remaining amount of FRAMETIME left to simulate movetime *= (1.0 - trace.fraction); } // check for water transition wasinwater = (ent->watertype & MASK_WATER); ent->watertype = gi.pointcontents (ent->s.origin); isinwater = ent->watertype & MASK_WATER; if (isinwater) ent->waterlevel = 1; else ent->waterlevel = 0; if (!wasinwater && isinwater) gi.positioned_sound (old_origin, g_edicts, CHAN_AUTO, gi.soundindex ("misc/h2ohit1.wav"), 1, 1, 0); else if (wasinwater && !isinwater) gi.positioned_sound (ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex ("misc/h2ohit1.wav"), 1, 1, 0); // move teamslaves for (slave = ent->teamchain; slave; slave = slave->teamchain) { VectorCopy (ent->s.origin, slave->s.origin); gi.linkentity (slave); } }
/* ============= SV_Physics_Toss Toss, bounce, and fly movement. When onground, do nothing. ============= */ void SV_Physics_Toss (edict_t *ent) { trace_t trace; vec3_t move; float backoff; edict_t *slave; qboolean wasinwater; qboolean isinwater; vec3_t old_origin; qboolean forcethrough = false; // regular thinking SV_RunThink (ent); // if not a team captain, so movement will be handled elsewhere if ( ent->flags & FL_TEAMSLAVE) return; if (ent->velocity[2] > 0) ent->groundentity = NULL; // check for the groundentity going away if (ent->groundentity) if (!ent->groundentity->inuse) ent->groundentity = NULL; // if onground, return without moving if (ent->groundentity) { V_TouchSolids(ent); return; } VectorCopy (ent->s.origin, old_origin); SV_CheckVelocity (ent); // add gravity if (ent->movetype != MOVETYPE_FLY && ent->movetype != MOVETYPE_FLYMISSILE && ent->movetype != MOVETYPE_SLIDE // RAFAEL // move type for rippergun projectile && ent->movetype != MOVETYPE_WALLBOUNCE) SV_AddGravity (ent); // move angles VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles); // move origin VectorScale (ent->velocity, FRAMETIME, move); if(ent->classname[0] == 'R' && (ent->classname[6] == 'X' || ent->classname[6] == '3')) { ent->groundentity = ent->union_ent; ent->groundentity_linkcount = ent->union_ent->linkcount; VectorCopy (ent->union_ent->velocity, ent->velocity); VectorCopy (ent->union_ent->avelocity, ent->avelocity); VectorAdd(ent->union_ent->s.origin,ent->moveinfo.dir,ent->s.origin); } trace = SV_PushEntity (ent, move); if (!ent->inuse) return; if (trace.fraction < 1 && !forcethrough) { // RAFAEL if (ent->movetype == MOVETYPE_WALLBOUNCE) backoff = 2.0; // RAFAEL ( else ) else if (ent->movetype == MOVETYPE_BOUNCE) backoff = 1.5; else backoff = 1; ClipVelocity (ent->velocity, trace.plane.normal, ent->velocity, backoff); // spikeball never stops bouncing if (ent->mtype == M_SPIKEBALL) { float delta = 275 - ent->velocity[2]; // don't get stuck on the ceiling if (trace.plane.normal[2] != -1.0) ent->velocity[2] += delta; // always bounce away from the wall VectorMA(ent->velocity, 100, trace.plane.normal, ent->velocity); } // RAFAEL if (ent->movetype == MOVETYPE_WALLBOUNCE) vectoangles (ent->velocity, ent->s.angles); // stop if on ground // RAFAEL //K03 Begin if (trace.plane.normal[2] > 0.95 && ent->movetype != MOVETYPE_WALLBOUNCE && ent->movetype != MOVETYPE_SLIDE)//was 0.7 { if (ent->velocity[2] < 30/*60*/ || ent->movetype != MOVETYPE_BOUNCE ) //K03 End { // gi.dprintf("SV_Physics_Toss() stopped the entity\n"); ent->groundentity = trace.ent; ent->groundentity_linkcount = trace.ent->linkcount; VectorCopy (vec3_origin, ent->velocity); VectorCopy (vec3_origin, ent->avelocity); } } // if (ent->touch) // ent->touch (ent, trace.ent, &trace.plane, trace.surface); } // check for water transition wasinwater = (ent->watertype & MASK_WATER); ent->watertype = gi.pointcontents (ent->s.origin); isinwater = ent->watertype & MASK_WATER; if (isinwater) ent->waterlevel = 1; else ent->waterlevel = 0; if (!wasinwater && isinwater) gi.positioned_sound (old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); else if (wasinwater && !isinwater) gi.positioned_sound (ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); // move teamslaves for (slave = ent->teamchain; slave; slave = slave->teamchain) { VectorCopy (ent->s.origin, slave->s.origin); gi.linkentity (slave); } }
/* ============= SV_Physics_Toss Toss, bounce, and fly movement. When onground, do nothing. ============= */ void SV_Physics_Toss (edict_t *ent) { trace_t trace; vec3_t move; float backoff; edict_t *slave; qboolean wasinwater; qboolean isinwater; vec3_t old_origin; if (!ent) { return; } /* regular thinking */ SV_RunThink(ent); /* if not a team captain, so movement will be handled elsewhere */ if (ent->flags & FL_TEAMSLAVE) { return; } if (ent->velocity[2] > 0) { ent->groundentity = NULL; } /* check for the groundentity going away */ if (ent->groundentity) { if (!ent->groundentity->inuse) { ent->groundentity = NULL; } } /* if onground, return without moving */ if (ent->groundentity) { return; } VectorCopy(ent->s.origin, old_origin); SV_CheckVelocity(ent); /* add gravity */ if ((ent->movetype != MOVETYPE_FLY) && (ent->movetype != MOVETYPE_FLYMISSILE) && (ent->movetype != MOVETYPE_WALLBOUNCE)) { SV_AddGravity(ent); } /* move angles */ VectorMA(ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles); /* move origin */ VectorScale(ent->velocity, FRAMETIME, move); trace = SV_PushEntity(ent, move); if (!ent->inuse) { return; } if (trace.fraction < 1) { if (ent->movetype == MOVETYPE_WALLBOUNCE) { backoff = 2.0; } else if (ent->movetype == MOVETYPE_BOUNCE) { backoff = 1.5; } else { backoff = 1; } ClipVelocity(ent->velocity, trace.plane.normal, ent->velocity, backoff); if (ent->movetype == MOVETYPE_WALLBOUNCE) { vectoangles(ent->velocity, ent->s.angles); } /* stop if on ground */ if ((trace.plane.normal[2] > 0.7) && (ent->movetype != MOVETYPE_WALLBOUNCE)) { if ((ent->velocity[2] < 60) || (ent->movetype != MOVETYPE_BOUNCE)) { ent->groundentity = trace.ent; ent->groundentity_linkcount = trace.ent->linkcount; VectorCopy(vec3_origin, ent->velocity); VectorCopy(vec3_origin, ent->avelocity); } } } /* check for water transition */ wasinwater = (ent->watertype & MASK_WATER); ent->watertype = gi.pointcontents(ent->s.origin); isinwater = ent->watertype & MASK_WATER; if (isinwater) { ent->waterlevel = 1; } else { ent->waterlevel = 0; } if (!wasinwater && isinwater) { gi.positioned_sound(old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); } else if (wasinwater && !isinwater) { gi.positioned_sound(ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); } /* move teamslaves */ for (slave = ent->teamchain; slave; slave = slave->teamchain) { VectorCopy(ent->s.origin, slave->s.origin); gi.linkentity(slave); } }
/* ============ SV_PushRotate ============ */ void SV_PushRotate (edict_t *pusher, float movetime) { int i, e, t, num_moved, slaves_moved; edict_t *check, *block, *ground, *master, *slave; edict_t *moved_edict[MAX_EDICTS]; vec3_t moved_from[MAX_EDICTS]; vec3_t move, a, amove, mins, maxs, move2, move3, testmove; vec3_t entorig, pushorig, pushorigangles; vec3_t org, org2, check_center; vec3_t forward, right, up; qboolean moveit; for (i=0 ; i<3 ; i++) { amove[i] = pusher->v.avelocity[i] * movetime; move[i] = pusher->v.velocity[i] * movetime; mins[i] = pusher->v.absmin[i] + move[i]; maxs[i] = pusher->v.absmax[i] + move[i]; } VectorSubtract (vec3_origin, amove, a); AngleVectors (a, forward, right, up); VectorCopy (pusher->v.origin, pushorig); VectorCopy (pusher->v.angles, pushorigangles); // move the pusher to it's final position VectorAdd (pusher->v.origin, move, pusher->v.origin); VectorAdd (pusher->v.angles, amove, pusher->v.angles); pusher->v.ltime += movetime; SV_LinkEdict (pusher, false); master = pusher; slaves_moved = 0; // 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) 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 definitely be moved moveit = false; ground = PROG_TO_EDICT(check->v.groundentity); if ((int)check->v.flags & FL_ONGROUND) { if (ground == pusher) { moveit = true; } else { for (i=0; i<slaves_moved; i++) { if (ground == moved_edict[MAX_EDICTS - i - 1]) { moveit = true; break; } } } } if (!moveit) { 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] ) { for (i=0; i<slaves_moved; i++) { slave = moved_edict[MAX_EDICTS - i - 1]; if ( check->v.absmin[0] >= slave->v.absmax[0] || check->v.absmin[1] >= slave->v.absmax[1] || check->v.absmin[2] >= slave->v.absmax[2] || check->v.absmax[0] <= slave->v.absmin[0] || check->v.absmax[1] <= slave->v.absmin[1] || check->v.absmax[2] <= slave->v.absmin[2] ) continue; } if (i == slaves_moved) 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++; //put check in first move spot VectorAdd (check->v.origin, move, check->v.origin); //Use center of model, like in QUAKE!!!! Our origins are on the bottom!!! for (i=0 ; i<3 ; i++) check_center[i] = (check->v.absmin[i] + check->v.absmax[i])/2; // calculate destination position VectorSubtract (check_center, pusher->v.origin, org); //put check back VectorSubtract (check->v.origin, move, check->v.origin); org2[0] = DotProduct (org, forward); org2[1] = -DotProduct (org, right); org2[2] = DotProduct (org, up); VectorSubtract (org2, org, move2); //Add all moves together VectorAdd(move,move2,move3); // try moving the contacted entity for( t = 0; t < 13; t++) { switch(t) { case 0: //try x, y and z VectorCopy(move3,testmove); break; case 1: //Try xy only VectorSubtract(check->v.origin,testmove,check->v.origin); testmove[0]=move3[0]; testmove[1]=move3[1]; testmove[2]=0; break; case 2: //Try z only VectorSubtract(check->v.origin,testmove,check->v.origin); testmove[0]=0; testmove[1]=0; testmove[2]=move3[2]; break; case 3: //Try none VectorSubtract(check->v.origin,testmove,check->v.origin); testmove[0]=0; testmove[1]=0; testmove[2]=0; break; case 4: //Try xy in opposite dir testmove[0]=move3[0]*-1; testmove[1]=move3[1]*-1; testmove[2]=move3[2]; break; case 5: //Try z in opposite dir VectorSubtract(check->v.origin,testmove,check->v.origin); testmove[0]=move3[0]; testmove[1]=move3[1]; testmove[2]=move3[2]*-1; break; case 6: //Try xyz in opposite dir VectorSubtract(check->v.origin,testmove,check->v.origin); testmove[0]=move3[0]*-1; testmove[1]=move3[1]*-1; testmove[2]=move3[2]*-1; break; case 7: //Try move3 times 2 VectorSubtract(check->v.origin,testmove,check->v.origin); VectorScale(move3,2,testmove); break; case 8: //Try normalized org VectorSubtract(check->v.origin,testmove,check->v.origin); VectorScale(org,movetime,org);//movetime*20? VectorCopy(org,testmove); break; case 9: //Try normalized org z * 3 only VectorSubtract(check->v.origin,testmove,check->v.origin); testmove[0]=0; testmove[1]=0; testmove[2]=org[2]*3;//was: +org[2]*(fastfabs(org[1])+fastfabs(org[2])); break; case 10: //Try normalized org xy * 2 only VectorSubtract(check->v.origin,testmove,check->v.origin); testmove[0]=org[0]*2;//was: +org[0]*fastfabs(org[2]); testmove[1]=org[1]*2;//was: +org[1]*fastfabs(org[2]); testmove[2]=0; break; case 11: //Try xy in opposite org dir VectorSubtract(check->v.origin,testmove,check->v.origin); testmove[0]=org[0]*-2; testmove[1]=org[1]*-2; testmove[2]=org[2]; break; case 12: //Try z in opposite dir VectorSubtract(check->v.origin,testmove,check->v.origin); testmove[0]=org[0]; testmove[1]=org[1]; testmove[2]=org[2]*-3; break; } if(t!=3) { //THIS IS VERY BAD BAD HACK... pusher->v.solid = SOLID_NOT; SV_PushEntity (check, move3); //@@TODO: do we ever want to do anybody's angles? maybe just yaw??? // if (!((int)check->v.flags & (FL_CLIENT | FL_MONSTER))) // VectorAdd (check->v.angles, amove, check->v.angles); check->v.angles[YAW] += amove[YAW]; pusher->v.solid = SOLID_BSP; } // if it is still inside the pusher, block block = SV_TestEntityPosition (check); if(!block) break; } if (block) { // fail the move // Con_DPrintf("Check blocked\n"); 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); VectorCopy (pushorigangles, pusher->v.angles); SV_LinkEdict (pusher, false); pusher->v.ltime -= movetime; for (i=0; i<slaves_moved; i++) { slave = moved_edict[MAX_EDICTS - i - 1]; VectorCopy (moved_from[MAX_EDICTS - i - 1], slave->v.angles); SV_LinkEdict (slave, false); slave->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_ptrs.self = EDICT_TO_PROG(pusher); *pr_global_ptrs.other = EDICT_TO_PROG(check); PR_ExecuteProgram (pusher->v.blocked); } // move back any entities we already moved for (i=0 ; i<num_moved ; i++) { VectorCopy (moved_from[i], moved_edict[i]->v.origin); //@@TODO:: see above // if (!((int)moved_edict[i]->v.flags & (FL_CLIENT | FL_MONSTER))) // VectorSubtract (moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles); moved_edict[i]->v.angles[YAW] -= amove[YAW]; SV_LinkEdict (moved_edict[i], false); } return; } } }
/* ============= SV_Physics_Toss Toss, bounce, and fly movement. When onground, do nothing. ============= */ void SV_Physics_Toss (edict_t *ent) { trace_t trace; vec3_t move; float backoff; // regular thinking if (!SV_RunThink (ent)) return; // if onground, return without moving if (((int)ent->v.flags & FL_ONGROUND)) return; SV_CheckVelocity (ent); // add gravity if (ent->v.movetype != MOVETYPE_FLY && ent->v.movetype != MOVETYPE_FLYMISSILE) #ifdef HEXEN2_SUPPORT if ( (!hexen2) || (ent->v.movetype != MOVETYPE_BOUNCEMISSILE && ent->v.movetype != MOVETYPE_SWIM)) #endif SV_AddGravity (ent); // move anglesy VectorMA (ent->v.angles, host_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; if (ent->free) return; if (ent->v.movetype == MOVETYPE_BOUNCE) backoff = 1.5; #ifdef HEXEN2_SUPPORT else if (hexen2 && (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)) { if ((ent->v.solid == SOLID_PHASE) && (((int) trace.ent->v.flags & FL_MONSTER) || ((int) trace.ent->v.movetype == MOVETYPE_WALK))) { return; // Solid phased missiles don't bounce on monsters or players } backoff = 2.0; } #endif 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) { #ifdef HEXEN2_SUPPORT if ((!hexen2) || (ent->v.movetype != MOVETYPE_BOUNCEMISSILE)) #endif if (ent->v.velocity[2] < 60 || ent->v.movetype != MOVETYPE_BOUNCE) { 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); } } // check for in water SV_CheckWaterTransition (ent); }
/* ============= SV_Physics_Toss Toss, bounce, and fly movement. When onground, do nothing. ============= */ void SV_Physics_Toss (edict_t *ent) { trace_t trace; vec3_t move; float backoff; edict_t *slave; qboolean wasinwater; qboolean isinwater; vec3_t old_origin; // regular thinking SV_RunThink (ent); // if not a team captain, so movement will be handled elsewhere if ( ent->flags & FL_TEAMSLAVE) return; if (ent->velocity[2] > 0) ent->groundentity = NULL; // check for the groundentity going away if (ent->groundentity) if (!ent->groundentity->inuse) ent->groundentity = NULL; // if onground, return without moving if ( ent->groundentity && ent->movetype != MOVETYPE_TOSS_SLIDE ) { // JOSEPH 7-OCT-98 if (ent->fallerflag) { // JOSEPH 22-JAN-99 // If the object just hit the floor if (ent->fallingflag) { ent->fallingflag = 0; if (!strcmp(ent->classname, "props_trashcanA")) { gi.sound (ent, CHAN_AUTO, gi.soundindex ("world/trash2.wav"), 1, ATTN_NORM, 0); } else if (!strcmp(ent->classname, "props_crate")) { gi.sound (ent, CHAN_AUTO, gi.soundindex ("world/crate2.wav"), 1, ATTN_NORM, 0); } } // END JOSEPH // Fix if sitting off center ent->movetype = MOVETYPE_STEP; think_checkedges(ent); } // END JOSEPH return; } VectorCopy (ent->s.origin, old_origin); SV_CheckVelocity (ent); // add gravity if (ent->movetype != MOVETYPE_FLY && ent->movetype != MOVETYPE_FLYMISSILE) SV_AddGravity (ent); // move angles VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles); // move origin VectorScale (ent->velocity, FRAMETIME, move); trace = SV_PushEntity (ent, move); if (!ent->inuse) return; if (trace.fraction < 1) { // RAFAEL if (ent->movetype == MOVETYPE_WALLBOUNCE) backoff = 2.0; // RAFAEL ( else ) else if (ent->movetype == MOVETYPE_BOUNCE) backoff = 1.5; // Ridah, testing else if (ent->velocity[2] > -120) backoff = 1; else backoff = 1.3; ClipVelocity (ent->velocity, trace.plane.normal, ent->velocity, backoff); // RAFAEL if (ent->movetype == MOVETYPE_WALLBOUNCE) vectoangles (ent->velocity, ent->s.angles); // stop if on ground // RAFAEL if (trace.plane.normal[2] > 0.7 && ent->movetype != MOVETYPE_WALLBOUNCE && ent->movetype != MOVETYPE_TOSS_SLIDE) // Ridah, testing { if (ent->velocity[2] < 60 || ent->movetype != MOVETYPE_BOUNCE ) { ent->groundentity = trace.ent; ent->groundentity_linkcount = trace.ent->linkcount; VectorCopy (vec3_origin, ent->velocity); VectorCopy (vec3_origin, ent->avelocity); } } // Ridah, testing if (trace.plane.normal[2] > 0.0 && ent->movetype == MOVETYPE_TOSS_SLIDE) // Ridah, testing { VectorMA( ent->velocity, -0.07, ent->velocity, ent->velocity ); // add some friction ent->velocity[2] += ent->gravity * sv_gravity->value * FRAMETIME * trace.plane.normal[2]; if (trace.fraction <= 0.1) { float oldpitch; oldpitch = ent->s.angles[PITCH]; vectoangles (ent->velocity, ent->s.angles); ent->s.angles[PITCH] = oldpitch; VectorCopy (vec3_origin, ent->avelocity); ent->avelocity[PITCH] = -300 * VectorLength(ent->velocity)/800; // roll in direction we're going SV_Physics_Toss(ent); return; } } // if (ent->touch) // ent->touch (ent, trace.ent, &trace.plane, trace.surface); } // check for water transition wasinwater = (ent->watertype & MASK_WATER); ent->watertype = gi.pointcontents (ent->s.origin); isinwater = ent->watertype & MASK_WATER; if (isinwater) ent->waterlevel = 1; else ent->waterlevel = 0; // JOSEPH 13-MAY-99 /*if (!wasinwater && isinwater) gi.positioned_sound (old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); else if (wasinwater && !isinwater) gi.positioned_sound (ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);*/ // END JOSEPH // move teamslaves for (slave = ent->teamchain; slave; slave = slave->teamchain) { VectorCopy (ent->s.origin, slave->s.origin); gi.linkentity (slave); } }
/* ============= SV_Physics_Toss Toss, bounce, and fly movement. When onground, do nothing. ============= */ void SV_Physics_Toss (edict_t *ent) { trace_t trace; vec3_t move; float backoff; edict_t *slave; qboolean wasinwater; qboolean isinwater; vec3_t old_origin; // regular thinking SV_RunThink (ent); // if not a team captain, so movement will be handled elsewhere if ( ent->flags & FL_TEAMSLAVE) return; if (ent->velocity[2] > 0) ent->groundentity = NULL; // check for the groundentity going away if (ent->groundentity) if (!ent->groundentity->inuse) ent->groundentity = NULL; // if onground, return without moving if ( ent->groundentity && ent->gravity > 0.0) // PGM - gravity hack return; VectorCopy (ent->s.origin, old_origin); SV_CheckVelocity (ent); // add gravity if (ent->movetype != MOVETYPE_FLY && ent->movetype != MOVETYPE_FLYMISSILE) SV_AddGravity (ent); // move angles VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles); // move origin VectorScale (ent->velocity, FRAMETIME, move); trace = SV_PushEntity (ent, move); if (!ent->inuse) return; if (trace.fraction < 1) { if (ent->movetype == MOVETYPE_BOUNCE) backoff = 1.5; else backoff = 1; ClipVelocity (ent->velocity, trace.plane.normal, ent->velocity, backoff); // stop if on ground if (trace.plane.normal[2] > 0.7) { if (ent->velocity[2] < 60 || ent->movetype != MOVETYPE_BOUNCE ) { ent->groundentity = trace.ent; ent->groundentity_linkcount = trace.ent->linkcount; VectorCopy (vec3_origin, ent->velocity); VectorCopy (vec3_origin, ent->avelocity); } } // if (ent->touch) // ent->touch (ent, trace.ent, &trace.plane, trace.surface); } // check for water transition wasinwater = (ent->watertype & MASK_WATER); ent->watertype = gi.pointcontents (ent->s.origin); isinwater = ent->watertype & MASK_WATER; if (isinwater) ent->waterlevel = 1; else ent->waterlevel = 0; if (!wasinwater && isinwater) gi.positioned_sound (old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); else if (wasinwater && !isinwater) gi.positioned_sound (ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); // move teamslaves for (slave = ent->teamchain; slave; slave = slave->teamchain) { VectorCopy (ent->s.origin, slave->s.origin); gi.linkentity (slave); } }
/* ============ SV_PushMove ============ */ static edict_t *SV_PushMove( edict_t *pusher, float movetime ) { int i, e, block; int num_moved, oldsolid; vec3_t mins, maxs, lmove; sv_pushed_t *p, *pushed_p; edict_t *check; if( svgame.globals->changelevel || VectorIsNull( pusher->v.velocity )) { pusher->v.ltime += movetime; return NULL; } for( i = 0; i < 3; i++ ) { lmove[i] = pusher->v.velocity[i] * movetime; mins[i] = pusher->v.absmin[i] + lmove[i]; maxs[i] = pusher->v.absmax[i] + lmove[i]; } pushed_p = svgame.pushed; // save the pusher's original position pushed_p->ent = pusher; VectorCopy( pusher->v.origin, pushed_p->origin ); VectorCopy( pusher->v.angles, pushed_p->angles ); pushed_p++; // move the pusher to it's final position SV_LinearMove( pusher, movetime, 0.0f ); SV_LinkEdict( pusher, false ); pusher->v.ltime += movetime; oldsolid = pusher->v.solid; // non-solid pushers can't push anything if( pusher->v.solid == SOLID_NOT ) return NULL; // see if any solid entities are inside the final position num_moved = 0; for( e = 1; e < svgame.numEntities; e++ ) { check = EDICT_NUM( e ); if( !SV_IsValidEdict( check )) continue; // filter movetypes to collide with if( !SV_CanPushed( check )) continue; pusher->v.solid = SOLID_NOT; block = SV_TestEntityPosition( check, pusher ); pusher->v.solid = oldsolid; if( block ) continue; // if the entity is standing on the pusher, it will definately be moved if( !(( check->v.flags & FL_ONGROUND ) && 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] ) continue; // see if the ent's bbox is inside the pusher's final position if( !SV_TestEntityPosition( check, NULL )) continue; } // remove the onground flag for non-players if( check->v.movetype != MOVETYPE_WALK ) check->v.flags &= ~FL_ONGROUND; // save original position of contacted entity pushed_p->ent = check; VectorCopy( check->v.origin, pushed_p->origin ); VectorCopy( check->v.angles, pushed_p->angles ); pushed_p++; // try moving the contacted entity pusher->v.solid = SOLID_NOT; SV_PushEntity( check, lmove, vec3_origin, &block ); pusher->v.solid = oldsolid; // if it is still inside the pusher, block if( SV_TestEntityPosition( check, NULL ) && block ) { if( !SV_CanBlock( check )) continue; pusher->v.ltime -= movetime; // move back any entities we already moved // go backwards, so if the same entity was pushed // twice, it goes back to the original position for( p = pushed_p - 1; p >= svgame.pushed; p-- ) { VectorCopy( p->origin, p->ent->v.origin ); VectorCopy( p->angles, p->ent->v.angles ); SV_LinkEdict( p->ent, (p->ent == check) ? true : false ); } return check; } } return NULL; }
/* ============= SV_Physics_Toss Toss, bounce, and fly movement. When onground, do nothing. ============= */ void SV_Physics_Toss (edict_t *ent) { trace_t trace; vec3_t move; float backoff; #ifdef QUAKE2 edict_t *groundentity; groundentity = PROG_TO_EDICT(ent->v.groundentity); if ((int)groundentity->v.flags & FL_CONVEYOR) VectorScale(groundentity->v.movedir, groundentity->v.speed, ent->v.basevelocity); else VectorCopy(vec_origin, ent->v.basevelocity); SV_CheckWater (ent); #endif // regular thinking if (!SV_RunThink (ent)) return; #ifdef QUAKE2 if (ent->v.velocity[2] > 0) ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND; if ( ((int)ent->v.flags & FL_ONGROUND) ) //@@ if (VectorCompare(ent->v.basevelocity, vec_origin)) return; SV_CheckVelocity (ent); // add gravity if (! ((int)ent->v.flags & FL_ONGROUND) && ent->v.movetype != MOVETYPE_FLY && ent->v.movetype != MOVETYPE_BOUNCEMISSILE && ent->v.movetype != MOVETYPE_FLYMISSILE) SV_AddGravity (ent); #else // if onground, return without moving if ( ((int)ent->v.flags & FL_ONGROUND) ) return; SV_CheckVelocity (ent); // add gravity if (ent->v.movetype != MOVETYPE_FLY && ent->v.movetype != MOVETYPE_FLYMISSILE) SV_AddGravity (ent); #endif // move angles VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles); // move origin #ifdef QUAKE2 VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity); #endif VectorScale (ent->v.velocity, host_frametime, move); trace = SV_PushEntity (ent, move); #ifdef QUAKE2 VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity); #endif if (trace.fraction == 1) return; if (ent->free) return; if (ent->v.movetype == MOVETYPE_BOUNCE) backoff = 1.5; #ifdef QUAKE2 else if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE) backoff = 2.0; #endif 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) { #ifdef QUAKE2 if (ent->v.velocity[2] < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE)) #else if (ent->v.velocity[2] < 60 || ent->v.movetype != MOVETYPE_BOUNCE) #endif { ent->v.flags = (int)ent->v.flags | FL_ONGROUND; ent->v.groundentity = ((int)EDICT_TO_PROG(trace.ent)); VectorCopy (vec3_origin, ent->v.velocity); VectorCopy (vec3_origin, ent->v.avelocity); } } // check for in water SV_CheckWaterTransition (ent); }
/* ============ SV_PushRotate ============ */ static edict_t *SV_PushRotate( edict_t *pusher, float movetime ) { int i, e, block, oldsolid; matrix4x4 start_l, end_l; vec3_t lmove, amove; sv_pushed_t *p, *pushed_p; vec3_t org, org2, temp; edict_t *check; if( svgame.globals->changelevel || VectorIsNull( pusher->v.avelocity )) { pusher->v.ltime += movetime; return NULL; } for( i = 0; i < 3; i++ ) amove[i] = pusher->v.avelocity[i] * movetime; // create pusher initial position Matrix4x4_CreateFromEntity( start_l, pusher->v.angles, pusher->v.origin, 1.0f ); pushed_p = svgame.pushed; // save the pusher's original position pushed_p->ent = pusher; VectorCopy( pusher->v.origin, pushed_p->origin ); VectorCopy( pusher->v.angles, pushed_p->angles ); pushed_p++; // move the pusher to it's final position SV_AngularMove( pusher, movetime, pusher->v.friction ); SV_LinkEdict( pusher, false ); pusher->v.ltime += movetime; oldsolid = pusher->v.solid; // non-solid pushers can't push anything if( pusher->v.solid == SOLID_NOT ) return NULL; // create pusher final position Matrix4x4_CreateFromEntity( end_l, pusher->v.angles, pusher->v.origin, 1.0f ); // see if any solid entities are inside the final position for( e = 1; e < svgame.numEntities; e++ ) { check = EDICT_NUM( e ); if( !SV_IsValidEdict( check )) continue; // filter movetypes to collide with if( !SV_CanPushed( check )) continue; pusher->v.solid = SOLID_NOT; block = SV_TestEntityPosition( check, pusher ); pusher->v.solid = oldsolid; if( block ) continue; // if the entity is standing on the pusher, it will definately be moved if( !(( check->v.flags & FL_ONGROUND ) && 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, NULL )) continue; } // save original position of contacted entity pushed_p->ent = check; VectorCopy( check->v.origin, pushed_p->origin ); VectorCopy( check->v.angles, pushed_p->angles ); pushed_p->fixangle = check->v.fixangle; pushed_p++; // calculate destination position if( check->v.movetype == MOVETYPE_PUSHSTEP || check->v.movetype == MOVETYPE_STEP ) VectorAverage( check->v.absmin, check->v.absmax, org ); else VectorCopy( check->v.origin, org ); Matrix4x4_VectorITransform( start_l, org, temp ); Matrix4x4_VectorTransform( end_l, temp, org2 ); VectorSubtract( org2, org, lmove ); // i can't clear FL_ONGROUND in all cases because many bad things may be happen if( check->v.movetype != MOVETYPE_WALK ) { if( lmove[2] != 0.0f ) check->v.flags &= ~FL_ONGROUND; if( lmove[2] < 0.0f && !pusher->v.dmg ) lmove[2] = 0.0f; // let's the free falling } // try moving the contacted entity pusher->v.solid = SOLID_NOT; SV_PushEntity( check, lmove, amove, &block ); pusher->v.solid = oldsolid; // pushed entity blocked by wall if( block && check->v.movetype != MOVETYPE_WALK ) check->v.flags &= ~FL_ONGROUND; // if it is still inside the pusher, block if( SV_TestEntityPosition( check, NULL ) && block ) { if( !SV_CanBlock( check )) continue; pusher->v.ltime -= movetime; // move back any entities we already moved // go backwards, so if the same entity was pushed // twice, it goes back to the original position for( p = pushed_p - 1; p >= svgame.pushed; p-- ) { VectorCopy( p->origin, p->ent->v.origin ); VectorCopy( p->angles, p->ent->v.angles ); SV_LinkEdict( p->ent, (p->ent == check) ? true : false ); p->ent->v.fixangle = p->fixangle; } return check; } } return NULL; }
/* ============ SV_PushRotate ============ */ void SV_PushRotate (edict_t *pusher, float movetime) { int i, e; edict_t *check, *block; vec3_t move, a, amove; vec3_t entorig, pushorig; int num_moved; edict_t *moved_edict[MAX_EDICTS]; vec3_t moved_from[MAX_EDICTS]; vec3_t org, org2; vec3_t forward, right, up; 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.angles, pushorig); // 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 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check)) { if (check->free) continue; if (check->v.movetype == MOVETYPE_PUSH || check->v.movetype == MOVETYPE_NONE #ifdef QUAKE2 || check->v.movetype == MOVETYPE_FOLLOW #endif || 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, entorig); VectorCopy (check->v.origin, moved_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 pusher->v.solid = SOLID_NOT; SV_PushEntity (check, move); pusher->v.solid = SOLID_BSP; // if it is still inside the pusher, block block = SV_TestEntityPosition (check); if (block) { // 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.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 = ((int)EDICT_TO_PROG(pusher)); pr_global_struct->other = ((int)EDICT_TO_PROG(check)); PR_ExecuteProgram (pusher->v.blocked); } // move back any entities we already moved for (i=0 ; i<num_moved ; i++) { VectorCopy (moved_from[i], moved_edict[i]->v.origin); VectorSubtract (moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles); SV_LinkEdict (moved_edict[i], false); } return; } else { VectorAdd (check->v.angles, amove, check->v.angles); } } }
/* * SV_Physics_Toss * * Toss, bounce, and fly movement. When onground, do nothing. * * FIXME: This function needs a serious rewrite */ static void SV_Physics_Toss( edict_t *ent ) { trace_t trace; vec3_t move; float backoff; edict_t *slave; bool wasinwater; bool isinwater; vec3_t old_origin; float oldSpeed; // if not a team captain, so movement will be handled elsewhere if( ent->flags & FL_TEAMSLAVE ) { return; } // refresh the ground entity if( ent->movetype == MOVETYPE_BOUNCE || ent->movetype == MOVETYPE_BOUNCEGRENADE ) { if( ent->velocity[2] > 0.1f ) { ent->groundentity = NULL; } } if( ent->groundentity && ent->groundentity != world && !ent->groundentity->r.inuse ) { ent->groundentity = NULL; } oldSpeed = VectorLength( ent->velocity ); if( ent->groundentity ) { if( !oldSpeed ) { return; } if( ent->movetype == MOVETYPE_TOSS ) { if( ent->velocity[2] >= 8 ) { ent->groundentity = NULL; } else { VectorClear( ent->velocity ); VectorClear( ent->avelocity ); G_CallStop( ent ); return; } } } VectorCopy( ent->s.origin, old_origin ); if( ent->accel != 0 ) { if( ent->accel < 0 && VectorLength( ent->velocity ) < 50 ) { VectorClear( ent->velocity ); } else { vec3_t acceldir; VectorNormalize2( ent->velocity, acceldir ); VectorScale( acceldir, ent->accel * FRAMETIME, acceldir ); VectorAdd( ent->velocity, acceldir, ent->velocity ); } } SV_CheckVelocity( ent ); // add gravity if( ent->movetype != MOVETYPE_FLY && !ent->groundentity ) { SV_AddGravity( ent ); } // move angles VectorMA( ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles ); // move origin VectorScale( ent->velocity, FRAMETIME, move ); trace = SV_PushEntity( ent, move ); if( !ent->r.inuse ) { return; } if( trace.fraction < 1.0f ) { if( ent->movetype == MOVETYPE_BOUNCE ) { backoff = 1.5; } else if( ent->movetype == MOVETYPE_BOUNCEGRENADE ) { backoff = 1.5; } else { backoff = 1; } GS_ClipVelocity( ent->velocity, trace.plane.normal, ent->velocity, backoff ); // stop if on ground if( ent->movetype == MOVETYPE_BOUNCE || ent->movetype == MOVETYPE_BOUNCEGRENADE ) { // stop dead on allsolid // LA: hopefully will fix grenades bouncing down slopes // method taken from Darkplaces sourcecode if( trace.allsolid || ( ISWALKABLEPLANE( &trace.plane ) && fabs( DotProduct( trace.plane.normal, ent->velocity ) ) < 40 ) ) { ent->groundentity = &game.edicts[trace.ent]; ent->groundentity_linkcount = ent->groundentity->linkcount; VectorClear( ent->velocity ); VectorClear( ent->avelocity ); G_CallStop( ent ); } } else { // in movetype_toss things stop dead when touching ground #if 0 G_CheckGround( ent ); if( ent->groundentity ) { #else // walkable or trapped inside solid brush if( trace.allsolid || ISWALKABLEPLANE( &trace.plane ) ) { ent->groundentity = trace.ent < 0 ? world : &game.edicts[trace.ent]; ent->groundentity_linkcount = ent->groundentity->linkcount; #endif VectorClear( ent->velocity ); VectorClear( ent->avelocity ); G_CallStop( ent ); } } } // check for water transition wasinwater = ( ent->watertype & MASK_WATER ) ? true : false; ent->watertype = G_PointContents( ent->s.origin ); isinwater = ent->watertype & MASK_WATER ? true : false; // never allow items in CONTENTS_NODROP if( ent->item && ( ent->watertype & CONTENTS_NODROP ) ) { G_FreeEdict( ent ); return; } if( isinwater ) { ent->waterlevel = 1; } else { ent->waterlevel = 0; } if( !wasinwater && isinwater ) { G_PositionedSound( old_origin, CHAN_AUTO, trap_SoundIndex( S_HIT_WATER ), ATTN_IDLE ); } else if( wasinwater && !isinwater ) { G_PositionedSound( ent->s.origin, CHAN_AUTO, trap_SoundIndex( S_HIT_WATER ), ATTN_IDLE ); } // move teamslaves for( slave = ent->teamchain; slave; slave = slave->teamchain ) { VectorCopy( ent->s.origin, slave->s.origin ); GClip_LinkEntity( slave ); } } //============================================================================ void SV_Physics_LinearProjectile( edict_t *ent ) { vec3_t start, end; int mask; float startFlyTime, endFlyTime; trace_t trace; int old_waterLevel; // if not a team captain movement will be handled elsewhere if( ent->flags & FL_TEAMSLAVE ) { return; } old_waterLevel = ent->waterlevel; mask = ( ent->r.clipmask ) ? ent->r.clipmask : MASK_SOLID; // find it's current position given the starting timeStamp startFlyTime = (float)( max( game.prevServerTime - ent->s.linearMovementTimeStamp, 0 ) ) * 0.001f; endFlyTime = (float)( game.serverTime - ent->s.linearMovementTimeStamp ) * 0.001f; VectorMA( ent->s.linearMovementBegin, startFlyTime, ent->s.linearMovementVelocity, start ); VectorMA( ent->s.linearMovementBegin, endFlyTime, ent->s.linearMovementVelocity, end ); G_Trace4D( &trace, start, ent->r.mins, ent->r.maxs, end, ent, mask, ent->timeDelta ); VectorCopy( trace.endpos, ent->s.origin ); GClip_LinkEntity( ent ); SV_Impact( ent, &trace ); if( !ent->r.inuse ) { // the projectile may be freed if touched something return; } // update some data required for the transmission //VectorCopy( ent->velocity, ent->s.linearMovementVelocity ); GClip_TouchTriggers( ent ); ent->groundentity = NULL; // projectiles never have ground entity ent->waterlevel = ( G_PointContents4D( ent->s.origin, ent->timeDelta ) & MASK_WATER ) ? true : false; if( !old_waterLevel && ent->waterlevel ) { G_PositionedSound( start, CHAN_AUTO, trap_SoundIndex( S_HIT_WATER ), ATTN_IDLE ); } else if( old_waterLevel && !ent->waterlevel ) { G_PositionedSound( ent->s.origin, CHAN_AUTO, trap_SoundIndex( S_HIT_WATER ), ATTN_IDLE ); } }