doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Fx.cpp
Go to the documentation of this file.
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 /*
35 ===============================================================================
36 
37  idEntityFx
38 
39 ===============================================================================
40 */
41 
42 const idEventDef EV_Fx_KillFx( "_killfx" );
43 const idEventDef EV_Fx_Action( "_fxAction", "e" ); // implemented by subclasses
44 
46 EVENT( EV_Activate, idEntityFx::Event_Trigger )
47 EVENT( EV_Fx_KillFx, idEntityFx::Event_ClearFx )
49 
50 
51 /*
52 ================
53 idEntityFx::Save
54 ================
55 */
56 void idEntityFx::Save( idSaveGame *savefile ) const {
57  int i;
58 
59  savefile->WriteInt( started );
60  savefile->WriteInt( nextTriggerTime );
61  savefile->WriteFX( fxEffect );
62  savefile->WriteString( systemName );
63 
64  savefile->WriteInt( actions.Num() );
65 
66  for ( i = 0; i < actions.Num(); i++ ) {
67 
68  if ( actions[i].lightDefHandle >= 0 ) {
69  savefile->WriteBool( true );
70  savefile->WriteRenderLight( actions[i].renderLight );
71  } else {
72  savefile->WriteBool( false );
73  }
74 
75  if ( actions[i].modelDefHandle >= 0 ) {
76  savefile->WriteBool( true );
77  savefile->WriteRenderEntity( actions[i].renderEntity );
78  } else {
79  savefile->WriteBool( false );
80  }
81 
82  savefile->WriteFloat( actions[i].delay );
83  savefile->WriteInt( actions[i].start );
84  savefile->WriteBool( actions[i].soundStarted );
85  savefile->WriteBool( actions[i].shakeStarted );
86  savefile->WriteBool( actions[i].decalDropped );
87  savefile->WriteBool( actions[i].launched );
88  }
89 }
90 
91 /*
92 ================
93 idEntityFx::Restore
94 ================
95 */
97  int i;
98  int num;
99  bool hasObject;
100 
101  savefile->ReadInt( started );
102  savefile->ReadInt( nextTriggerTime );
103  savefile->ReadFX( fxEffect );
104  savefile->ReadString( systemName );
105 
106  savefile->ReadInt( num );
107 
108  actions.SetNum( num );
109  for ( i = 0; i < num; i++ ) {
110 
111  savefile->ReadBool( hasObject );
112  if ( hasObject ) {
113  savefile->ReadRenderLight( actions[i].renderLight );
114  actions[i].lightDefHandle = gameRenderWorld->AddLightDef( &actions[i].renderLight );
115  } else {
116  memset( &actions[i].renderLight, 0, sizeof( renderLight_t ) );
117  actions[i].lightDefHandle = -1;
118  }
119 
120  savefile->ReadBool( hasObject );
121  if ( hasObject ) {
122  savefile->ReadRenderEntity( actions[i].renderEntity );
123  actions[i].modelDefHandle = gameRenderWorld->AddEntityDef( &actions[i].renderEntity );
124  } else {
125  memset( &actions[i].renderEntity, 0, sizeof( renderEntity_t ) );
126  actions[i].modelDefHandle = -1;
127  }
128 
129  savefile->ReadFloat( actions[i].delay );
130 
131  // let the FX regenerate the particleSystem
132  actions[i].particleSystem = -1;
133 
134  savefile->ReadInt( actions[i].start );
135  savefile->ReadBool( actions[i].soundStarted );
136  savefile->ReadBool( actions[i].shakeStarted );
137  savefile->ReadBool( actions[i].decalDropped );
138  savefile->ReadBool( actions[i].launched );
139  }
140 }
141 
142 /*
143 ================
144 idEntityFx::Setup
145 ================
146 */
147 void idEntityFx::Setup( const char *fx ) {
148 
149  if ( started >= 0 ) {
150  return; // already started
151  }
152 
153  // early during MP Spawn() with no information. wait till we ReadFromSnapshot for more
154  if ( gameLocal.isClient && ( !fx || fx[0] == '\0' ) ) {
155  return;
156  }
157 
158  systemName = fx;
159  started = 0;
160 
161  fxEffect = static_cast<const idDeclFX *>( declManager->FindType( DECL_FX, systemName.c_str() ) );
162 
163  if ( fxEffect ) {
164  idFXLocalAction localAction;
165 
166  memset( &localAction, 0, sizeof( idFXLocalAction ) );
167 
168  actions.AssureSize( fxEffect->events.Num(), localAction );
169 
170  for( int i = 0; i<fxEffect->events.Num(); i++ ) {
171  const idFXSingleAction& fxaction = fxEffect->events[i];
172 
173  idFXLocalAction& laction = actions[i];
174  if ( fxaction.random1 || fxaction.random2 ) {
175  laction.delay = fxaction.random1 + gameLocal.random.RandomFloat() * ( fxaction.random2 - fxaction.random1 );
176  } else {
177  laction.delay = fxaction.delay;
178  }
179  laction.start = -1;
180  laction.lightDefHandle = -1;
181  laction.modelDefHandle = -1;
182  laction.particleSystem = -1;
183  laction.shakeStarted = false;
184  laction.decalDropped = false;
185  laction.launched = false;
186  }
187  }
188 }
189 
190 /*
191 ================
192 idEntityFx::EffectName
193 ================
194 */
195 const char *idEntityFx::EffectName( void ) {
196  return fxEffect ? fxEffect->GetName() : NULL;
197 }
198 
199 /*
200 ================
201 idEntityFx::Joint
202 ================
203 */
204 const char *idEntityFx::Joint( void ) {
205  return fxEffect ? fxEffect->joint.c_str() : NULL;
206 }
207 
208 /*
209 ================
210 idEntityFx::CleanUp
211 ================
212 */
213 void idEntityFx::CleanUp( void ) {
214  if ( !fxEffect ) {
215  return;
216  }
217  for( int i = 0; i < fxEffect->events.Num(); i++ ) {
218  const idFXSingleAction& fxaction = fxEffect->events[i];
219  idFXLocalAction& laction = actions[i];
220  CleanUpSingleAction( fxaction, laction );
221  }
222 }
223 
224 /*
225 ================
226 idEntityFx::CleanUpSingleAction
227 ================
228 */
230  if ( laction.lightDefHandle != -1 && fxaction.sibling == -1 && fxaction.type != FX_ATTACHLIGHT ) {
232  laction.lightDefHandle = -1;
233  }
234  if ( laction.modelDefHandle != -1 && fxaction.sibling == -1 && fxaction.type != FX_ATTACHENTITY ) {
236  laction.modelDefHandle = -1;
237  }
238  laction.start = -1;
239 }
240 
241 /*
242 ================
243 idEntityFx::Start
244 ================
245 */
246 void idEntityFx::Start( int time ) {
247  if ( !fxEffect ) {
248  return;
249  }
250  started = time;
251  for( int i = 0; i < fxEffect->events.Num(); i++ ) {
252  idFXLocalAction& laction = actions[i];
253  laction.start = time;
254  laction.soundStarted = false;
255  laction.shakeStarted = false;
256  laction.particleSystem = -1;
257  laction.decalDropped = false;
258  laction.launched = false;
259  }
260 }
261 
262 /*
263 ================
264 idEntityFx::Stop
265 ================
266 */
267 void idEntityFx::Stop( void ) {
268  CleanUp();
269  started = -1;
270 }
271 
272 /*
273 ================
274 idEntityFx::Duration
275 ================
276 */
277 const int idEntityFx::Duration( void ) {
278  int max = 0;
279 
280  if ( !fxEffect ) {
281  return max;
282  }
283  for( int i = 0; i < fxEffect->events.Num(); i++ ) {
284  const idFXSingleAction& fxaction = fxEffect->events[i];
285  int d = ( fxaction.delay + fxaction.duration ) * 1000.0f;
286  if ( d > max ) {
287  max = d;
288  }
289  }
290 
291  return max;
292 }
293 
294 
295 /*
296 ================
297 idEntityFx::Done
298 ================
299 */
300 const bool idEntityFx::Done() {
301  if (started > 0 && gameLocal.time > started + Duration()) {
302  return true;
303  }
304  return false;
305 }
306 
307 /*
308 ================
309 idEntityFx::ApplyFade
310 ================
311 */
312 void idEntityFx::ApplyFade( const idFXSingleAction& fxaction, idFXLocalAction& laction, const int time, const int actualStart ) {
313  if ( fxaction.fadeInTime || fxaction.fadeOutTime ) {
314  float fadePct = (float)( time - actualStart ) / ( 1000.0f * ( ( fxaction.fadeInTime != 0 ) ? fxaction.fadeInTime : fxaction.fadeOutTime ) );
315  if (fadePct > 1.0) {
316  fadePct = 1.0;
317  }
318  if ( laction.modelDefHandle != -1 ) {
319  laction.renderEntity.shaderParms[SHADERPARM_RED] = (fxaction.fadeInTime) ? fadePct : 1.0f - fadePct;
320  laction.renderEntity.shaderParms[SHADERPARM_GREEN] = (fxaction.fadeInTime) ? fadePct : 1.0f - fadePct;
321  laction.renderEntity.shaderParms[SHADERPARM_BLUE] = (fxaction.fadeInTime) ? fadePct : 1.0f - fadePct;
322 
324  }
325  if ( laction.lightDefHandle != -1 ) {
326  laction.renderLight.shaderParms[SHADERPARM_RED] = fxaction.lightColor.x * ( (fxaction.fadeInTime) ? fadePct : 1.0f - fadePct );
327  laction.renderLight.shaderParms[SHADERPARM_GREEN] = fxaction.lightColor.y * ( (fxaction.fadeInTime) ? fadePct : 1.0f - fadePct );
328  laction.renderLight.shaderParms[SHADERPARM_BLUE] = fxaction.lightColor.z * ( (fxaction.fadeInTime) ? fadePct : 1.0f - fadePct );
329 
331  }
332  }
333 }
334 
335 /*
336 ================
337 idEntityFx::Run
338 ================
339 */
340 void idEntityFx::Run( int time ) {
341  int ieff, j;
342  idEntity *ent = NULL;
343  const idDict *projectileDef = NULL;
344  idProjectile *projectile = NULL;
345 
346  if ( !fxEffect ) {
347  return;
348  }
349 
350  for( ieff = 0; ieff < fxEffect->events.Num(); ieff++ ) {
351  const idFXSingleAction& fxaction = fxEffect->events[ieff];
352  idFXLocalAction& laction = actions[ieff];
353 
354  //
355  // if we're currently done with this one
356  //
357  if ( laction.start == -1 ) {
358  continue;
359  }
360 
361  //
362  // see if it's delayed
363  //
364  if ( laction.delay ) {
365  if ( laction.start + (time - laction.start) < laction.start + (laction.delay * 1000) ) {
366  continue;
367  }
368  }
369 
370  //
371  // each event can have it's own delay and restart
372  //
373  int actualStart = laction.delay ? laction.start + (int)( laction.delay * 1000 ) : laction.start;
374  float pct = (float)( time - actualStart ) / (1000 * fxaction.duration );
375  if ( pct >= 1.0f ) {
376  laction.start = -1;
377  float totalDelay = 0.0f;
378  if ( fxaction.restart ) {
379  if ( fxaction.random1 || fxaction.random2 ) {
380  totalDelay = fxaction.random1 + gameLocal.random.RandomFloat() * (fxaction.random2 - fxaction.random1);
381  } else {
382  totalDelay = fxaction.delay;
383  }
384  laction.delay = totalDelay;
385  laction.start = time;
386  }
387  continue;
388  }
389 
390  if ( fxaction.fire.Length() ) {
391  for( j = 0; j < fxEffect->events.Num(); j++ ) {
392  if ( fxEffect->events[j].name.Icmp( fxaction.fire ) == 0 ) {
393  actions[j].delay = 0;
394  }
395  }
396  }
397 
398  idFXLocalAction *useAction;
399  if ( fxaction.sibling == -1 ) {
400  useAction = &laction;
401  } else {
402  useAction = &actions[fxaction.sibling];
403  }
404  assert( useAction );
405 
406  switch( fxaction.type ) {
407  case FX_ATTACHLIGHT:
408  case FX_LIGHT: {
409  if ( useAction->lightDefHandle == -1 ) {
410  if ( fxaction.type == FX_LIGHT ) {
411  memset( &useAction->renderLight, 0, sizeof( renderLight_t ) );
412  useAction->renderLight.origin = GetPhysics()->GetOrigin() + fxaction.offset;
413  useAction->renderLight.axis = GetPhysics()->GetAxis();
414  useAction->renderLight.lightRadius[0] = fxaction.lightRadius;
415  useAction->renderLight.lightRadius[1] = fxaction.lightRadius;
416  useAction->renderLight.lightRadius[2] = fxaction.lightRadius;
417  useAction->renderLight.shader = declManager->FindMaterial( fxaction.data, false );
418  useAction->renderLight.shaderParms[ SHADERPARM_RED ] = fxaction.lightColor.x;
419  useAction->renderLight.shaderParms[ SHADERPARM_GREEN ] = fxaction.lightColor.y;
420  useAction->renderLight.shaderParms[ SHADERPARM_BLUE ] = fxaction.lightColor.z;
421  useAction->renderLight.shaderParms[ SHADERPARM_TIMESCALE ] = 1.0f;
422  useAction->renderLight.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( time );
424  useAction->renderLight.pointLight = true;
425  if ( fxaction.noshadows ) {
426  useAction->renderLight.noShadows = true;
427  }
428  useAction->lightDefHandle = gameRenderWorld->AddLightDef( &useAction->renderLight );
429  }
430  if ( fxaction.noshadows ) {
431  for( j = 0; j < fxEffect->events.Num(); j++ ) {
432  idFXLocalAction& laction2 = actions[j];
433  if ( laction2.modelDefHandle != -1 ) {
434  laction2.renderEntity.noShadow = true;
435  }
436  }
437  }
438  }
439  ApplyFade( fxaction, *useAction, time, actualStart );
440  break;
441  }
442  case FX_SOUND: {
443  if ( !useAction->soundStarted ) {
444  useAction->soundStarted = true;
445  const idSoundShader *shader = declManager->FindSound(fxaction.data);
446  StartSoundShader( shader, SND_CHANNEL_ANY, 0, false, NULL );
447  for( j = 0; j < fxEffect->events.Num(); j++ ) {
448  idFXLocalAction& laction2 = actions[j];
449  if ( laction2.lightDefHandle != -1 ) {
452  }
453  }
454  }
455  break;
456  }
457  case FX_DECAL: {
458  if ( !useAction->decalDropped ) {
459  useAction->decalDropped = true;
460  gameLocal.ProjectDecal( GetPhysics()->GetOrigin(), GetPhysics()->GetGravity(), 8.0f, true, fxaction.size, fxaction.data );
461  }
462  break;
463  }
464  case FX_SHAKE: {
465  if ( !useAction->shakeStarted ) {
466  idDict args;
467  args.Clear();
468  args.SetFloat( "kick_time", fxaction.shakeTime );
469  args.SetFloat( "kick_amplitude", fxaction.shakeAmplitude );
470  for ( j = 0; j < gameLocal.numClients; j++ ) {
471  idPlayer *player = gameLocal.GetClientByNum( j );
472  if ( player && ( player->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin() ).LengthSqr() < Square( fxaction.shakeDistance ) ) {
473  if ( !gameLocal.isMultiplayer || !fxaction.shakeIgnoreMaster || GetBindMaster() != player ) {
474  player->playerView.DamageImpulse( fxaction.offset, &args );
475  }
476  }
477  }
478  if ( fxaction.shakeImpulse != 0.0f && fxaction.shakeDistance != 0.0f ) {
479  idEntity *ignore_ent = NULL;
480  if ( gameLocal.isMultiplayer ) {
481  ignore_ent = this;
482  if ( fxaction.shakeIgnoreMaster ) {
483  ignore_ent = GetBindMaster();
484  }
485  }
486  // lookup the ent we are bound to?
487  gameLocal.RadiusPush( GetPhysics()->GetOrigin(), fxaction.shakeDistance, fxaction.shakeImpulse, this, ignore_ent, 1.0f, true );
488  }
489  useAction->shakeStarted = true;
490  }
491  break;
492  }
493  case FX_ATTACHENTITY:
494  case FX_PARTICLE:
495  case FX_MODEL: {
496  if ( useAction->modelDefHandle == -1 ) {
497  memset( &useAction->renderEntity, 0, sizeof( renderEntity_t ) );
498  useAction->renderEntity.origin = GetPhysics()->GetOrigin() + fxaction.offset;
499  useAction->renderEntity.axis = (fxaction.explicitAxis) ? fxaction.axis : GetPhysics()->GetAxis();
500  useAction->renderEntity.hModel = renderModelManager->FindModel( fxaction.data );
501  useAction->renderEntity.shaderParms[ SHADERPARM_RED ] = 1.0f;
502  useAction->renderEntity.shaderParms[ SHADERPARM_GREEN ] = 1.0f;
503  useAction->renderEntity.shaderParms[ SHADERPARM_BLUE ] = 1.0f;
504  useAction->renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( time );
505  useAction->renderEntity.shaderParms[3] = 1.0f;
506  useAction->renderEntity.shaderParms[5] = 0.0f;
507  if ( useAction->renderEntity.hModel ) {
508  useAction->renderEntity.bounds = useAction->renderEntity.hModel->Bounds( &useAction->renderEntity );
509  }
510  useAction->modelDefHandle = gameRenderWorld->AddEntityDef( &useAction->renderEntity );
511  } else if ( fxaction.trackOrigin ) {
512  useAction->renderEntity.origin = GetPhysics()->GetOrigin() + fxaction.offset;
513  useAction->renderEntity.axis = fxaction.explicitAxis ? fxaction.axis : GetPhysics()->GetAxis();
514 #ifdef _D3XP
515  gameRenderWorld->UpdateEntityDef( useAction->modelDefHandle, &useAction->renderEntity );
516 #endif
517  }
518  ApplyFade( fxaction, *useAction, time, actualStart );
519  break;
520  }
521  case FX_LAUNCH: {
522  if ( gameLocal.isClient ) {
523  // client never spawns entities outside of ClientReadSnapshot
524  useAction->launched = true;
525  break;
526  }
527  if ( !useAction->launched ) {
528  useAction->launched = true;
529  projectile = NULL;
530  // FIXME: may need to cache this if it is slow
531  projectileDef = gameLocal.FindEntityDefDict( fxaction.data, false );
532  if ( !projectileDef ) {
533  gameLocal.Warning( "projectile \'%s\' not found", fxaction.data.c_str() );
534  } else {
535  gameLocal.SpawnEntityDef( *projectileDef, &ent, false );
536  if ( ent && ent->IsType( idProjectile::Type ) ) {
537  projectile = ( idProjectile * )ent;
538  projectile->Create( this, GetPhysics()->GetOrigin(), GetPhysics()->GetAxis()[0] );
539  projectile->Launch( GetPhysics()->GetOrigin(), GetPhysics()->GetAxis()[0], vec3_origin );
540  }
541  }
542  }
543  break;
544  }
545 #ifdef _D3XP
546  case FX_SHOCKWAVE: {
547  if ( gameLocal.isClient ) {
548  useAction->shakeStarted = true;
549  break;
550  }
551  if ( !useAction->shakeStarted ) {
552  idStr shockDefName;
553  useAction->shakeStarted = true;
554 
555  shockDefName = fxaction.data;
556  if ( !shockDefName.Length() ) {
557  shockDefName = "func_shockwave";
558  }
559 
560  projectileDef = gameLocal.FindEntityDefDict( shockDefName, false );
561  if ( !projectileDef ) {
562  gameLocal.Warning( "shockwave \'%s\' not found", shockDefName.c_str() );
563  } else {
564  gameLocal.SpawnEntityDef( *projectileDef, &ent );
565  ent->SetOrigin( GetPhysics()->GetOrigin() + fxaction.offset );
566  ent->PostEventMS( &EV_Remove, ent->spawnArgs.GetInt( "duration" ) );
567  }
568  }
569  break;
570  }
571 #endif
572  }
573  }
574 }
575 
576 /*
577 ================
578 idEntityFx::idEntityFx
579 ================
580 */
582  fxEffect = NULL;
583  started = -1;
584  nextTriggerTime = -1;
585  fl.networkSync = true;
586 }
587 
588 /*
589 ================
590 idEntityFx::~idEntityFx
591 ================
592 */
594  CleanUp();
595  fxEffect = NULL;
596 }
597 
598 /*
599 ================
600 idEntityFx::Spawn
601 ================
602 */
603 void idEntityFx::Spawn( void ) {
604 
605  if ( g_skipFX.GetBool() ) {
606  return;
607  }
608 
609  const char *fx;
610  nextTriggerTime = 0;
611  fxEffect = NULL;
612  if ( spawnArgs.GetString( "fx", "", &fx ) ) {
613  systemName = fx;
614  }
615  if ( !spawnArgs.GetBool( "triggered" ) ) {
616  Setup( fx );
617  if ( spawnArgs.GetBool( "test" ) || spawnArgs.GetBool( "start" ) || spawnArgs.GetFloat ( "restart" ) ) {
618  PostEventMS( &EV_Activate, 0, this );
619  }
620  }
621 }
622 
623 /*
624 ================
625 idEntityFx::Think
626 
627  Clears any visual fx started when {item,mob,player} was spawned
628 ================
629 */
630 void idEntityFx::Think( void ) {
631  if ( g_skipFX.GetBool() ) {
632  return;
633  }
634 
635  if ( thinkFlags & TH_THINK ) {
636  Run( gameLocal.time );
637  }
638 
639  RunPhysics();
640  Present();
641 }
642 
643 /*
644 ================
645 idEntityFx::Event_ClearFx
646 
647  Clears any visual fx started when item(mob) was spawned
648 ================
649 */
651 
652  if ( g_skipFX.GetBool() ) {
653  return;
654  }
655 
656  Stop();
657  CleanUp();
659 
660  if ( spawnArgs.GetBool("test") ) {
661  PostEventMS( &EV_Activate, 0, this );
662  } else {
663  if ( spawnArgs.GetFloat( "restart" ) || !spawnArgs.GetBool( "triggered")) {
664  float rest = spawnArgs.GetFloat( "restart", "0" );
665  if ( rest == 0.0f ) {
666  PostEventSec( &EV_Remove, 0.1f );
667  } else {
668  rest *= gameLocal.random.RandomFloat();
669  PostEventSec( &EV_Activate, rest, this );
670  }
671  }
672  }
673 }
674 
675 /*
676 ================
677 idEntityFx::Event_Trigger
678 ================
679 */
681 
682  if ( g_skipFX.GetBool() ) {
683  return;
684  }
685 
686  float fxActionDelay;
687  const char *fx;
688 
689  if ( gameLocal.time < nextTriggerTime ) {
690  return;
691  }
692 
693  if ( spawnArgs.GetString( "fx", "", &fx) ) {
694  Setup( fx );
695  Start( gameLocal.time );
698  }
699 
700  fxActionDelay = spawnArgs.GetFloat( "fxActionDelay" );
701  if ( fxActionDelay != 0.0f ) {
702  nextTriggerTime = gameLocal.time + SEC2MS( fxActionDelay );
703  } else {
704  // prevent multiple triggers on same frame
706  }
707  PostEventSec( &EV_Fx_Action, fxActionDelay, activator );
708 }
709 
710 
711 /*
712 ================
713 idEntityFx::StartFx
714 ================
715 */
716 idEntityFx *idEntityFx::StartFx( const char *fx, const idVec3 *useOrigin, const idMat3 *useAxis, idEntity *ent, bool bind ) {
717 
718  if ( g_skipFX.GetBool() || !fx || !*fx ) {
719  return NULL;
720  }
721 
722  idDict args;
723  args.SetBool( "start", true );
724  args.Set( "fx", fx );
725  idEntityFx *nfx = static_cast<idEntityFx *>( gameLocal.SpawnEntityType( idEntityFx::Type, &args ) );
726  if ( nfx->Joint() && *nfx->Joint() ) {
727  nfx->BindToJoint( ent, nfx->Joint(), true );
728  nfx->SetOrigin( vec3_origin );
729  } else {
730  nfx->SetOrigin( (useOrigin) ? *useOrigin : ent->GetPhysics()->GetOrigin() );
731  nfx->SetAxis( (useAxis) ? *useAxis : ent->GetPhysics()->GetAxis() );
732  }
733 
734  if ( bind ) {
735  // never bind to world spawn
736  if ( ent != gameLocal.world ) {
737  nfx->Bind( ent, true );
738  }
739  }
740  nfx->Show();
741  return nfx;
742 }
743 
744 /*
745 =================
746 idEntityFx::WriteToSnapshot
747 =================
748 */
750  GetPhysics()->WriteToSnapshot( msg );
751  WriteBindToSnapshot( msg );
752  msg.WriteLong( ( fxEffect != NULL ) ? gameLocal.ServerRemapDecl( -1, DECL_FX, fxEffect->Index() ) : -1 );
753  msg.WriteLong( started );
754 }
755 
756 /*
757 =================
758 idEntityFx::ReadFromSnapshot
759 =================
760 */
762  int fx_index, start_time, max_lapse;
763 
764  GetPhysics()->ReadFromSnapshot( msg );
765  ReadBindFromSnapshot( msg );
766  fx_index = gameLocal.ClientRemapDecl( DECL_FX, msg.ReadLong() );
767  start_time = msg.ReadLong();
768 
769  if ( fx_index != -1 && start_time > 0 && !fxEffect && started < 0 ) {
770  spawnArgs.GetInt( "effect_lapse", "1000", max_lapse );
771  if ( gameLocal.time - start_time > max_lapse ) {
772  // too late, skip the effect completely
773  started = 0;
774  return;
775  }
776  const idDeclFX *fx = static_cast<const idDeclFX *>( declManager->DeclByIndex( DECL_FX, fx_index ) );
777  if ( !fx ) {
778  gameLocal.Error( "FX at index %d not found", fx_index );
779  }
780  fxEffect = fx;
781  Setup( fx->GetName() );
782  Start( start_time );
783  }
784 }
785 
786 /*
787 =================
788 idEntityFx::ClientPredictionThink
789 =================
790 */
792  if ( gameLocal.isNewFrame ) {
793  Run( gameLocal.time );
794  }
795  RunPhysics();
796  Present();
797 }
798 
799 /*
800 ===============================================================================
801 
802  idTeleporter
803 
804 ===============================================================================
805 */
806 
808  EVENT( EV_Fx_Action, idTeleporter::Event_DoAction )
809 END_CLASS
810 
811 /*
812 ================
813 idTeleporter::Event_DoAction
814 ================
815 */
816 void idTeleporter::Event_DoAction( idEntity *activator ) {
817  float angle;
818 
819  angle = spawnArgs.GetFloat( "angle" );
820  idAngles a( 0, spawnArgs.GetFloat( "angle" ), 0 );
821  activator->Teleport( GetPhysics()->GetOrigin(), a, NULL );
822 }
virtual const idVec3 & GetOrigin(int id=0) const =0
bool explicitAxis
Definition: DeclFX.h:88
renderLight_t renderLight
Definition: Fx.h:41
idStr systemName
Definition: Fx.h:94
renderEntity_t renderEntity
Definition: Entity.h:371
bool trackOrigin
Definition: DeclFX.h:91
float GetFloat(const char *key, const char *defaultString="0") const
Definition: Dict.h:248
int GetInt(const char *key, const char *defaultString="0") const
Definition: Dict.h:252
bool PostEventSec(const idEventDef *ev, float time)
Definition: Class.cpp:747
void WriteBindToSnapshot(idBitMsgDelta &msg) const
Definition: Entity.cpp:4756
float duration
Definition: DeclFX.h:65
assert(prefInfo.fullscreenBtn)
virtual const idSoundShader * FindSound(const char *name, bool makeDefault=true)=0
const idDict * FindEntityDefDict(const char *name, bool makeDefault=true) const
virtual void FreeLightDef(qhandle_t lightHandle)=0
const idDeclFX * fxEffect
Definition: Fx.h:92
void Stop(void)
Definition: Fx.cpp:267
idVec3 lightColor
Definition: DeclFX.h:79
virtual void Launch(const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity, const float timeSinceFire=0.0f, const float launchPower=1.0f, const float dmgPower=1.0f)
Definition: Projectile.cpp:306
struct idEntity::entityFlags_s fl
void BindToJoint(idEntity *master, const char *jointname, bool orientated)
Definition: Entity.cpp:1921
void Bind(idEntity *master, bool orientated)
Definition: Entity.cpp:1896
idStr joint
Definition: DeclFX.h:107
int modelDefHandle
Definition: Fx.h:44
float shakeTime
Definition: DeclFX.h:70
void SetNum(int newnum, bool resize=true)
Definition: List.h:289
void Event_ClearFx(void)
Definition: Fx.cpp:650
const idEventDef EV_Activate("activate","e")
bool isNewFrame
Definition: Game_local.h:333
idEntity * GetBindMaster(void) const
Definition: Entity.cpp:2153
virtual qhandle_t AddEntityDef(const renderEntity_t *re)=0
idRandom random
Definition: Game_local.h:291
int Length(void) const
Definition: Str.h:702
void SetAxis(const idMat3 &axis)
Definition: Entity.cpp:2796
void void void void void Error(const char *fmt,...) const id_attribute((format(printf
Definition: Game_local.cpp:783
bool isMultiplayer
Definition: Game_local.h:325
void AssureSize(int newSize)
Definition: List.h:445
bool IsType(const idTypeInfo &c) const
Definition: Class.h:337
idStr data
Definition: DeclFX.h:60
int ClientRemapDecl(declType_t type, int index)
void Setup(const char *fx)
Definition: Fx.cpp:147
float z
Definition: Vector.h:320
case const int
Definition: Callbacks.cpp:52
virtual void ReadFromSnapshot(const idBitMsgDelta &msg)
Definition: Fx.cpp:761
int nextTriggerTime
Definition: Fx.h:91
bool soundStarted
Definition: Fx.h:48
virtual void Think()
Definition: Fx.cpp:630
void ReadFX(const idDeclFX *&fx)
Definition: SaveGame.cpp:1180
bool isClient
Definition: Game_local.h:327
const char * GetName(void) const
Definition: DeclManager.h:140
Definition: Vector.h:316
case const float
Definition: Callbacks.cpp:62
void ReadBool(bool &value)
Definition: SaveGame.cpp:976
qhandle_t lightDefHandle
Definition: Fx.h:42
ID_INLINE T Square(T x)
Definition: Math.h:104
const int SHADERPARM_GREEN
Definition: RenderWorld.h:47
float random1
Definition: DeclFX.h:76
float fadeOutTime
Definition: DeclFX.h:69
void ApplyFade(const idFXSingleAction &fxaction, idFXLocalAction &laction, const int time, const int actualStart)
Definition: Fx.cpp:312
void Create(idEntity *owner, const idVec3 &start, const idVec3 &dir)
Definition: Projectile.cpp:218
virtual qhandle_t AddLightDef(const renderLight_t *rlight)=0
virtual const idMaterial * FindMaterial(const char *name, bool makeDefault=true)=0
int particleSystem
Definition: Fx.h:46
void Set(const char *key, const char *value)
Definition: Dict.cpp:275
float fadeInTime
Definition: DeclFX.h:68
float x
Definition: Vector.h:318
idDict spawnArgs
Definition: Entity.h:122
int i
Definition: process.py:33
void SetFloat(const char *key, float val)
Definition: Dict.h:188
GLuint GLuint num
Definition: glext.h:5390
void ReadRenderEntity(renderEntity_t &renderEntity)
Definition: SaveGame.cpp:1269
const int Duration(void)
Definition: Fx.cpp:277
#define EVENT(event, function)
Definition: Class.h:53
float lightRadius
Definition: DeclFX.h:74
float shaderParms[MAX_ENTITY_SHADER_PARMS]
Definition: RenderWorld.h:201
const int SHADERPARM_TIMESCALE
Definition: RenderWorld.h:50
idEntity * SpawnEntityType(const idTypeInfo &classdef, const idDict *args=NULL, bool bIsClientReadSnapshot=false)
void void void Warning(const char *fmt,...) const id_attribute((format(printf
Definition: Game_local.cpp:735
bool StartSoundShader(const idSoundShader *shader, const s_channelType channel, int soundShaderFlags, bool broadcast, int *length)
Definition: Entity.cpp:1656
const int SHADERPARM_BLUE
Definition: RenderWorld.h:48
class idPlayerView playerView
Definition: Player.h:251
int ServerRemapDecl(int clientNum, declType_t type, int index)
virtual void Show(void)
Definition: Entity.cpp:1239
virtual void FreeEntityDef(qhandle_t entityHandle)=0
int Index(void) const
Definition: DeclManager.h:165
virtual void ReadFromSnapshot(const idBitMsgDelta &msg)=0
idMat3 axis
Definition: DeclFX.h:81
idPhysics * GetPhysics(void) const
Definition: Entity.cpp:2607
void WriteLong(int c)
Definition: BitMsg.h:554
const char * GetString(const char *key, const char *defaultString="") const
Definition: Dict.h:240
idStr fire
Definition: DeclFX.h:62
bool SpawnEntityDef(const idDict &args, idEntity **ent=NULL, bool setDefaults=true)
void ReadFloat(float &value)
Definition: SaveGame.cpp:967
idVec3 lightRadius
Definition: RenderWorld.h:178
int start
Definition: Fx.h:47
idWorldspawn * world
Definition: Game_local.h:280
float shakeImpulse
Definition: DeclFX.h:73
void Start(int time)
Definition: Fx.cpp:246
float RandomFloat(void)
Definition: Random.h:82
idVec3 vec3_origin(0.0f, 0.0f, 0.0f)
idSoundEmitter * referenceSound
Definition: Game.h:209
void ReadRenderLight(renderLight_t &renderLight)
Definition: SaveGame.cpp:1333
void Spawn(void)
Definition: Fx.cpp:603
bool GetBool(const char *key, const char *defaultString="0") const
Definition: Dict.h:256
Definition: Dict.h:65
#define NULL
Definition: Lib.h:88
void Clear(void)
Definition: Dict.cpp:201
void DamageImpulse(idVec3 localKickDir, const idDict *damageDef)
Definition: PlayerView.cpp:252
virtual idRenderModel * FindModel(const char *modelName)=0
virtual const idDecl * FindType(declType_t type, const char *name, bool makeDefault=true)=0
float y
Definition: Vector.h:319
void RadiusPush(const idVec3 &origin, const float radius, const float push, const idEntity *inflictor, const idEntity *ignore, float inflictorScale, const bool quake)
int ReadLong(void) const
Definition: BitMsg.h:621
float restart
Definition: DeclFX.h:66
Definition: Fx.h:54
virtual const idMat3 & GetAxis(int id=0) const =0
bool launched
Definition: Fx.h:51
float shakeDistance
Definition: DeclFX.h:72
void Event_Trigger(idEntity *activator)
Definition: Fx.cpp:680
float size
Definition: DeclFX.h:67
virtual void UpdateEntityDef(qhandle_t entityHandle, const renderEntity_t *re)=0
bool decalDropped
Definition: Fx.h:50
const char * EffectName(void)
Definition: Fx.cpp:195
idGameLocal gameLocal
Definition: Game_local.cpp:64
void SetBool(const char *key, bool val)
Definition: Dict.h:196
bool RunPhysics(void)
Definition: Entity.cpp:2616
const int SHADERPARM_TIMEOFFSET
Definition: RenderWorld.h:51
#define END_CLASS
Definition: Class.h:54
idRenderModel * hModel
Definition: RenderWorld.h:81
GLubyte GLubyte GLubyte a
Definition: glext.h:4662
virtual void UpdateLightDef(qhandle_t lightHandle, const renderLight_t *rlight)=0
virtual idBounds Bounds(const struct renderEntity_s *ent=NULL) const =0
bool shakeIgnoreMaster
Definition: DeclFX.h:86
float delay
Definition: DeclFX.h:64
virtual void Present(void)
Definition: Entity.cpp:1471
int numClients
Definition: Game_local.h:271
const idEventDef EV_Fx_KillFx("_killfx")
idDeclManager * declManager
#define SEC2MS(t)
Definition: Math.h:59
idPlayer * GetClientByNum(int current) const
idRenderModelManager * renderModelManager
Definition: Matrix.h:333
const int SHADERPARM_RED
Definition: RenderWorld.h:46
idCVar g_skipFX("g_skipFX","0", CVAR_GAME|CVAR_BOOL,"")
idList< idFXLocalAction > actions
Definition: Fx.h:93
idList< idFXSingleAction > events
Definition: DeclFX.h:106
bool GetBool(void) const
Definition: CVarSystem.h:142
virtual const idDecl * DeclByIndex(declType_t type, int index, bool forceParse=true)=0
virtual void WriteToSnapshot(idBitMsgDelta &msg) const =0
idVec3 offset
Definition: DeclFX.h:80
virtual ~idEntityFx()
Definition: Fx.cpp:593
tuple f
Definition: idal.py:89
void ProjectDecal(const idVec3 &origin, const idVec3 &dir, float depth, bool parallel, float size, const char *material, float angle=0)
int Num(void) const
Definition: List.h:265
#define CLASS_DECLARATION(nameofsuperclass, nameofclass)
Definition: Class.h:110
Definition: Str.h:116
idBounds bounds
Definition: RenderWorld.h:95
void CleanUpSingleAction(const idFXSingleAction &fxaction, idFXLocalAction &laction)
Definition: Fx.cpp:229
const char * Joint(void)
Definition: Fx.cpp:204
const char * c_str(void) const
Definition: Str.h:487
virtual void ClientPredictionThink(void)
Definition: Fx.cpp:791
void BecomeActive(int flags)
Definition: Entity.cpp:995
refSound_t refSound
Definition: Entity.h:373
const bool Done()
Definition: Fx.cpp:300
const idEventDef EV_Remove("<immediateremove>", NULL)
renderEntity_t renderEntity
Definition: Fx.h:43
int started
Definition: Fx.h:90
float delay
Definition: Fx.h:45
GLint j
Definition: qgl.h:264
const idEventDef EV_Fx_Action("_fxAction","e")
void Run(int time)
Definition: Fx.cpp:340
virtual void WriteToSnapshot(idBitMsgDelta &msg) const
Definition: Fx.cpp:749
void Restore(idRestoreGame *savefile)
Definition: Fx.cpp:96
idEntityFx()
Definition: Fx.cpp:581
idRenderWorld * gameRenderWorld
Definition: Game_local.cpp:55
void ReadBindFromSnapshot(const idBitMsgDelta &msg)
Definition: Entity.cpp:4780
static idEntityFx * StartFx(const char *fx, const idVec3 *useOrigin, const idMat3 *useAxis, idEntity *ent, bool bind)
Definition: Fx.cpp:716
bool PostEventMS(const idEventDef *ev, int time)
Definition: Class.cpp:666
void SetOrigin(const idVec3 &org)
Definition: Entity.cpp:2784
#define max(x, y)
Definition: os.h:70
idSoundEmitter * referenceSound
Definition: RenderWorld.h:202
const idMaterial * shader
Definition: RenderWorld.h:200
int thinkFlags
Definition: Entity.h:125
float shakeAmplitude
Definition: DeclFX.h:71
float shaderParms[MAX_ENTITY_SHADER_PARMS]
Definition: RenderWorld.h:127
void ReadString(idStr &string)
Definition: SaveGame.cpp:985
void BecomeInactive(int flags)
Definition: Entity.cpp:1025
bool shakeStarted
Definition: Fx.h:49
void ReadInt(int &value)
Definition: SaveGame.cpp:922
float random2
Definition: DeclFX.h:77
bool noshadows
Definition: DeclFX.h:89
GLuint start
Definition: glext.h:2845
#define MS2SEC(t)
Definition: Math.h:60
void CleanUp(void)
Definition: Fx.cpp:213