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 "sys/platform.h"
30 #include "physics/Physics_Player.h"
31 #include "physics/Physics_Monster.h"
32 #include "WorldSpawn.h"
33 
34 #include "physics/Force_Field.h"
35 
CLASS_DECLARATION(idForce,idForce_Field)36 CLASS_DECLARATION( idForce, idForce_Field )
37 END_CLASS
38 
39 /*
40 ================
41 idForce_Field::idForce_Field
42 ================
43 */
44 idForce_Field::idForce_Field( void ) {
45 	type			= FORCEFIELD_UNIFORM;
46 	applyType		= FORCEFIELD_APPLY_FORCE;
47 	magnitude		= 0.0f;
48 	dir.Set( 0, 0, 1 );
49 	randomTorque	= 0.0f;
50 	playerOnly		= false;
51 	monsterOnly		= false;
52 	clipModel		= NULL;
53 }
54 
55 /*
56 ================
57 idForce_Field::~idForce_Field
58 ================
59 */
~idForce_Field(void)60 idForce_Field::~idForce_Field( void ) {
61 	if ( this->clipModel ) {
62 		delete this->clipModel;
63 	}
64 }
65 
66 /*
67 ================
68 idForce_Field::Save
69 ================
70 */
Save(idSaveGame * savefile) const71 void idForce_Field::Save( idSaveGame *savefile ) const {
72 	savefile->WriteInt( type );
73 	savefile->WriteInt( applyType);
74 	savefile->WriteFloat( magnitude );
75 	savefile->WriteVec3( dir );
76 	savefile->WriteFloat( randomTorque );
77 	savefile->WriteBool( playerOnly );
78 	savefile->WriteBool( monsterOnly );
79 	savefile->WriteClipModel( clipModel );
80 }
81 
82 /*
83 ================
84 idForce_Field::Restore
85 ================
86 */
Restore(idRestoreGame * savefile)87 void idForce_Field::Restore( idRestoreGame *savefile ) {
88 	savefile->ReadInt( (int &)type );
89 	savefile->ReadInt( (int &)applyType);
90 	savefile->ReadFloat( magnitude );
91 	savefile->ReadVec3( dir );
92 	savefile->ReadFloat( randomTorque );
93 	savefile->ReadBool( playerOnly );
94 	savefile->ReadBool( monsterOnly );
95 	savefile->ReadClipModel( clipModel );
96 }
97 
98 /*
99 ================
100 idForce_Field::SetClipModel
101 ================
102 */
SetClipModel(idClipModel * clipModel)103 void idForce_Field::SetClipModel( idClipModel *clipModel ) {
104 	if ( this->clipModel && clipModel != this->clipModel ) {
105 		delete this->clipModel;
106 	}
107 	this->clipModel = clipModel;
108 }
109 
110 /*
111 ================
112 idForce_Field::Uniform
113 ================
114 */
Uniform(const idVec3 & force)115 void idForce_Field::Uniform( const idVec3 &force ) {
116 	dir = force;
117 	magnitude = dir.Normalize();
118 	type = FORCEFIELD_UNIFORM;
119 }
120 
121 /*
122 ================
123 idForce_Field::Explosion
124 ================
125 */
Explosion(float force)126 void idForce_Field::Explosion( float force ) {
127 	magnitude = force;
128 	type = FORCEFIELD_EXPLOSION;
129 }
130 
131 /*
132 ================
133 idForce_Field::Implosion
134 ================
135 */
Implosion(float force)136 void idForce_Field::Implosion( float force ) {
137 	magnitude = force;
138 	type = FORCEFIELD_IMPLOSION;
139 }
140 
141 /*
142 ================
143 idForce_Field::RandomTorque
144 ================
145 */
RandomTorque(float force)146 void idForce_Field::RandomTorque( float force ) {
147 	randomTorque = force;
148 }
149 
150 /*
151 ================
152 idForce_Field::Evaluate
153 ================
154 */
Evaluate(int time)155 void idForce_Field::Evaluate( int time ) {
156 	int numClipModels, i;
157 	idBounds bounds;
158 	idVec3 force, torque, angularVelocity;
159 	idClipModel *cm, *clipModelList[ MAX_GENTITIES ];
160 
161 	assert( clipModel );
162 
163 	bounds.FromTransformedBounds( clipModel->GetBounds(), clipModel->GetOrigin(), clipModel->GetAxis() );
164 	numClipModels = gameLocal.clip.ClipModelsTouchingBounds( bounds, -1, clipModelList, MAX_GENTITIES );
165 
166 	torque.Zero();
167 
168 	for ( i = 0; i < numClipModels; i++ ) {
169 		cm = clipModelList[ i ];
170 
171 		if ( !cm->IsTraceModel() ) {
172 			continue;
173 		}
174 
175 		idEntity *entity = cm->GetEntity();
176 
177 		if ( !entity ) {
178 			continue;
179 		}
180 
181 		idPhysics *physics = entity->GetPhysics();
182 
183 		if ( playerOnly ) {
184 			if ( !physics->IsType( idPhysics_Player::Type ) ) {
185 				continue;
186 			}
187 		} else if ( monsterOnly ) {
188 			if ( !physics->IsType( idPhysics_Monster::Type ) ) {
189 				continue;
190 			}
191 		}
192 
193 		if ( !gameLocal.clip.ContentsModel( cm->GetOrigin(), cm, cm->GetAxis(), -1,
194 									clipModel->Handle(), clipModel->GetOrigin(), clipModel->GetAxis() ) ) {
195 			continue;
196 		}
197 
198 		switch( type ) {
199 			case FORCEFIELD_UNIFORM: {
200 				force = dir;
201 				break;
202 			}
203 			case FORCEFIELD_EXPLOSION: {
204 				force = cm->GetOrigin() - clipModel->GetOrigin();
205 				force.Normalize();
206 				break;
207 			}
208 			case FORCEFIELD_IMPLOSION: {
209 				force = clipModel->GetOrigin() - cm->GetOrigin();
210 				force.Normalize();
211 				break;
212 			}
213 			default: {
214 				gameLocal.Error( "idForce_Field: invalid type" );
215 				return;
216 			}
217 		}
218 
219 		if ( randomTorque != 0.0f ) {
220 			torque[0] = gameLocal.random.CRandomFloat();
221 			torque[1] = gameLocal.random.CRandomFloat();
222 			torque[2] = gameLocal.random.CRandomFloat();
223 			if ( torque.Normalize() == 0.0f ) {
224 				torque[2] = 1.0f;
225 			}
226 		}
227 
228 		switch( applyType ) {
229 			case FORCEFIELD_APPLY_FORCE: {
230 				if ( randomTorque != 0.0f ) {
231 					entity->AddForce( gameLocal.world, cm->GetId(), cm->GetOrigin() + torque.Cross( dir ) * randomTorque, dir * magnitude );
232 				}
233 				else {
234 					entity->AddForce( gameLocal.world, cm->GetId(), cm->GetOrigin(), force * magnitude );
235 				}
236 				break;
237 			}
238 			case FORCEFIELD_APPLY_VELOCITY: {
239 				physics->SetLinearVelocity( force * magnitude, cm->GetId() );
240 				if ( randomTorque != 0.0f ) {
241 					angularVelocity = physics->GetAngularVelocity( cm->GetId() );
242 					physics->SetAngularVelocity( 0.5f * (angularVelocity + torque * randomTorque), cm->GetId() );
243 				}
244 				break;
245 			}
246 			case FORCEFIELD_APPLY_IMPULSE: {
247 				if ( randomTorque != 0.0f ) {
248 					entity->ApplyImpulse( gameLocal.world, cm->GetId(), cm->GetOrigin() + torque.Cross( dir ) * randomTorque, dir * magnitude );
249 				}
250 				else {
251 					entity->ApplyImpulse( gameLocal.world, cm->GetId(), cm->GetOrigin(), force * magnitude );
252 				}
253 				break;
254 			}
255 			default: {
256 				gameLocal.Error( "idForce_Field: invalid apply type" );
257 				return;
258 			}
259 		}
260 	}
261 }
262