/* * GS_ClipVelocityToClippingPlanes */ static void GS_ClipVelocityToClippingPlanes( move_t *move ) { int i; for( i = 0; i < move->numClipPlanes; i++ ) { if( DotProduct( move->velocity, move->clipPlaneNormals[i] ) >= SLIDEMOVE_PLANEINTERACT_EPSILON ) continue; // looking in the same direction than the velocity #ifndef TRACEVICFIX #ifndef TRACE_NOAXIAL // this is a hack, cause non axial planes can return invalid positions in trace endpos if( PlaneTypeForNormal( move->clipPlaneNormals[i] ) == PLANE_NONAXIAL ) { // offset the origin a little bit along the plane normal VectorMA( move->origin, 0.05, move->clipPlaneNormals[i], move->origin ); } #endif #endif GS_ClipVelocity( move->velocity, move->clipPlaneNormals[i], move->velocity, move->slideBounce ); } }
/* * 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 ); } }
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]; G_Trace4D( &trace, ent->s.origin, ent->r.mins, ent->r.maxs, end, ent, mask, ent->timeDelta ); if( trace.allsolid ) { // entity is trapped in another solid VectorClear( 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 = &game.edicts[trace.ent]; if( ISWALKABLEPLANE( &trace.plane ) ) { blocked |= 1; // floor if( hit->s.solid == SOLID_BMODEL ) { 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->r.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 VectorClear( 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++ ) { GS_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->velocity ); } else { // go along the crease if( numplanes != 2 ) { VectorClear( ent->velocity ); return 7; } CrossProduct( planes[0], planes[1], dir ); VectorNormalize( 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 ) { VectorClear( ent->velocity ); return blocked; } } return blocked; }