]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/d3xp/physics/Force_Field.cpp
hello world
[icculus/iodoom3.git] / neo / d3xp / physics / Force_Field.cpp
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #include "../../idlib/precompiled.h"
30 #pragma hdrstop
31
32 #include "../Game_local.h"
33
34 CLASS_DECLARATION( idForce, idForce_Field )
35 END_CLASS
36
37 /*
38 ================
39 idForce_Field::idForce_Field
40 ================
41 */
42 idForce_Field::idForce_Field( void ) {
43         type                    = FORCEFIELD_UNIFORM;
44         applyType               = FORCEFIELD_APPLY_FORCE;
45         magnitude               = 0.0f;
46         dir.Set( 0, 0, 1 );
47         randomTorque    = 0.0f;
48         playerOnly              = false;
49         monsterOnly             = false;
50         clipModel               = NULL;
51 }
52
53 /*
54 ================
55 idForce_Field::~idForce_Field
56 ================
57 */
58 idForce_Field::~idForce_Field( void ) {
59         if ( this->clipModel ) {
60                 delete this->clipModel;
61         }
62 }
63
64 /*
65 ================
66 idForce_Field::Save
67 ================
68 */
69 void idForce_Field::Save( idSaveGame *savefile ) const {
70         savefile->WriteInt( type );
71         savefile->WriteInt( applyType);
72         savefile->WriteFloat( magnitude );
73         savefile->WriteVec3( dir );
74         savefile->WriteFloat( randomTorque );
75         savefile->WriteBool( playerOnly );
76         savefile->WriteBool( monsterOnly );
77         savefile->WriteClipModel( clipModel );
78 }
79
80 /*
81 ================
82 idForce_Field::Restore
83 ================
84 */
85 void idForce_Field::Restore( idRestoreGame *savefile ) {
86         savefile->ReadInt( (int &)type );
87         savefile->ReadInt( (int &)applyType);
88         savefile->ReadFloat( magnitude );
89         savefile->ReadVec3( dir );
90         savefile->ReadFloat( randomTorque );
91         savefile->ReadBool( playerOnly );
92         savefile->ReadBool( monsterOnly );
93         savefile->ReadClipModel( clipModel );
94 }
95
96 /*
97 ================
98 idForce_Field::SetClipModel
99 ================
100 */
101 void idForce_Field::SetClipModel( idClipModel *clipModel ) {
102         if ( this->clipModel && clipModel != this->clipModel ) {
103                 delete this->clipModel;
104         }
105         this->clipModel = clipModel;
106 }
107
108 /*
109 ================
110 idForce_Field::Uniform
111 ================
112 */
113 void idForce_Field::Uniform( const idVec3 &force ) {
114         dir = force;
115         magnitude = dir.Normalize();
116         type = FORCEFIELD_UNIFORM;
117 }
118
119 /*
120 ================
121 idForce_Field::Explosion
122 ================
123 */
124 void idForce_Field::Explosion( float force ) {
125         magnitude = force;
126         type = FORCEFIELD_EXPLOSION;
127 }
128
129 /*
130 ================
131 idForce_Field::Implosion
132 ================
133 */
134 void idForce_Field::Implosion( float force ) {
135         magnitude = force;
136         type = FORCEFIELD_IMPLOSION;
137 }
138
139 /*
140 ================
141 idForce_Field::RandomTorque
142 ================
143 */
144 void idForce_Field::RandomTorque( float force ) {
145         randomTorque = force;
146 }
147
148 /*
149 ================
150 idForce_Field::Evaluate
151 ================
152 */
153 void idForce_Field::Evaluate( int time ) {
154         int numClipModels, i;
155         idBounds bounds;
156         idVec3 force, torque, angularVelocity;
157         idClipModel *cm, *clipModelList[ MAX_GENTITIES ];
158
159         assert( clipModel );
160
161         bounds.FromTransformedBounds( clipModel->GetBounds(), clipModel->GetOrigin(), clipModel->GetAxis() );
162         numClipModels = gameLocal.clip.ClipModelsTouchingBounds( bounds, -1, clipModelList, MAX_GENTITIES );
163
164         for ( i = 0; i < numClipModels; i++ ) {
165                 cm = clipModelList[ i ];
166
167                 if ( !cm->IsTraceModel() ) {
168                         continue;
169                 }
170
171                 idEntity *entity = cm->GetEntity();
172
173                 if ( !entity ) {
174                         continue;
175                 }
176                 
177                 idPhysics *physics = entity->GetPhysics();
178
179                 if ( playerOnly ) {
180                         if ( !physics->IsType( idPhysics_Player::Type ) ) {
181                                 continue;
182                         }
183                 } else if ( monsterOnly ) {
184                         if ( !physics->IsType( idPhysics_Monster::Type ) ) {
185                                 continue;
186                         }
187                 }
188
189                 if ( !gameLocal.clip.ContentsModel( cm->GetOrigin(), cm, cm->GetAxis(), -1,
190                                                                         clipModel->Handle(), clipModel->GetOrigin(), clipModel->GetAxis() ) ) {
191                         continue;
192                 }
193
194                 switch( type ) {
195                         case FORCEFIELD_UNIFORM: {
196                                 force = dir;
197                                 break;
198                         }
199                         case FORCEFIELD_EXPLOSION: {
200                                 force = cm->GetOrigin() - clipModel->GetOrigin();
201                                 force.Normalize();
202                                 break;
203                         }
204                         case FORCEFIELD_IMPLOSION: {
205                                 force = clipModel->GetOrigin() - cm->GetOrigin();
206                                 force.Normalize();
207                                 break;
208                         }
209                         default: {
210                                 gameLocal.Error( "idForce_Field: invalid type" );
211                                 break;
212                         }
213                 }
214
215                 if ( randomTorque != 0.0f ) {
216                         torque[0] = gameLocal.random.CRandomFloat();
217                         torque[1] = gameLocal.random.CRandomFloat();
218                         torque[2] = gameLocal.random.CRandomFloat();
219                         if ( torque.Normalize() == 0.0f ) {
220                                 torque[2] = 1.0f;
221                         }
222                 }
223
224                 switch( applyType ) {
225                         case FORCEFIELD_APPLY_FORCE: {
226                                 if ( randomTorque != 0.0f ) {
227                                         entity->AddForce( gameLocal.world, cm->GetId(), cm->GetOrigin() + torque.Cross( dir ) * randomTorque, dir * magnitude );
228                                 }
229                                 else {
230                                         entity->AddForce( gameLocal.world, cm->GetId(), cm->GetOrigin(), force * magnitude );
231                                 }
232                                 break;
233                         }
234                         case FORCEFIELD_APPLY_VELOCITY: {
235                                 physics->SetLinearVelocity( force * magnitude, cm->GetId() );
236                                 if ( randomTorque != 0.0f ) {
237                                         angularVelocity = physics->GetAngularVelocity( cm->GetId() );
238                                         physics->SetAngularVelocity( 0.5f * (angularVelocity + torque * randomTorque), cm->GetId() );
239                                 }
240                                 break;
241                         }
242                         case FORCEFIELD_APPLY_IMPULSE: {
243                                 if ( randomTorque != 0.0f ) {
244                                         entity->ApplyImpulse( gameLocal.world, cm->GetId(), cm->GetOrigin() + torque.Cross( dir ) * randomTorque, dir * magnitude );
245                                 }
246                                 else {
247                                         entity->ApplyImpulse( gameLocal.world, cm->GetId(), cm->GetOrigin(), force * magnitude );
248                                 }
249                                 break;
250                         }
251                         default: {
252                                 gameLocal.Error( "idForce_Field: invalid apply type" );
253                                 break;
254                         }
255                 }
256         }
257 }