qboolean PM_SlideMove( float gravMod ) { int bumpcount, numbumps; vec3_t dir; float d; int numplanes; vec3_t normal, planes[MAX_CLIP_PLANES]; vec3_t primal_velocity; vec3_t clipVelocity; int i, j, k; trace_t trace; vec3_t end; float time_left; float into; vec3_t endVelocity; vec3_t endClipVelocity; qboolean damageSelf = qtrue; numbumps = 4; VectorCopy (pm->ps->velocity, primal_velocity); if ( gravMod ) { VectorCopy( pm->ps->velocity, endVelocity ); if ( !(pm->ps->eFlags&EF_FORCE_GRIPPED) ) { endVelocity[2] -= pm->ps->gravity * pml.frametime * gravMod; } pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5; primal_velocity[2] = endVelocity[2]; if ( pml.groundPlane ) { if ( PM_GroundSlideOkay( pml.groundTrace.plane.normal[2] ) ) {// slide along the ground plane PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity, OVERCLIP ); } } } time_left = pml.frametime; // never turn against the ground plane if ( pml.groundPlane ) { numplanes = 1; VectorCopy( pml.groundTrace.plane.normal, planes[0] ); if ( !PM_GroundSlideOkay( planes[0][2] ) ) { planes[0][2] = 0; VectorNormalize( planes[0] ); } } else { numplanes = 0; } // never turn against original velocity VectorNormalize2( pm->ps->velocity, planes[numplanes] ); numplanes++; for ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) { // calculate position we are trying to move to VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end ); // see if we can make it there pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask, G2_NOCOLLIDE, 0); if ( trace.allsolid ) {// entity is completely trapped in another solid pm->ps->velocity[2] = 0; // don't build up falling damage, but allow sideways acceleration return qtrue; } if ( trace.fraction > 0 ) {// actually covered some distance VectorCopy( trace.endpos, pm->ps->origin ); } if ( trace.fraction == 1 ) { break; // moved the entire distance } //pm->ps->pm_flags |= PMF_BUMPED; // save entity for contact PM_AddTouchEnt( trace.entityNum ); //Hit it if ( trace.surfaceFlags&SURF_NODAMAGE ) { damageSelf = qfalse; } else if ( trace.entityNum == ENTITYNUM_WORLD && trace.plane.normal[2] > 0.5f ) {//if we land on the ground, let falling damage do it's thing itself, otherwise do impact damage damageSelf = qfalse; } else { damageSelf = qtrue; } if ( PM_ClientImpact( trace.entityNum, damageSelf ) ) { continue; } time_left -= time_left * trace.fraction; if ( numplanes >= MAX_CLIP_PLANES ) {// this shouldn't really happen VectorClear( pm->ps->velocity ); return qtrue; } VectorCopy( trace.plane.normal, normal ); if ( !PM_GroundSlideOkay( normal[2] ) ) {//wall-running //never push up off a sloped wall normal[2] = 0; VectorNormalize( normal ); } // // if this is the same plane we hit before, nudge velocity // out along it, which fixes some epsilon issues with // non-axial planes // for ( i = 0 ; i < numplanes ; i++ ) { if ( DotProduct( normal, planes[i] ) > 0.99 ) { VectorAdd( normal, pm->ps->velocity, pm->ps->velocity ); break; } } if ( i < numplanes ) { continue; } VectorCopy( normal, planes[numplanes] ); numplanes++; // // modify velocity so it parallels all of the clip planes // // find a plane that it enters for ( i = 0 ; i < numplanes ; i++ ) { into = DotProduct( pm->ps->velocity, planes[i] ); if ( into >= 0.1 ) { continue; // move doesn't interact with the plane } // see how hard we are hitting things if ( -into > pml.impactSpeed ) { pml.impactSpeed = -into; } // slide along the plane PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP ); // slide along the plane PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP ); // see if there is a second plane that the new move enters for ( j = 0 ; j < numplanes ; j++ ) { if ( j == i ) { continue; } if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) { continue; // move doesn't interact with the plane } // try clipping the move to the plane PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP ); PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP ); // see if it goes back into the first clip plane if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) { continue; } // slide the original velocity along the crease CrossProduct (planes[i], planes[j], dir); VectorNormalize( dir ); d = DotProduct( dir, pm->ps->velocity ); VectorScale( dir, d, clipVelocity ); CrossProduct (planes[i], planes[j], dir); VectorNormalize( dir ); d = DotProduct( dir, endVelocity ); VectorScale( dir, d, endClipVelocity ); // see if there is a third plane the the new move enters for ( k = 0 ; k < numplanes ; k++ ) { if ( k == i || k == j ) { continue; } if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) { continue; // move doesn't interact with the plane } // stop dead at a triple plane interaction VectorClear( pm->ps->velocity ); return qtrue; } } // if we have fixed all interactions, try another move VectorCopy( clipVelocity, pm->ps->velocity ); VectorCopy( endClipVelocity, endVelocity ); break; } } if ( gravMod ) { VectorCopy( endVelocity, pm->ps->velocity ); } // don't change velocity if in a timer (FIXME: is this correct?) if ( pm->ps->pm_time ) { VectorCopy( primal_velocity, pm->ps->velocity ); } return ( bumpcount != 0 ); }
qboolean PM_SlideMove( qboolean gravity ) { int bumpcount, numbumps; vec3_t dir; float d; int numplanes; vec3_t normal, planes[MAX_CLIP_PLANES]; vec3_t primal_velocity; vec3_t clipVelocity; int i, j, k; trace_t trace; vec3_t end; float time_left; float into; vec3_t endVelocity; vec3_t endClipVelocity; //qboolean damageSelf = qtrue; numbumps = 4; VectorCopy (pm->ps->velocity, primal_velocity); if ( gravity ) { VectorCopy( pm->ps->velocity, endVelocity ); endVelocity[2] -= pm->ps->gravity * pml.frametime; pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5; primal_velocity[2] = endVelocity[2]; if ( pml.groundPlane ) { if ( PM_GroundSlideOkay( pml.groundTrace.plane.normal[2] ) ) {// slide along the ground plane PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity, OVERCLIP ); } } } time_left = pml.frametime; // never turn against the ground plane if ( pml.groundPlane ) { numplanes = 1; VectorCopy( pml.groundTrace.plane.normal, planes[0] ); if ( !PM_GroundSlideOkay( planes[0][2] ) ) { planes[0][2] = 0; VectorNormalize( planes[0] ); } } else { numplanes = 0; } // never turn against original velocity VectorNormalize2( pm->ps->velocity, planes[numplanes] ); numplanes++; for ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) { // calculate position we are trying to move to VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end ); // see if we can make it there pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask); if (trace.allsolid) { // entity is completely trapped in another solid pm->ps->velocity[2] = 0; // don't build up falling damage, but allow sideways acceleration return qtrue; } if (trace.fraction > 0) { // actually covered some distance VectorCopy (trace.endpos, pm->ps->origin); } if (trace.fraction == 1) { break; // moved the entire distance } // save entity for contact PM_AddTouchEnt( trace.entityNum ); if (pm->ps->clientNum >= MAX_CLIENTS) { bgEntity_t *pEnt = pm_entSelf; if (pEnt && pEnt->s.eType == ET_NPC && pEnt->s.NPC_class == CLASS_VEHICLE && pEnt->m_pVehicle) { //do vehicle impact stuff then PM_VehicleImpact(pEnt, &trace); } } #ifdef QAGAME else { if ( PM_ClientImpact( &trace ) ) { continue; } } #endif time_left -= time_left * trace.fraction; if (numplanes >= MAX_CLIP_PLANES) { // this shouldn't really happen VectorClear( pm->ps->velocity ); return qtrue; } VectorCopy( trace.plane.normal, normal ); if ( !PM_GroundSlideOkay( normal[2] ) ) {//wall-running //never push up off a sloped wall normal[2] = 0; VectorNormalize( normal ); } // // if this is the same plane we hit before, nudge velocity // out along it, which fixes some epsilon issues with // non-axial planes // if ( !(pm->ps->pm_flags&PMF_STUCK_TO_WALL) ) {//no sliding if stuck to wall! for ( i = 0 ; i < numplanes ; i++ ) { if ( VectorCompare( normal, planes[i] ) ) {//DotProduct( normal, planes[i] ) > 0.99 ) { VectorAdd( normal, pm->ps->velocity, pm->ps->velocity ); break; } } if ( i < numplanes ) { continue; } } VectorCopy (normal, planes[numplanes]); numplanes++; // // modify velocity so it parallels all of the clip planes // // find a plane that it enters for ( i = 0 ; i < numplanes ; i++ ) { into = DotProduct( pm->ps->velocity, planes[i] ); if ( into >= 0.1 ) { continue; // move doesn't interact with the plane } // see how hard we are hitting things if ( -into > pml.impactSpeed ) { pml.impactSpeed = -into; } // slide along the plane PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP ); // slide along the plane PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP ); // see if there is a second plane that the new move enters for ( j = 0 ; j < numplanes ; j++ ) { if ( j == i ) { continue; } if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) { continue; // move doesn't interact with the plane } // try clipping the move to the plane PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP ); PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP ); // see if it goes back into the first clip plane if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) { continue; } // slide the original velocity along the crease CrossProduct (planes[i], planes[j], dir); VectorNormalize( dir ); d = DotProduct( dir, pm->ps->velocity ); VectorScale( dir, d, clipVelocity ); CrossProduct (planes[i], planes[j], dir); VectorNormalize( dir ); d = DotProduct( dir, endVelocity ); VectorScale( dir, d, endClipVelocity ); // see if there is a third plane the the new move enters for ( k = 0 ; k < numplanes ; k++ ) { if ( k == i || k == j ) { continue; } if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) { continue; // move doesn't interact with the plane } // stop dead at a triple plane interaction VectorClear( pm->ps->velocity ); return qtrue; } } // if we have fixed all interactions, try another move VectorCopy( clipVelocity, pm->ps->velocity ); VectorCopy( endClipVelocity, endVelocity ); break; } } if ( gravity ) { VectorCopy( endVelocity, pm->ps->velocity ); } // don't change velocity if in a timer (FIXME: is this correct?) if ( pm->ps->pm_time ) { VectorCopy( primal_velocity, pm->ps->velocity ); } return ( bumpcount != 0 ); }
qboolean PM_SlideMove( float gravMod ) { int bumpcount, numbumps; vec3_t dir; float d; int numplanes; vec3_t normal, planes[MAX_CLIP_PLANES]; vec3_t primal_velocity; vec3_t clipVelocity; int i, j, k; trace_t trace; vec3_t end; float time_left; float into; vec3_t endVelocity; vec3_t endClipVelocity; qboolean damageSelf = qtrue; int slideMoveContents = pm->tracemask; if ( pm->ps->clientNum >= MAX_CLIENTS && !PM_ControlledByPlayer() ) {//a non-player client, not an NPC under player control if ( pml.walking //walking on the ground || (pm->ps->groundEntityNum != ENTITYNUM_NONE //in air && PM_InSpecialJump( pm->ps->legsAnim )//in a special jump && !(pm->ps->eFlags&EF_FORCE_GRIPPED)//not being gripped && !(pm->ps->pm_flags&PMF_TIME_KNOCKBACK) && pm->gent && pm->gent->forcePushTime < level.time) )//not being pushed {// // If we're a vehicle, ignore this if we're being driven if ( !pm->gent //not an game ent || !pm->gent->client //not a client || pm->gent->client->NPC_class != CLASS_VEHICLE//not a vehicle || !pm->gent->m_pVehicle //no vehicle || !pm->gent->m_pVehicle->m_pPilot//no pilot || pm->gent->m_pVehicle->m_pPilot->s.number >= MAX_CLIENTS )//pilot is not the player {//then treat do not enter brushes as SOLID slideMoveContents |= CONTENTS_BOTCLIP; } } } numbumps = 4; VectorCopy (pm->ps->velocity, primal_velocity); if ( gravMod ) { VectorCopy( pm->ps->velocity, endVelocity ); if ( !(pm->ps->eFlags&EF_FORCE_GRIPPED) && !(pm->ps->eFlags&EF_FORCE_DRAINED) ) { endVelocity[2] -= pm->ps->gravity * pml.frametime * gravMod; } pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5; primal_velocity[2] = endVelocity[2]; if ( pml.groundPlane ) { if ( PM_GroundSlideOkay( pml.groundTrace.plane.normal[2] ) ) {// slide along the ground plane PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity, OVERCLIP ); } } } time_left = pml.frametime; // never turn against the ground plane if ( pml.groundPlane ) { numplanes = 1; VectorCopy( pml.groundTrace.plane.normal, planes[0] ); if ( !PM_GroundSlideOkay( planes[0][2] ) ) { planes[0][2] = 0; VectorNormalize( planes[0] ); } } else { numplanes = 0; } // never turn against original velocity VectorNormalize2( pm->ps->velocity, planes[numplanes] ); numplanes++; for ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) { // calculate position we are trying to move to VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end ); // see if we can make it there pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, slideMoveContents ); if ( (trace.contents&CONTENTS_BOTCLIP) && (slideMoveContents&CONTENTS_BOTCLIP) ) {//hit a do not enter brush if ( trace.allsolid || trace.startsolid )//inside the botclip {//crap, we're in a do not enter brush, take it out for the remainder of the traces and re-trace this one right now without it slideMoveContents &= ~CONTENTS_BOTCLIP; pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, slideMoveContents ); } else if ( trace.plane.normal[2] > 0.0f ) {//on top of a do not enter brush, it, just redo this one trace without it pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, (slideMoveContents&~CONTENTS_BOTCLIP) ); } } if ( trace.allsolid ) {// entity is completely trapped in another solid pm->ps->velocity[2] = 0; // don't build up falling damage, but allow sideways acceleration return qtrue; } if ( trace.fraction > 0 ) {// actually covered some distance VectorCopy( trace.endpos, pm->ps->origin ); } if ( trace.fraction == 1 ) { break; // moved the entire distance } // save entity for contact PM_AddTouchEnt( trace.entityNum ); //Hit it if ( trace.surfaceFlags&SURF_NODAMAGE ) { damageSelf = qfalse; } else if ( trace.entityNum == ENTITYNUM_WORLD && trace.plane.normal[2] > 0.5f ) {//if we land on the ground, let falling damage do it's thing itself, otherwise do impact damage damageSelf = qfalse; } else { damageSelf = qtrue; } if ( PM_ClientImpact( &trace, damageSelf ) ) { continue; } if (pm->gent->client && pm->gent->client->NPC_class == CLASS_VEHICLE && trace.plane.normal[2]<pm->gent->m_pVehicle->m_pVehicleInfo->maxSlope ) { pm->ps->pm_flags |= PMF_BUMPED; } time_left -= time_left * trace.fraction; if ( numplanes >= MAX_CLIP_PLANES ) {// this shouldn't really happen VectorClear( pm->ps->velocity ); return qtrue; } VectorCopy( trace.plane.normal, normal ); if ( !PM_GroundSlideOkay( normal[2] ) ) {//wall-running //never push up off a sloped wall normal[2] = 0; VectorNormalize( normal ); } // // if this is the same plane we hit before, nudge velocity // out along it, which fixes some epsilon issues with // non-axial planes // if ( !(pm->ps->pm_flags&PMF_STUCK_TO_WALL) ) {//no sliding if stuck to wall! for ( i = 0 ; i < numplanes ; i++ ) { if ( DotProduct( normal, planes[i] ) > 0.99 ) { VectorAdd( normal, pm->ps->velocity, pm->ps->velocity ); break; } } if ( i < numplanes ) { continue; } } VectorCopy( normal, planes[numplanes] ); numplanes++; // // modify velocity so it parallels all of the clip planes // // find a plane that it enters for ( i = 0 ; i < numplanes ; i++ ) { into = DotProduct( pm->ps->velocity, planes[i] ); if ( into >= 0.1 ) { continue; // move doesn't interact with the plane } // see how hard we are hitting things if ( -into > pml.impactSpeed ) { pml.impactSpeed = -into; } // slide along the plane PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP ); // slide along the plane PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP ); // see if there is a second plane that the new move enters for ( j = 0 ; j < numplanes ; j++ ) { if ( j == i ) { continue; } if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) { continue; // move doesn't interact with the plane } // try clipping the move to the plane PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP ); PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP ); // see if it goes back into the first clip plane if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) { continue; } // slide the original velocity along the crease CrossProduct (planes[i], planes[j], dir); VectorNormalize( dir ); d = DotProduct( dir, pm->ps->velocity ); VectorScale( dir, d, clipVelocity ); CrossProduct (planes[i], planes[j], dir); VectorNormalize( dir ); d = DotProduct( dir, endVelocity ); VectorScale( dir, d, endClipVelocity ); // see if there is a third plane the the new move enters for ( k = 0 ; k < numplanes ; k++ ) { if ( k == i || k == j ) { continue; } if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) { continue; // move doesn't interact with the plane } // stop dead at a triple plane interaction VectorClear( pm->ps->velocity ); return qtrue; } } // if we have fixed all interactions, try another move VectorCopy( clipVelocity, pm->ps->velocity ); VectorCopy( endClipVelocity, endVelocity ); break; } } if ( gravMod ) { VectorCopy( endVelocity, pm->ps->velocity ); } // don't change velocity if in a timer (FIXME: is this correct?) if ( pm->ps->pm_time ) { VectorCopy( primal_velocity, pm->ps->velocity ); } return ( bumpcount != 0 ); }