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