// Copyright (C) 2007 Id Software, Inc. // #include "../precompiled.h" #pragma hdrstop #if defined( _DEBUG ) && !defined( ID_REDIRECT_NEWDELETE ) #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #include "Force_Field.h" #include "Clip.h" #include "../Entity.h" #include "Physics_Player.h" #include "Physics_Monster.h" #include "../WorldSpawn.h" CLASS_DECLARATION( idForce, idForce_Field ) END_CLASS /* ================ idForce_Field::idForce_Field ================ */ idForce_Field::idForce_Field( void ) { type = FORCEFIELD_UNIFORM; applyType = FORCEFIELD_APPLY_FORCE; magnitude = 0.0f; dir.Set( 0, 0, 1 ); randomTorque = 0.0f; playerOnly = false; monsterOnly = false; clipModel = NULL; } /* ================ idForce_Field::~idForce_Field ================ */ idForce_Field::~idForce_Field( void ) { if ( this->clipModel != NULL ) { gameLocal.clip.DeleteClipModel( this->clipModel ); } } /* ================ idForce_Field::SetClipModel ================ */ void idForce_Field::SetClipModel( idClipModel *clipModel ) { if ( this->clipModel != NULL && clipModel != this->clipModel ) { gameLocal.clip.DeleteClipModel( this->clipModel ); } this->clipModel = clipModel; } /* ================ idForce_Field::Uniform ================ */ void idForce_Field::Uniform( const idVec3 &force ) { dir = force; magnitude = dir.Normalize(); type = FORCEFIELD_UNIFORM; } /* ================ idForce_Field::Explosion ================ */ void idForce_Field::Explosion( float force ) { magnitude = force; type = FORCEFIELD_EXPLOSION; } /* ================ idForce_Field::Implosion ================ */ void idForce_Field::Implosion( float force ) { magnitude = force; type = FORCEFIELD_IMPLOSION; } /* ================ idForce_Field::RandomTorque ================ */ void idForce_Field::RandomTorque( float force ) { randomTorque = force; } /* ================ idForce_Field::Evaluate ================ */ void idForce_Field::Evaluate( int time ) { int numClipModels, i; idBounds bounds; idVec3 force, torque, angularVelocity; const idClipModel* cm; const idClipModel* clipModelList[ MAX_GENTITIES ]; assert( clipModel ); bounds.FromTransformedBounds( clipModel->GetBounds(), clipModel->GetOrigin(), clipModel->GetAxis() ); numClipModels = gameLocal.clip.ClipModelsTouchingBounds( CLIP_DEBUG_PARMS bounds, -1, clipModelList, MAX_GENTITIES, NULL ); for ( i = 0; i < numClipModels; i++ ) { cm = clipModelList[ i ]; if ( !cm->IsTraceModel() ) { continue; } idEntity *entity = cm->GetEntity(); idPhysics *physics = entity->GetPhysics(); if ( playerOnly && !physics->IsType( idPhysics_Player::Type ) ) { continue; } if ( !gameLocal.clip.ContentsModel( CLIP_DEBUG_PARMS cm->GetOrigin(), cm, cm->GetAxis(), -1, clipModel, clipModel->GetOrigin(), clipModel->GetAxis() ) ) { continue; } switch( type ) { case FORCEFIELD_UNIFORM: { force = dir; break; } case FORCEFIELD_EXPLOSION: { force = cm->GetOrigin() - clipModel->GetOrigin(); force.Normalize(); break; } case FORCEFIELD_IMPLOSION: { force = clipModel->GetOrigin() - cm->GetOrigin(); force.Normalize(); break; } default: { gameLocal.Error( "idForce_Field: invalid type" ); break; } } if ( randomTorque != 0.0f ) { torque[0] = gameLocal.random.CRandomFloat(); torque[1] = gameLocal.random.CRandomFloat(); torque[2] = gameLocal.random.CRandomFloat(); if ( torque.Normalize() == 0.0f ) { torque[2] = 1.0f; } } switch( applyType ) { case FORCEFIELD_APPLY_FORCE: { if ( randomTorque != 0.0f ) { entity->AddForce( gameLocal.world, cm->GetId(), cm->GetOrigin() + torque.Cross( dir ) * randomTorque, dir * magnitude ); } else { entity->AddForce( gameLocal.world, cm->GetId(), cm->GetOrigin(), force * magnitude ); } break; } case FORCEFIELD_APPLY_VELOCITY: { physics->SetLinearVelocity( force * magnitude, cm->GetId() ); if ( randomTorque != 0.0f ) { angularVelocity = physics->GetAngularVelocity( cm->GetId() ); physics->SetAngularVelocity( 0.5f * (angularVelocity + torque * randomTorque), cm->GetId() ); } break; } case FORCEFIELD_APPLY_IMPULSE: { if ( randomTorque != 0.0f ) { entity->ApplyImpulse( gameLocal.world, cm->GetId(), cm->GetOrigin() + torque.Cross( dir ) * randomTorque, dir * magnitude ); } else { entity->ApplyImpulse( gameLocal.world, cm->GetId(), cm->GetOrigin(), force * magnitude ); } break; } default: { gameLocal.Error( "idForce_Field: invalid apply type" ); break; } } } }