/* ============ SV_PushEntity Does not change the entities velocity at all ============ */ trace_t SV_PushEntity(edict_t * ent, vec3_t push) { trace_t trace; vec3_t end; VectorAdd(ent->v.origin, push, end); if (ent->v.movetype == MOVETYPE_FLYMISSILE) trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent); else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT) // only clip against bmodels trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent); else trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent); VectorCopy(trace.endpos, ent->v.origin); SV_LinkEdict(ent, true); if (trace.ent) SV_Impact(ent, trace.ent); return trace; }
/* * G_ProjectileDistancePrestep */ static void G_ProjectileDistancePrestep( edict_t *projectile, float distance ) { float speed; vec3_t dir, dest; int mask, i; trace_t trace; #ifdef PLASMAHACK vec3_t plasma_hack_start; #endif if( projectile->movetype != MOVETYPE_TOSS && projectile->movetype != MOVETYPE_LINEARPROJECTILE && projectile->movetype != MOVETYPE_BOUNCE && projectile->movetype != MOVETYPE_BOUNCEGRENADE ) return; if( !distance ) return; if( ( speed = VectorNormalize2( projectile->velocity, dir ) ) == 0.0f ) return; mask = ( projectile->r.clipmask ) ? projectile->r.clipmask : MASK_SHOT; // race trick should come set up inside clipmask if( projectile->movetype == MOVETYPE_LINEARPROJECTILE ) VectorCopy( projectile->s.origin2, projectile->s.origin ); #ifdef PLASMAHACK VectorCopy( projectile->s.origin, plasma_hack_start ); #endif VectorMA( projectile->s.origin, distance, dir, dest ); G_Trace4D( &trace, projectile->s.origin, projectile->r.mins, projectile->r.maxs, dest, projectile->r.owner, mask, projectile->timeDelta ); for( i = 0; i < 3; i++ ) projectile->s.origin[i] = projectile->s.origin2[i] = projectile->olds.origin[i] = projectile->olds.origin2[i] = trace.endpos[i]; GClip_LinkEntity( projectile ); SV_Impact( projectile, &trace ); // set initial water state if( !projectile->r.inuse ) return; projectile->waterlevel = ( G_PointContents4D( projectile->s.origin, projectile->timeDelta ) & MASK_WATER ) ? qtrue : qfalse; // ffs : hack for the plasmagun #ifdef PLASMAHACK if( projectile->s.type == ET_PLASMA ) if (trap_Cvar_Get( "rs_plasma_hack", "1", CVAR_ARCHIVE )->integer==1)//racesow W_Plasma_Backtrace( projectile, plasma_hack_start ); #endif }
/* * Does not change the entities velocity at all */ trace_t SV_PushEntity(edict_t *ent, vec3_t push) { trace_t trace; vec3_t start; vec3_t end; int mask; VectorCopy(ent->s.origin, start); VectorAdd(start, push, end); retry: if (ent->clipmask) { mask = ent->clipmask; } else { mask = MASK_SOLID; } trace = gi.trace(start, ent->mins, ent->maxs, end, ent, mask); VectorCopy(trace.endpos, ent->s.origin); gi.linkentity(ent); if (trace.fraction != 1.0) { SV_Impact(ent, &trace); /* if the pushed entity went away and the pusher is still there */ if (!trace.ent->inuse && ent->inuse) { /* move the pusher back and try again */ VectorCopy(start, ent->s.origin); gi.linkentity(ent); goto retry; } } if (ent->inuse) { G_TouchTriggers(ent); } return trace; }
/* ============ SV_PushEntity Does not change the entities velocity at all ============ */ trace_t SV_PushEntity (edict_t *ent, vec3_t push) { trace_t trace; vec3_t start; vec3_t end; int mask; VectorCopy (ent->s.origin, start); VectorAdd (start, push, end); retry: if (ent->clipmask) mask = ent->clipmask; else mask = MASK_SOLID; trace = gi.trace (start, ent->mins, ent->maxs, end, ent, mask); VectorCopy (trace.endpos, ent->s.origin); gi.linkentity (ent); if (trace.fraction != 1.0) { SV_Impact (ent, &trace); // if the pushed entity went away and the pusher is still there if (!trace.ent->inuse && ent->inuse) { // move the pusher back and try again VectorCopy (start, ent->s.origin); gi.linkentity (ent); goto retry; } } // ================ // PGM // FIXME - is this needed? ent->gravity = 1.0; // PGM // ================ if (ent->inuse) G_TouchTriggers (ent); return trace; }
/* * SV_PushEntity * * Does not change the entities velocity at all */ static trace_t SV_PushEntity( edict_t *ent, vec3_t push ) { trace_t trace; vec3_t start; vec3_t end; int mask; VectorCopy( ent->s.origin, start ); VectorAdd( start, push, end ); retry: if( ent->r.clipmask ) { mask = ent->r.clipmask; } else { mask = MASK_SOLID; } G_Trace4D( &trace, start, ent->r.mins, ent->r.maxs, end, ent, mask, ent->timeDelta ); if( ent->movetype == MOVETYPE_PUSH || !trace.startsolid ) { VectorCopy( trace.endpos, ent->s.origin ); } GClip_LinkEntity( ent ); if( trace.fraction < 1.0 ) { SV_Impact( ent, &trace ); // if the pushed entity went away and the pusher is still there if( !game.edicts[trace.ent].r.inuse && ent->movetype == MOVETYPE_PUSH && ent->r.inuse ) { // move the pusher back and try again VectorCopy( start, ent->s.origin ); GClip_LinkEntity( ent ); goto retry; } } if( ent->r.inuse ) { GClip_TouchTriggers( ent ); } return trace; }
/* ============ SV_PushEntity Does not change the entities velocity at all ============ */ trace_t SV_PushEntity( edict_t *ent, const vec3_t lpush, const vec3_t apush, int *blocked ) { trace_t trace; int type; vec3_t end; VectorAdd( ent->v.origin, lpush, end ); if( ent->v.movetype == MOVETYPE_FLYMISSILE ) type = MOVE_MISSILE; else if( ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT ) type = MOVE_NOMONSTERS; // only clip against bmodels else type = MOVE_NORMAL; trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, end, type, ent ); if( trace.fraction != 0.0f ) { VectorCopy( trace.endpos, ent->v.origin ); if( sv.state == ss_active && apush[YAW] && ( ent->v.flags & FL_CLIENT )) { ent->v.avelocity[1] += apush[1]; ent->v.fixangle = 2; } // don't rotate pushables! if( SV_AllowPushRotate( ent )) ent->v.angles[YAW] += trace.fraction * apush[YAW]; } SV_LinkEdict( ent, true ); if( blocked ) *blocked = !VectorCompare( ent->v.origin, end ); // can't move full distance // so we can run impact function afterwards. if( SV_IsValidEdict( trace.ent )) SV_Impact( ent, trace.ent, &trace ); return trace; }
int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace) { int bumpcount, numbumps; vec3_t dir; float d; int numplanes; vec3_t planes[MAX_CLIP_PLANES]; vec3_t primal_velocity, original_velocity, new_velocity; int i, j; trace_t trace; vec3_t end; float time_left; int blocked; numbumps = 4; blocked = 0; VectorCopy (ent->v.velocity, original_velocity); VectorCopy (ent->v.velocity, primal_velocity); numplanes = 0; time_left = time; for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++) { if (!ent->v.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2]) break; for (i=0 ; i<3 ; i++) end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i]; trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent); if (trace.allsolid) { // entity is trapped in another solid VectorCopy (vec3_origin, ent->v.velocity); return 3; } if (trace.fraction > 0) { // actually covered some distance VectorCopy (trace.endpos, ent->v.origin); VectorCopy (ent->v.velocity, original_velocity); numplanes = 0; } if (trace.fraction == 1) break; // moved the entire distance if (!trace.ent) Sys_Error ("SV_FlyMove: !trace.ent"); if (trace.plane.normal[2] > 0.7) { blocked |= 1; // floor if (trace.ent->v.solid == SOLID_BSP) { ent->v.flags = (int)ent->v.flags | FL_ONGROUND; ent->v.groundentity = ((int)EDICT_TO_PROG(trace.ent)); } } if (!trace.plane.normal[2]) { blocked |= 2; // step if (steptrace) *steptrace = trace; // save for player extrafriction } // // run the impact function // 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); return 3; } VectorCopy (trace.plane.normal, planes[numplanes]); numplanes++; // // modify original_velocity so it parallels all of the clip planes // for (i=0 ; i<numplanes ; i++) { ClipVelocity (original_velocity, planes[i], new_velocity, 1); for (j=0 ; j<numplanes ; j++) if (j != i) { if (DotProduct (new_velocity, planes[j]) < 0) break; // not ok } if (j == numplanes) break; } if (i != numplanes) { // go along this plane VectorCopy (new_velocity, ent->v.velocity); } else { // go along the crease if (numplanes != 2) { // Con_Printf ("clip velocity, numplanes == %i\n",numplanes); VectorCopy (vec3_origin, ent->v.velocity); return 7; } CrossProduct (planes[0], planes[1], dir); d = DotProduct (dir, ent->v.velocity); VectorScale (dir, d, ent->v.velocity); } // // if original velocity is against the original velocity, stop dead // to avoid tiny occilations in sloping corners // if (DotProduct (ent->v.velocity, primal_velocity) <= 0) { VectorCopy (vec3_origin, ent->v.velocity); return blocked; } } return blocked; }
int SV_FlyMove (edict_t *ent, float time, int mask) { edict_t *hit; int bumpcount, numbumps; vec3_t dir; float d; int numplanes; vec3_t planes[MAX_CLIP_PLANES]; vec3_t primal_velocity, original_velocity, new_velocity; int i, j; trace_t trace; vec3_t end; float time_left; int blocked; numbumps = 4; blocked = 0; VectorCopy (ent->velocity, original_velocity); VectorCopy (ent->velocity, primal_velocity); numplanes = 0; time_left = time; ent->groundentity = NULL; for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++) { for (i=0 ; i<3 ; i++) end[i] = ent->s.origin[i] + time_left * ent->velocity[i]; trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, mask); if (trace.allsolid) { // entity is trapped in another solid VectorCopy (vec3_origin, ent->velocity); return 3; } if (trace.fraction > 0) { // actually covered some distance VectorCopy (trace.endpos, ent->s.origin); VectorCopy (ent->velocity, original_velocity); numplanes = 0; } if (trace.fraction == 1) break; // moved the entire distance hit = trace.ent; if (trace.plane.normal[2] > 0.7) { blocked |= 1; // floor if ( hit->solid == SOLID_BSP) { ent->groundentity = hit; ent->groundentity_linkcount = hit->linkcount; } } if (!trace.plane.normal[2]) { blocked |= 2; // step } // // run the impact function // SV_Impact (ent, &trace); if (!ent->inuse) 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->velocity); return 3; } VectorCopy (trace.plane.normal, planes[numplanes]); numplanes++; // // modify original_velocity so it parallels all of the clip planes // for (i=0 ; i<numplanes ; i++) { ClipVelocity (original_velocity, planes[i], new_velocity, 1); for (j=0 ; j<numplanes ; j++) if ((j != i) && !VectorCompare (planes[i], planes[j])) { if (DotProduct (new_velocity, planes[j]) < 0) break; // not ok } if (j == numplanes) break; } if (i != numplanes) { // go along this plane VectorCopy (new_velocity, ent->velocity); } else { // go along the crease if (numplanes != 2) { // gi.dprintf ("clip velocity, numplanes == %i\n",numplanes); VectorCopy (vec3_origin, ent->velocity); return 7; } CrossProduct (planes[0], planes[1], dir); d = DotProduct (dir, ent->velocity); VectorScale (dir, d, ent->velocity); } // // if original velocity is against the original velocity, stop dead // to avoid tiny occilations in sloping corners // if (DotProduct (ent->velocity, primal_velocity) <= 0) { VectorCopy (vec3_origin, ent->velocity); return blocked; } } return blocked; }
int SV_FlyMove (edict_t *ent, float time, int mask) { edict_t *hit; int bumpcount, numbumps; vec3_t dir; float d; int numplanes; vec3_t planes[MAX_CLIP_PLANES]; vec3_t primal_velocity, original_velocity, new_velocity; int i, j; trace_t trace; vec3_t end; float time_left; int blocked; numbumps = 4; blocked = 0; VectorCopy (ent->velocity, original_velocity); VectorCopy (ent->velocity, primal_velocity); numplanes = 0; time_left = time; ent->groundentity = NULL; for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++) { for (i=0 ; i<3 ; i++) end[i] = ent->s.origin[i] + time_left * ent->velocity[i]; trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, mask); if (trace.allsolid) { // entity is trapped in another solid // if (bumpcount == 0) // gi.dprintf( "WARNING: %s is stuck inside %s at (%s)\n", ent->classname, trace.ent->classname, vtos(ent->s.origin) ); VectorCopy (vec3_origin, ent->velocity); return 3; } if ((trace.fraction > 0) && !(trace.ent->svflags & SVF_MONSTER) && !trace.ent->client) { // covered some distance VectorCopy (trace.endpos, ent->s.origin); VectorCopy (ent->velocity, original_velocity); numplanes = 0; } else if ((trace.ent->svflags & SVF_MONSTER) || trace.ent->client) // stay well clear of other characters { // Ridah, don't climb beneath another character if (ent->flags & FL_FLY) { // abort climbing AngleVectors( ent->s.angles, ent->velocity, NULL, NULL ); VectorScale( ent->velocity, -32, ent->velocity ); ent->velocity[2] = 0; ent->flags &= ~FL_FLY; if (ent->cast_info.move_end_climb) ent->cast_info.currentmove = ent->cast_info.move_end_climb; } else if (ent->s.origin[2] > (trace.ent->s.origin[2] + trace.ent->maxs[2])) { // they're below us, jump randomly to get off VectorSet (ent->velocity, random()*128, random()*128, 220); return 20; } else { VectorCopy (vec3_origin, ent->velocity); } return 3; } if (trace.fraction == 1) { blocked = -1; break; // moved the entire distance } hit = trace.ent; if (trace.plane.normal[2] > 0.7) { blocked |= 1; // floor if ( hit->solid == SOLID_BSP) { ent->groundentity = hit; ent->groundentity_linkcount = hit->linkcount; } } if (!trace.plane.normal[2]) { blocked |= 2; // step } // // run the impact function // SV_Impact (ent, &trace); if (!ent->inuse) 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->velocity); return 3; } VectorCopy (trace.plane.normal, planes[numplanes]); numplanes++; // // modify original_velocity so it parallels all of the clip planes // for (i=0 ; i<numplanes ; i++) { ClipVelocity (original_velocity, planes[i], new_velocity, 1); for (j=0 ; j<numplanes ; j++) if ((j != i) && !VectorCompare (planes[i], planes[j])) { if (DotProduct (new_velocity, planes[j]) < 0) break; // not ok } if (j == numplanes) break; } if (i != numplanes) { // go along this plane //gi.dprintf( "Adjusting velocity for %s\n", ent->classname ); VectorCopy (new_velocity, ent->velocity); // Xatrix/Ridah, help Cast members's jump up to ledges if ( ent->velocity[2] > 60 && !(ent->flags & FL_FLY) ) ent->velocity[2] += (sv_gravity->value*FRAMETIME*0.5); // Xatrix/Ridah, help grunt's jump up to ledges } else { // go along the crease if (numplanes != 2) { // gi.dprintf ("clip velocity, numplanes == %i\n",numplanes); VectorCopy (vec3_origin, ent->velocity); return 7; } CrossProduct (planes[0], planes[1], dir); d = DotProduct (dir, ent->velocity); VectorScale (dir, d, ent->velocity); } // // if original velocity is against the original velocity, stop dead // to avoid tiny occilations in sloping corners // if (DotProduct (ent->velocity, primal_velocity) <= 0) { //gi.dprintf( "Clearing velocity for occilations for %s\n", ent->classname ); VectorCopy (vec3_origin, ent->velocity); return blocked; } } // Ridah, trying to fix jumping onto ledges problem in SR1 (for example) // ent->velocity[0] = primal_velocity[0]; // ent->velocity[1] = primal_velocity[1]; return blocked; }
/* * 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 ); } }
/* ============ SV_FlyMove The basic solid body movement clip that slides along multiple planes *steptrace - if not NULL, the trace results of any vertical wall hit will be stored Returns the clipflags if the velocity was modified (hit something solid) 1 = floor 2 = wall / step 4 = dead stop ============ */ int SV_FlyMove( edict_t *ent, float time, trace_t *steptrace ) { int i, j, numplanes, bumpcount, blocked; vec3_t dir, end, planes[MAX_CLIP_PLANES]; vec3_t primal_velocity, original_velocity, new_velocity; float d, time_left, allFraction; trace_t trace; blocked = 0; VectorCopy( ent->v.velocity, original_velocity ); VectorCopy( ent->v.velocity, primal_velocity ); numplanes = 0; allFraction = 0.0f; time_left = time; for( bumpcount = 0; bumpcount < MAX_CLIP_PLANES - 1; bumpcount++ ) { if( VectorIsNull( ent->v.velocity )) break; VectorMA( ent->v.origin, time_left, ent->v.velocity, end ); trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent ); allFraction += trace.fraction; if( trace.allsolid ) { // entity is trapped in another solid VectorClear( ent->v.velocity ); return 4; } if( trace.fraction > 0.0f ) { // actually covered some distance VectorCopy( trace.endpos, ent->v.origin ); VectorCopy( ent->v.velocity, original_velocity ); numplanes = 0; } if( trace.fraction == 1.0f ) break; // moved the entire distance if( !trace.ent ) MsgDev( D_ERROR, "SV_FlyMove: trace.ent == NULL\n" ); if( trace.plane.normal[2] > 0.7f ) { blocked |= 1; // floor if( trace.ent->v.solid == SOLID_BSP || trace.ent->v.solid == SOLID_SLIDEBOX || trace.ent->v.movetype == MOVETYPE_PUSHSTEP || (trace.ent->v.flags & FL_CLIENT)) { ent->v.flags |= FL_ONGROUND; ent->v.groundentity = trace.ent; } } if( trace.plane.normal[2] == 0.0f ) { blocked |= 2; // step if( steptrace ) *steptrace = trace; // save for player extrafriction } // run the impact function SV_Impact( ent, trace.ent, &trace ); // break if removed by the impact function if( ent->free ) break; time_left -= time_left * trace.fraction; // clipped to another plane if( numplanes >= MAX_CLIP_PLANES ) { // this shouldn't really happen VectorClear( ent->v.velocity ); break; } VectorCopy( trace.plane.normal, planes[numplanes] ); numplanes++; // modify original_velocity so it parallels all of the clip planes for( i = 0; i < numplanes; i++ ) { SV_ClipVelocity( original_velocity, planes[i], new_velocity, 1.0f ); for( j = 0; j < numplanes; j++ ) { if( j != i ) { if( DotProduct( new_velocity, planes[j] ) < 0.0f ) break; // not ok } } if( j == numplanes ) break; } if( i != numplanes ) { // go along this plane VectorCopy( new_velocity, ent->v.velocity ); } else { // go along the crease if( numplanes != 2 ) { VectorClear( ent->v.velocity ); break; } CrossProduct( planes[0], planes[1], dir ); d = DotProduct( dir, ent->v.velocity ); VectorScale( dir, d, ent->v.velocity ); } // if current velocity is against the original velocity, // stop dead to avoid tiny occilations in sloping corners if( DotProduct( ent->v.velocity, primal_velocity ) <= 0.0f ) { VectorClear( ent->v.velocity ); break; } } if( allFraction == 0.0f ) VectorClear( ent->v.velocity ); return blocked; }
/* ============= SV_Physics_Step Monsters freefall when they don't have a ground entity, otherwise all movement is done with discrete steps. This is also used for objects that have become still on the ground, but will fall if the floor is pulled out from under them. ============= */ void SV_Physics_Step( edict_t *ent ) { qboolean inwater; qboolean wasonground; qboolean wasonmover; vec3_t mins, maxs; vec3_t point; trace_t trace; int x, y; SV_WaterMove( ent ); SV_CheckVelocity( ent ); wasonground = (ent->v.flags & FL_ONGROUND); wasonmover = SV_CheckMover( ent ); inwater = SV_CheckWater( ent ); if( ent->v.flags & FL_FLOAT && ent->v.waterlevel > 0 ) { float buoyancy = SV_Submerged( ent ) * ent->v.skin * host.frametime; SV_AddGravity( ent ); ent->v.velocity[2] += buoyancy; } if( !wasonground && !( ent->v.flags & FL_FLY ) && (!( ent->v.flags & FL_SWIM ) || ent->v.waterlevel <= 0 )) { if( !inwater ) SV_AddGravity( ent ); } if( !VectorIsNull( ent->v.velocity ) || !VectorIsNull( ent->v.basevelocity )) { ent->v.flags &= ~FL_ONGROUND; if(( wasonground || wasonmover ) && ( ent->v.health > 0 || SV_CheckBottom( ent, MOVE_NORMAL ))) { float *vel = ent->v.velocity; float control, speed, newspeed; float friction; speed = sqrt(( vel[0] * vel[0] ) + ( vel[1] * vel[1] )); // DotProduct2D if( speed ) { friction = sv_friction->value * ent->v.friction; // factor ent->v.friction = 1.0f; // g-cont. ??? if( wasonmover ) friction *= 0.5f; // add a little friction control = (speed < sv_stopspeed->value) ? sv_stopspeed->value : speed; newspeed = speed - (host.frametime * control * friction); if( newspeed < 0 ) newspeed = 0; newspeed /= speed; vel[0] = vel[0] * newspeed; vel[1] = vel[1] * newspeed; } } VectorAdd( ent->v.velocity, ent->v.basevelocity, ent->v.velocity ); SV_CheckVelocity( ent ); SV_FlyMove( ent, host.frametime, NULL ); if( ent->free ) return; SV_CheckVelocity( ent ); VectorSubtract( ent->v.velocity, ent->v.basevelocity, ent->v.velocity ); SV_CheckVelocity( ent ); VectorAdd( ent->v.origin, ent->v.mins, mins ); VectorAdd( ent->v.origin, ent->v.maxs, maxs ); point[2] = mins[2] - 1.0f; for( x = 0; x <= 1; x++ ) { if( ent->v.flags & FL_ONGROUND ) break; for( y = 0; y <= 1; y++ ) { point[0] = x ? maxs[0] : mins[0]; point[1] = y ? maxs[1] : mins[1]; trace = SV_Move( point, vec3_origin, vec3_origin, point, MOVE_NORMAL, ent ); if( trace.startsolid ) { ent->v.flags |= FL_ONGROUND; ent->v.groundentity = trace.ent; ent->v.friction = 1.0f; break; } } } SV_LinkEdict( ent, true ); } else { if( svgame.globals->force_retouch != 0 ) { trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NORMAL, ent ); // hentacle impact code if(( trace.fraction < 1.0f || trace.startsolid ) && SV_IsValidEdict( trace.ent )) { SV_Impact( ent, trace.ent, &trace ); if( ent->free ) return; } } } if( !SV_RunThink( ent )) return; SV_CheckWaterTransition( ent ); }
/* =========== SV_RunCmd =========== */ void SV_RunCmd( sv_client_t *cl, usercmd_t *ucmd, int random_seed ) { usercmd_t lastcmd; edict_t *clent, *touch; double frametime; int i, oldmsec; pmtrace_t *pmtrace; trace_t trace; vec3_t oldvel; clent = cl->edict; if( cl->next_movetime > host.realtime ) { cl->last_movetime += ( ucmd->msec * 0.001f ); return; } cl->next_movetime = 0.0; // chop up very long commands if( ucmd->msec > 50 ) { lastcmd = *ucmd; oldmsec = ucmd->msec; lastcmd.msec = oldmsec / 2; SV_RunCmd( cl, &lastcmd, random_seed ); lastcmd.msec = oldmsec / 2 + (oldmsec & 1); // give them back thier msec. lastcmd.impulse = 0; SV_RunCmd( cl, &lastcmd, random_seed ); return; } if( !cl->fakeclient ) { SV_SetupMoveInterpolant( cl ); } lastcmd = *ucmd; svgame.dllFuncs.pfnCmdStart( cl->edict, ucmd, random_seed ); frametime = ucmd->msec * 0.001; cl->timebase += frametime; cl->last_movetime += frametime; PM_CheckMovingGround( clent, frametime ); VectorCopy( clent->v.v_angle, svgame.pmove->oldangles ); // save oldangles if( !clent->v.fixangle ) VectorCopy( ucmd->viewangles, clent->v.v_angle ); VectorClear( clent->v.clbasevelocity ); // copy player buttons clent->v.button = ucmd->buttons; if( ucmd->impulse ) clent->v.impulse = ucmd->impulse; if( ucmd->impulse == 204 ) { // force client.dll update SV_RefreshUserinfo(); } svgame.globals->time = cl->timebase; svgame.dllFuncs.pfnPlayerPreThink( clent ); SV_PlayerRunThink( clent, frametime, cl->timebase ); // If conveyor, or think, set basevelocity, then send to client asap too. if( !VectorIsNull( clent->v.basevelocity )) VectorCopy( clent->v.basevelocity, clent->v.clbasevelocity ); // setup playermove state SV_SetupPMove( svgame.pmove, cl, ucmd, cl->physinfo ); // motor! svgame.dllFuncs.pfnPM_Move( svgame.pmove, true ); // copy results back to client SV_FinishPMove( svgame.pmove, cl ); // link into place and touch triggers SV_LinkEdict( clent, true ); VectorCopy( clent->v.velocity, oldvel ); // save velocity // touch other objects for( i = 0; i < svgame.pmove->numtouch; i++ ) { // never touch the objects when "playersonly" is active if( i == MAX_PHYSENTS || ( sv.hostflags & SVF_PLAYERSONLY )) break; pmtrace = &svgame.pmove->touchindex[i]; touch = EDICT_NUM( svgame.pmove->physents[pmtrace->ent].info ); if( touch == clent ) continue; VectorCopy( pmtrace->deltavelocity, clent->v.velocity ); SV_ConvertPMTrace( &trace, pmtrace, touch ); SV_Impact( touch, clent, &trace ); } // restore velocity VectorCopy( oldvel, clent->v.velocity ); svgame.pmove->numtouch = 0; svgame.globals->time = cl->timebase; svgame.globals->frametime = frametime; // run post-think svgame.dllFuncs.pfnPlayerPostThink( clent ); svgame.dllFuncs.pfnCmdEnd( clent ); if( !cl->fakeclient ) { SV_RestoreMoveInterpolant( cl ); } }
/* ============ SV_PushEntity Does not change the entity's velocity at all ============ */ trace_t SV_PushEntity (edict_t *ent, vec3_t push) { trace_t trace; vec3_t end; int movetype; VectorAdd (ent->v.origin, push, end); if (ent->v.movetype == MOVETYPE_FLYMISSILE) movetype = MOVE_MISSILE; #ifdef HEXEN2_SUPPORT else if (hexen2 && (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)) movetype = MOVE_MISSILE; #endif else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT) movetype = MOVE_NOMONSTERS; // only clip against bmodels #ifdef HEXEN2_SUPPORT else if (hexen2 && (ent->v.movetype == MOVETYPE_SWIM)) movetype = MOVE_WATER; #endif else movetype = MOVE_NORMAL; trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, movetype, ent); #ifdef HEXEN2_SUPPORT if (hexen2) { if (ent->v.solid != SOLID_PHASE) { if ((ent->v.movetype == MOVETYPE_BOUNCE) && !(trace.allsolid == 0 && trace.startsolid == 0)) { trace.fraction = 0; return trace; } } else // Entity is PHASED so bounce off walls and other entities, go through monsters and players { if (trace.ent) { // Go through MONSTERS and PLAYERS, can't use FL_CLIENT cause rotating brushes do if (((int) trace.ent->v.flags & FL_MONSTER) || (trace.ent->v.movetype == MOVETYPE_WALK)) { vec3_t impact; edict_t *impact_e; VectorCopy (trace.endpos, impact); impact_e = trace.ent; trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_PHASE, ent); VectorCopy (impact, ent->v.origin); SV_Impact (ent, impact_e); } } } } #endif VectorCopy (trace.endpos, ent->v.origin); #ifdef _DEBUG if (!VectorCompare(trace.endpos, end)) movetype *= 1; #endif SV_LinkEdict (ent, true); if (trace.ent) SV_Impact (ent, trace.ent); return trace; }