/* ============ idPush::GetPushableEntitiesForRotation ============ */ int idPush::GetPushableEntitiesForRotation( idEntity *pusher, idEntity *initialPusher, const int flags, const idRotation &rotation, idEntity *entityList[], int maxEntities ) { int i, n, l; idBounds bounds, pushBounds; idPhysics *physics; // get bounds for the whole movement physics = pusher->GetPhysics(); bounds = physics->GetBounds(); pushBounds.FromBoundsRotation( bounds, physics->GetOrigin(), physics->GetAxis(), rotation ); pushBounds.ExpandSelf( 2.0f ); // get all entities within the push bounds n = gameLocal.clip.EntitiesTouchingBounds( pushBounds, -1, entityList, MAX_GENTITIES ); for ( l = i = 0; i < n; i++ ) { if ( entityList[i] == pusher || entityList[i] == initialPusher ) { continue; } if ( CanPushEntity( entityList[i], pusher, initialPusher, flags ) ) { entityList[l++] = entityList[i]; } } return l; }
/* ============ idPush::GetPushableEntitiesForTranslation ============ */ int idPush::GetPushableEntitiesForTranslation( idEntity *pusher, idEntity *initialPusher, const int flags, const idVec3 &translation, idEntity *entityList[], int maxEntities ) { int i, n, l; idBounds bounds, pushBounds; idPhysics *physics; // get bounds for the whole movement physics = pusher->GetPhysics(); bounds = physics->GetBounds(); pushBounds.FromBoundsTranslation( bounds, physics->GetOrigin(), physics->GetAxis(), translation ); pushBounds.ExpandSelf( 2.0f ); // get all entities within the push bounds // RAVEN BEGIN // ddynerman: multiple clip worlds n = gameLocal.EntitiesTouchingBounds( this, pushBounds, -1, entityList, MAX_GENTITIES ); // RAVEN END for ( l = i = 0; i < n; i++ ) { if ( entityList[i] == pusher || entityList[i] == initialPusher ) { continue; } if ( CanPushEntity( entityList[i], pusher, initialPusher, flags ) ) { entityList[l++] = entityList[i]; } } return l; }
/* ============ idPush::ClipTranslationalPush Try to push other entities by translating the given entity. ============ */ float idPush::ClipTranslationalPush( trace_t &results, idEntity *pusher, const int flags, const idVec3 &newOrigin, const idVec3 &translation ) { int i, j, numListedEntities; idEntity *curPusher, *ent, *entityList[ MAX_GENTITIES ]; float fraction; bool groundContact, blocked = false; float totalMass; trace_t trace; idVec3 realTranslation, partialTranslation; totalMass = 0.0f; results.fraction = 1.0f; results.endpos = newOrigin; results.endAxis = pusher->GetPhysics()->GetAxis(); memset( results.c, 0, sizeof( results.c ) ); if ( translation == vec3_origin ) { return totalMass; } // clip against all non-pushable physics objects if ( flags & PUSHFL_CLIP ) { numListedEntities = GetPushableEntitiesForTranslation( pusher, pusher, flags, translation, entityList, MAX_GENTITIES ); // disable pushable entities for collision detection for ( i = 0; i < numListedEntities; i++ ) { entityList[i]->GetPhysics()->DisableClip(); } // clip translation pusher->GetPhysics()->ClipTranslation( results, translation, NULL ); // enable pushable entities for ( i = 0; i < numListedEntities; i++ ) { entityList[i]->GetPhysics()->EnableClip(); } if ( results.fraction == 0.0f ) { return totalMass; } realTranslation = results.fraction * translation; } else { realTranslation = translation; } // put the pusher in the group of pushed physics objects pushedGroup[0].ent = pusher; pushedGroup[0].fraction = 1.0f; pushedGroup[0].groundContact = true; pushedGroup[0].test = true; pushedGroupSize = 1; // get all physics objects that need to be pushed for ( i = 0; i < pushedGroupSize; ) { if ( !pushedGroup[i].test ) { i++; continue; } pushedGroup[i].test = false; curPusher = pushedGroup[i].ent; fraction = pushedGroup[i].fraction; groundContact = pushedGroup[i].groundContact; i = 0; numListedEntities = GetPushableEntitiesForTranslation( curPusher, pusher, flags, realTranslation, entityList, MAX_GENTITIES ); for ( j = 0; j < numListedEntities; j++ ) { ent = entityList[ j ]; if ( IsFullyPushed( ent ) ) { continue; } if ( !CanPushEntity( ent, curPusher, pusher, flags ) ) { continue; } if ( ent->GetPhysics()->IsGroundEntity( curPusher->entityNumber ) ) { AddEntityToPushedGroup( ent, 1.0f * fraction, false ); } else if ( ClipTranslationAgainstPusher( trace, ent, curPusher, -fraction * realTranslation ) ) { AddEntityToPushedGroup( ent, ( 1.0f - trace.fraction ) * fraction, groundContact ); } } } // save physics states and disable physics objects for collision detection for ( i = 0; i < pushedGroupSize; i++ ) { SaveEntityPosition( pushedGroup[i].ent ); pushedGroup[i].ent->GetPhysics()->DisableClip(); } // clip all pushed physics objects for ( i = 1; i < pushedGroupSize; i++ ) { partialTranslation = realTranslation * pushedGroup[i].fraction; pushedGroup[i].ent->GetPhysics()->ClipTranslation( trace, partialTranslation, NULL ); if ( trace.fraction < 1.0f ) { blocked = true; break; } } // enable all physics objects for collision detection for ( i = 1; i < pushedGroupSize; i++ ) { pushedGroup[i].ent->GetPhysics()->EnableClip(); } // push all or nothing if ( blocked ) { if ( flags & PUSHFL_CLIP ) { pusher->GetPhysics()->ClipTranslation( results, realTranslation, NULL ); } else { results.fraction = 0.0f; results.endpos = pusher->GetPhysics()->GetOrigin(); results.endAxis = pusher->GetPhysics()->GetAxis(); } } else { // translate all pushed physics objects for ( i = 1; i < pushedGroupSize; i++ ) { partialTranslation = realTranslation * pushedGroup[i].fraction; pushedGroup[i].ent->GetPhysics()->Translate( partialTranslation ); totalMass += pushedGroup[i].ent->GetPhysics()->GetMass(); } // translate the clip models of the pusher for ( i = 0; i < pusher->GetPhysics()->GetNumClipModels(); i++ ) { pusher->GetPhysics()->GetClipModel(i)->Translate( results.fraction * realTranslation ); pusher->GetPhysics()->GetClipModel(i)->Link( gameLocal.clip ); } } return totalMass; }