/* ============ idPush::ClipRotationalPush Try to push other entities by moving the given entity. ============ */ float idPush::ClipRotationalPush( trace_t &results, idEntity *pusher, const int flags, const idMat3 &newAxis, const idRotation &rotation ) { int i, listedEntities, res; idEntity *check, *entityList[ MAX_GENTITIES ]; idBounds bounds, pushBounds; idRotation clipRotation; idMat3 clipAxis, oldAxis; trace_t pushResults; bool wasEnabled; float totalMass; idClipModel *clipModel; clipModel = pusher->GetPhysics()->GetClipModel(); totalMass = 0.0f; results.fraction = 1.0f; results.endpos = clipModel->GetOrigin(); results.endAxis = newAxis; memset( &results.c, 0, sizeof( results.c ) ); if ( !rotation.GetAngle() ) { return totalMass; } // get bounds for the whole movement bounds = clipModel->GetBounds(); if ( bounds[0].x >= bounds[1].x ) { return totalMass; } pushBounds.FromBoundsRotation( bounds, clipModel->GetOrigin(), clipModel->GetAxis(), rotation ); wasEnabled = clipModel->IsEnabled(); // make sure we don't get the pushing clip model in the list clipModel->Disable(); listedEntities = gameLocal.clip.EntitiesTouchingBounds( pushBounds, -1, entityList, MAX_GENTITIES ); // discard entities we cannot or should not push listedEntities = DiscardEntities( entityList, listedEntities, flags, pusher ); if ( flags & PUSHFL_CLIP ) { // can only clip movement of a trace model assert( clipModel->IsTraceModel() ); // disable to be pushed entities for collision detection for ( i = 0; i < listedEntities; i++ ) { entityList[i]->GetPhysics()->DisableClip(); } gameLocal.clip.Rotation( results, clipModel->GetOrigin(), rotation, clipModel, clipModel->GetAxis(), pusher->GetPhysics()->GetClipMask(), NULL ); // enable to be pushed entities for collision detection for ( i = 0; i < listedEntities; i++ ) { entityList[i]->GetPhysics()->EnableClip(); } if ( results.fraction == 0.0f ) { if ( wasEnabled ) { clipModel->Enable(); } return totalMass; } clipRotation = rotation * results.fraction; clipAxis = results.endAxis; } else { clipRotation = rotation; clipAxis = newAxis; } // we have to enable the clip model because we use it during pushing clipModel->Enable(); // save pusher old position oldAxis = clipModel->GetAxis(); // try to push all the entities for ( i = 0; i < listedEntities; i++ ) { check = entityList[ i ]; idPhysics *physics = check->GetPhysics(); // disable the entity for collision detection physics->DisableClip(); res = TryRotatePushEntity( pushResults, check, clipModel, flags, clipAxis, clipRotation ); // enable the entity for collision detection physics->EnableClip(); // if the entity is pushed if ( res == PUSH_OK ) { // set the pusher in the rotated position clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), newAxis ); // the entity might be pushed off the ground physics->EvaluateContacts(); // put pusher back in old position clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), oldAxis ); // wake up this object check->ApplyImpulse( clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), vec3_origin ); // add mass of pushed entity totalMass += physics->GetMass(); } // if the entity is not blocking if ( res != PUSH_BLOCKED ) { continue; } // if the blocking entity is a projectile if ( check->IsType( idProjectile::Type ) ) { check->ProcessEvent( &EV_Explode ); continue; } // if blocking entities should be crushed if ( flags & PUSHFL_CRUSH ) { check->Damage( clipModel->GetEntity(), clipModel->GetEntity(), vec3_origin, "damage_crush", 1.0f, CLIPMODEL_ID_TO_JOINT_HANDLE( pushResults.c.id ) ); continue; } // if the entity is an active articulated figure and gibs if ( check->IsType( idAFEntity_Base::Type ) && check->spawnArgs.GetBool( "gib" ) ) { if ( static_cast<idAFEntity_Base *>(check)->IsActiveAF() ) { check->ProcessEvent( &EV_Gib, "damage_Gib" ); } } // blocked results = pushResults; results.fraction = 0.0f; results.endAxis = clipModel->GetAxis(); results.endpos = clipModel->GetOrigin(); results.c.entityNum = check->entityNumber; results.c.id = 0; if ( !wasEnabled ) { clipModel->Disable(); } return totalMass; } if ( !wasEnabled ) { clipModel->Disable(); } return totalMass; }
/* ============ idPush::ClipRotationalPush Try to push other entities by moving the given entity. ============ */ float idPush::ClipRotationalPush( trace_t &results, idEntity *pusher, const int flags, const idMat3 &newAxis, const idRotation &rotation, idClipModel * clipModel ) { int i, listedEntities, res; idEntity *check, *entityList[ MAX_GENTITIES ]; idBounds bounds, pushBounds; idRotation clipRotation; idMat3 clipAxis, oldAxis; trace_t pushResults; bool wasEnabled; float totalMass; totalMass = 0.0f; results.fraction = 1.0f; results.endpos = clipModel->GetOrigin(); results.endAxis = newAxis; memset( &results.c, 0, sizeof( results.c ) ); if ( !rotation.GetAngle() ) { return totalMass; } // get bounds for the whole movement bounds = clipModel->GetBounds(); if ( bounds[0].x >= bounds[1].x ) { return totalMass; } pushBounds.FromBoundsRotation( bounds, clipModel->GetOrigin(), clipModel->GetAxis(), rotation ); wasEnabled = clipModel->GetContents() != 0; // make sure we don't get the pushing clip model in the list clipModel->Disable(); listedEntities = gameLocal.clip.EntitiesTouchingBounds( pushBounds, -1, entityList, MAX_GENTITIES ); // discard entities we cannot or should not push listedEntities = DiscardEntities( entityList, listedEntities, flags, pusher, clipModel->GetRealContents() ); if ( flags & PUSHFL_CLIP ) { // can only clip movement of a trace model assert( clipModel->IsTraceModel() ); // disable to be pushed entities for collision detection for ( i = 0; i < listedEntities; i++ ) { entityList[ i ]->DisableClip( false ); } gameLocal.clip.Rotation( CLIP_DEBUG_PARMS results, clipModel->GetOrigin(), rotation, clipModel, clipModel->GetAxis(), pusher->GetPhysics()->GetClipMask(), NULL ); // enable to be pushed entities for collision detection for ( i = 0; i < listedEntities; i++ ) { entityList[ i ]->EnableClip(); } if ( results.fraction == 0.0f ) { if ( wasEnabled ) { clipModel->Enable(); } return totalMass; } clipRotation = rotation * results.fraction; clipAxis = results.endAxis; } else { clipRotation = rotation; clipAxis = newAxis; } // we have to enable the clip model because we use it during pushing clipModel->Link( gameLocal.clip ); // save pusher old position oldAxis = clipModel->GetAxis(); // try to push all the entities for ( i = 0; i < listedEntities; i++ ) { check = entityList[ i ]; idPhysics *physics = check->GetPhysics(); // disable the entity for collision detection check->DisableClip( false ); res = TryRotatePushEntity( pushResults, check, clipModel, flags, clipAxis, clipRotation ); // enable the entity for collision detection check->EnableClip(); // if the entity is pushed if ( res == PUSH_OK ) { // set the pusher in the rotated position clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), newAxis ); // the entity might be pushed off the ground physics->EvaluateContacts( CLIP_DEBUG_PARMS_ONLY ); // put pusher back in old position clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), oldAxis ); // wake up this object check->ApplyImpulse( clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), vec3_origin ); // add mass of pushed entity totalMass += physics->GetMass(); } // if the entity is not blocking if ( res != PUSH_BLOCKED ) { continue; } // if blocking entities should be crushed if ( flags & PUSHFL_CRUSH ) { check->Damage( clipModel->GetEntity(), clipModel->GetEntity(), vec3_origin, DAMAGE_FOR_NAME( "damage_crush" ), 1.0f, &pushResults ); continue; } // blocked results = pushResults; results.fraction = 0.0f; results.endAxis = clipModel->GetAxis(); results.endpos = clipModel->GetOrigin(); results.c.entityNum = check->entityNumber; results.c.id = 0; if ( !wasEnabled ) { clipModel->Disable(); } return totalMass; } if ( !wasEnabled ) { clipModel->Disable(); } return totalMass; }