home *** CD-ROM | disk | FTP | other *** search
/ GameStar 2006 March / Gamestar_82_2006-03_dvd.iso / DVDStar / Editace / quake4_sdkv10.exe / source / game / Effect.cpp < prev    next >
C/C++ Source or Header  |  2005-11-14  |  11KB  |  463 lines

  1. #include "../idlib/precompiled.h"
  2. #pragma hdrstop
  3.  
  4. #include "Game_local.h"
  5. #include "Effect.h"
  6. #include "client/ClientEffect.h"
  7.  
  8. const idEventDef EV_LookAtTarget( "lookAtTarget", NULL );
  9. const idEventDef EV_Attenuate( "attenuate", "f" );
  10.  
  11. CLASS_DECLARATION( idEntity, rvEffect )
  12.     EVENT( EV_Activate,                rvEffect::Event_Activate )
  13.     EVENT( EV_LookAtTarget,            rvEffect::Event_LookAtTarget )
  14.     EVENT( EV_Earthquake,            rvEffect::Event_EarthQuake )
  15.     EVENT( EV_Camera_Start,            rvEffect::Event_Start )
  16.     EVENT( EV_Camera_Stop,            rvEffect::Event_Stop )
  17.     EVENT( EV_Attenuate,            rvEffect::Event_Attenuate )
  18.     EVENT( EV_IsActive,                rvEffect::Event_IsActive )
  19. END_CLASS
  20.  
  21. /*
  22. ================
  23. rvEffect::rvEffect
  24. ================
  25. */
  26. rvEffect::rvEffect ( void ) {
  27.     fl.networkSync = true;
  28.     loop = false;
  29.     lookAtTarget = false;
  30.     effect = NULL;
  31.     endOrigin.Zero();
  32. }
  33.  
  34. /*
  35. ================
  36. rvEffect::Spawn
  37. ================
  38. */
  39. void rvEffect::Spawn( void ) {
  40.     const char* fx;
  41.     if ( !spawnArgs.GetString ( "fx", "", &fx ) || !*fx ) {
  42.         if ( !( gameLocal.editors & EDITOR_FX ) ) {
  43.             gameLocal.Warning ( "no effect file specified on effect entity '%s'", name.c_str() );
  44.             PostEventMS ( &EV_Remove, 0 );
  45.             return;
  46.         }
  47.     } else {
  48.         effect = ( const idDecl * )declManager->FindEffect( spawnArgs.GetString ( "fx" ) );
  49.         if( effect->IsImplicit() ) {
  50.             common->Warning( "Unknown effect \'%s\' on entity \'%s\'", spawnArgs.GetString ( "fx" ), GetName() );
  51.         }
  52.     }
  53.     
  54.     spawnArgs.GetVector ( "endOrigin", "0 0 0", endOrigin );
  55.     
  56.     spawnArgs.GetBool ( "loop", "0", loop );
  57.  
  58.     // If look at target is set the effect will continually update itself to look at its target
  59.     spawnArgs.GetBool( "lookAtTarget", "0", lookAtTarget );
  60.  
  61.     renderEntity.shaderParms[SHADERPARM_ALPHA] = spawnArgs.GetFloat ( "_alpha", "1" );
  62.     renderEntity.shaderParms[SHADERPARM_BRIGHTNESS] = spawnArgs.GetFloat ( "_brightness", "1" );
  63.  
  64.     if( spawnArgs.GetBool( "start_on", loop ? "1" : "0" ) ) {
  65.         ProcessEvent( &EV_Activate, this );
  66.     }        
  67. #if 0
  68.     // If anyone ever gets around to a flood fill from the origin rather than the over generous PushVolumeIntoTree bounds,
  69.     // this warning will become useful. Until then, it's a bogus warning.
  70.     if( gameRenderWorld->PointInArea( GetPhysics()->GetOrigin() ) < 0 ) {
  71.         common->Warning( "Effect \'%s\' out of world", name.c_str() );
  72.     }
  73. #endif
  74. }
  75.  
  76. /*
  77. ================
  78. rvEffect::Think
  79. ================
  80. */
  81. void rvEffect::Think( void ) {
  82.     
  83.     if( clientEntities.IsListEmpty ( ) ) {
  84.         BecomeInactive( TH_THINK );
  85.  
  86.         // Should the func_fx be removed now?
  87.         if( !(gameLocal.editors & EDITOR_FX) && spawnArgs.GetBool( "remove" ) ) {        
  88.             PostEventMS( &EV_Remove, 0 );
  89.         } 
  90.         
  91.         return;
  92.     }    
  93.     else if( lookAtTarget ) {
  94.         // If activated and looking at its target then update the target information
  95.         ProcessEvent( &EV_LookAtTarget );
  96.     }    
  97.  
  98.     UpdateVisuals();
  99.     Present ( );
  100. }
  101.  
  102. /*
  103. ================
  104. rvEffect::Save
  105. ================
  106. */
  107. void rvEffect::Save ( idSaveGame *savefile ) const {
  108.     savefile->WriteBool ( loop );
  109.     savefile->WriteBool ( lookAtTarget );
  110.     savefile->WriteString ( effect->GetName() );
  111.     savefile->WriteVec3 ( endOrigin );
  112.     clientEffect.Save ( savefile );
  113. }
  114.  
  115. /*
  116. ================
  117. rvEffect::Restore
  118. ================
  119. */
  120. void rvEffect::Restore ( idRestoreGame *savefile ) {
  121.     idStr    name;
  122.  
  123.     savefile->ReadBool ( loop );
  124.     savefile->ReadBool ( lookAtTarget );
  125.     savefile->ReadString ( name );
  126.     effect = declManager->FindType( DECL_EFFECT, name );
  127.     savefile->ReadVec3 ( endOrigin );
  128.     clientEffect.Restore ( savefile );
  129. }
  130.  
  131. /*
  132. ================
  133. rvEffect::Think
  134. ================
  135. */
  136. void rvEffect::Stop( bool destroyParticles ) {
  137.     StopEffect ( effect, destroyParticles );
  138. }
  139.  
  140. /*
  141. ================
  142. rvEffect::Play
  143. ================
  144. */
  145. bool rvEffect::Play( void ) {
  146.     clientEffect = PlayEffect ( effect, renderEntity.origin, renderEntity.axis, loop, endOrigin );
  147.     if ( clientEffect ) {
  148.  
  149.         idVec4 color;
  150.         color[0] = renderEntity.shaderParms[SHADERPARM_RED];
  151.         color[1] = renderEntity.shaderParms[SHADERPARM_GREEN];
  152.         color[2] = renderEntity.shaderParms[SHADERPARM_BLUE];
  153.         color[3] = renderEntity.shaderParms[SHADERPARM_ALPHA];
  154.         clientEffect->SetColor ( color );
  155.         clientEffect->SetBrightness ( renderEntity.shaderParms[ SHADERPARM_BRIGHTNESS ] );
  156.         clientEffect->SetAmbient( true );
  157.  
  158.         BecomeActive ( TH_THINK );
  159.         return true;
  160.     }
  161.     
  162.     return false;
  163. }
  164.  
  165. /*
  166. ================
  167. rvEffect::Attenuate
  168. ================
  169. */
  170. void rvEffect::Attenuate ( float attenuation ) {
  171.     rvClientEntity* cent;
  172.     for( cent = clientEntities.Next(); cent != NULL; cent = cent->spawnNode.Next() ) {
  173. // RAVEN BEGIN
  174. // jnewquist: Use accessor for static class type 
  175.         if ( cent->IsType ( rvClientEffect::GetClassType() ) ) {
  176. // RAVEN END
  177.             static_cast<rvClientEffect*>(cent)->Attenuate ( attenuation );
  178.         }
  179.     }            
  180. }
  181.  
  182. /*
  183. ================
  184. rvEffect::Restart
  185. ================
  186. */
  187. void rvEffect::Restart( void ) {
  188.     Stop( false );    
  189.     
  190.     if( loop )    {
  191.         Play();
  192.     }
  193. }
  194.  
  195. /*
  196. ================
  197. rvEffect::UpdateChangeableSpawnArgs
  198. ================
  199. */
  200. void rvEffect::UpdateChangeableSpawnArgs( const idDict *source ) {
  201.     const char* fx;
  202.     const idDecl *newEffect;
  203.     bool        newLoop;
  204.  
  205.     idEntity::UpdateChangeableSpawnArgs(source);
  206.     if ( !source ) {
  207.         return;
  208.     }
  209.  
  210.     if ( source->GetString ( "fx", "", &fx ) && *fx ) {
  211.         newEffect = ( const idDecl * )declManager->FindEffect( fx );
  212.     } else {
  213.         newEffect = NULL;
  214.     }
  215.  
  216.     idVec3 color;
  217.     source->GetVector( "_color", "1 1 1", color );
  218.     renderEntity.shaderParms[ SHADERPARM_RED ]     = color[0];
  219.     renderEntity.shaderParms[ SHADERPARM_GREEN ] = color[1];
  220.     renderEntity.shaderParms[ SHADERPARM_BLUE ]     = color[2];
  221.     renderEntity.shaderParms[ SHADERPARM_ALPHA ] = source->GetFloat ( "_alpha", "1" );
  222.     renderEntity.shaderParms[ SHADERPARM_BRIGHTNESS ] = source->GetFloat ( "_brightness", "1" );
  223.     if ( clientEffect ) {        
  224.         clientEffect->SetColor ( idVec4(color[0],color[1],color[2],renderEntity.shaderParms[ SHADERPARM_ALPHA ]) );
  225.         clientEffect->SetBrightness ( renderEntity.shaderParms[ SHADERPARM_BRIGHTNESS ] );
  226.     }
  227.  
  228.     source->GetBool ( "loop", "0", newLoop );
  229.  
  230.     spawnArgs.Copy( *source );
  231.     
  232.     // IF the effect handle has changed or the loop status has changed then restart the effect
  233.     if ( newEffect != effect || loop != newLoop ) {
  234.         Stop ( false );        
  235.     
  236.         loop = newLoop;
  237.         effect = newEffect;
  238.  
  239.         if ( effect ) {
  240.             Play ( );
  241.             BecomeActive( TH_THINK );
  242.             UpdateVisuals();
  243.         } else {
  244.             BecomeInactive ( TH_THINK );
  245.             UpdateVisuals();
  246.         }
  247.     }
  248. }
  249.  
  250. /*
  251. ===============
  252. rvEffect::ShowEditingDialog
  253. ===============
  254. */
  255. void rvEffect::ShowEditingDialog( void ) {
  256.     common->InitTool( EDITOR_FX, &spawnArgs );
  257. }
  258.  
  259. /*
  260. =================
  261. rvEffect::WriteToSnapshot
  262. =================
  263. */
  264. void rvEffect::WriteToSnapshot( idBitMsgDelta &msg ) const {
  265.     GetPhysics()->WriteToSnapshot( msg );
  266.     WriteBindToSnapshot( msg );
  267.     idGameLocal::WriteDecl( msg, effect );
  268.     msg.WriteBits( loop, 1 );
  269. }
  270.  
  271. /*
  272. =================
  273. rvEffect::ReadFromSnapshot
  274. =================
  275. */
  276. void rvEffect::ReadFromSnapshot( const idBitMsgDelta &msg ) {
  277.     const idDecl *old = effect;
  278.     GetPhysics()->ReadFromSnapshot( msg );
  279.     ReadBindFromSnapshot( msg );
  280.     
  281.     effect = idGameLocal::ReadDecl( msg, DECL_EFFECT );
  282.     loop = ( msg.ReadBits( 1 ) != 0 );
  283.  
  284.     if ( effect && !old ) {
  285.         // TODO: need to account for when the effect really started
  286.         Play();
  287.     }
  288. }
  289.  
  290. /*
  291. =================
  292. rvEffect::ClientPredictionThink
  293. =================
  294. */
  295. void rvEffect::ClientPredictionThink( void ) {
  296.     if ( gameLocal.isNewFrame ) {     
  297.         Think ( );
  298.     }
  299.     RunPhysics();
  300.     Present();
  301. }
  302.  
  303. /*
  304. ================
  305. rvEffect::Event_Start
  306. ================
  307. */
  308. void rvEffect::Event_Start ( void ) {
  309.     if( !effect || !clientEntities.IsListEmpty ( ) ) {
  310.         return;
  311.     }
  312.  
  313.     if( !Play() ) {
  314.         if ( gameLocal.isMultiplayer && !gameLocal.isClient && !gameLocal.isListenServer ) {
  315.             // no effects on dedicated server
  316.         } else {
  317.             gameLocal.Warning( "Unable to play effect '%s'", effect->GetName() );
  318.         }
  319.         BecomeInactive ( TH_THINK );
  320.     }
  321.  
  322.     ProcessEvent( &EV_LookAtTarget );
  323. }
  324.  
  325. /*
  326. ================
  327. rvEffect::Event_Stop
  328. ================
  329. */
  330. void rvEffect::Event_Stop ( void ) {
  331.     if( !effect ) {
  332.         return;
  333.     }
  334.  
  335.     Stop( false );
  336. }
  337.  
  338. /*
  339. =================
  340. rvEffect::Event_Activate
  341. =================
  342. */
  343. void rvEffect::Event_Activate( idEntity *activator ) {
  344.     // Stop the effect if its already playing
  345.     if( !clientEntities.IsListEmpty ( ) ) {
  346.         Event_Stop ( );
  347.     } else {
  348.         Event_Start ( );
  349.     }
  350.  
  351.     ActivateTargets( activator );
  352. }
  353.  
  354. /*
  355. ================
  356. rvEffect::Event_LookAtTarget
  357.  
  358. Reorients the effect entity towards its target and sets the end origin as well
  359. ================
  360. */
  361. void rvEffect::Event_LookAtTarget ( void ) {
  362.     const idKeyValue    *kv;
  363.     idVec3                dir;        
  364.  
  365.     if ( !effect || !clientEffect ) {
  366.         return;
  367.     }
  368.  
  369.     kv = spawnArgs.MatchPrefix( "target", NULL );
  370.     while( kv ) {
  371.         idEntity *ent = gameLocal.FindEntity( kv->GetValue() );
  372.         if( ent ) {
  373.             if( !idStr::Icmp( ent->GetEntityDefName(), "target_null" ) ) {
  374.                 dir = ent->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin();
  375.                 dir.Normalize();
  376.                 
  377.                 clientEffect->SetEndOrigin ( ent->GetPhysics()->GetOrigin() );
  378.                 clientEffect->SetAxis ( dir.ToMat3( ) );
  379.                 return;                        
  380.             }
  381.         }
  382.         kv = spawnArgs.MatchPrefix( "target", kv );
  383.     }
  384. }
  385.  
  386. /*
  387. ================
  388. rvEffect::Event_EarthQuake
  389. ================
  390. */
  391. void rvEffect::Event_EarthQuake ( float requiresLOS ) {
  392.     float quakeChance;
  393.  
  394.     if ( !spawnArgs.GetFloat("quakeChance", "0", quakeChance) ) {
  395.         return;
  396.     }
  397.     
  398.     if ( rvRandom::flrand(0, 1.0f) > quakeChance ) {
  399.         // failed its activation roll
  400.         return;
  401.     }
  402.     
  403.     if ( requiresLOS ) {
  404.         // if the player doesn't have line of sight to this fx, don't do anything
  405.         trace_t        trace;
  406.         idPlayer    *player = gameLocal.GetLocalPlayer();
  407.         idVec3        viewOrigin;
  408.         idMat3        viewAxis;
  409.  
  410.         player->GetViewPos(viewOrigin, viewAxis);
  411. // RAVEN BEGIN
  412. // ddynerman: multiple collision worlds
  413.         gameLocal.TracePoint( this, trace, viewOrigin, GetPhysics()->GetOrigin(), MASK_OPAQUE, player );
  414. // RAVEN END
  415.         if (trace.fraction < 1.0f)
  416.         {
  417.             // something blocked LOS
  418.             return;
  419.         }
  420.     }
  421.     
  422.     // activate this effect now
  423.     ProcessEvent ( &EV_Activate, gameLocal.entities[ENTITYNUM_WORLD] );
  424. }
  425.  
  426. /*
  427. ================
  428. rvEffect::Event_Attenuate
  429. ================
  430. */
  431. void rvEffect::Event_Attenuate( float attenuation ) {
  432.     Attenuate( attenuation );
  433. }
  434.  
  435. /*
  436. ================
  437. rvEffect::Event_Attenuate
  438. ================
  439. */
  440. void rvEffect::Event_IsActive( void ) {
  441.     idThread::ReturnFloat( ( !effect || !clientEntities.IsListEmpty() ) ? 0.0f : 1.0f );
  442. }
  443.  
  444. /*
  445. ================
  446. rvEffect::InstanceLeave
  447. ================
  448. */
  449. void rvEffect::InstanceLeave( void ) {
  450.     idEntity::InstanceLeave();
  451.     Stop( true );    
  452. }
  453.  
  454. /*
  455. ================
  456. rvEffect::InstanceJoin
  457. ================
  458. */
  459. void rvEffect::InstanceJoin( void ) {
  460.     idEntity::InstanceJoin();
  461.  
  462.     Restart();
  463. }