246 lines
7 KiB
C++
246 lines
7 KiB
C++
// Copyright (C) 2007 Id Software, Inc.
|
|
//
|
|
|
|
//----------------------------------------------------------------
|
|
// ClientMoveable.cpp
|
|
//----------------------------------------------------------------
|
|
|
|
#include "../precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#if defined( _DEBUG ) && !defined( ID_REDIRECT_NEWDELETE )
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
#include "ClientMoveable.h"
|
|
#include "../ContentMask.h"
|
|
#include "../demos/DemoManager.h"
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
rvClientMoveable
|
|
|
|
===============================================================================
|
|
*/
|
|
const idEventDefInternal CL_FadeOut( "internal_fadeOut", "d" );
|
|
|
|
static const float BOUNCE_SOUND_MIN_VELOCITY = 100.0f;
|
|
static const float BOUNCE_SOUND_MAX_VELOCITY = 200.0f;
|
|
static const int BOUNCE_SOUND_DELAY = 200;
|
|
|
|
CLASS_DECLARATION( rvClientEntity, rvClientMoveable )
|
|
EVENT( CL_FadeOut, rvClientMoveable::Event_FadeOut )
|
|
END_CLASS
|
|
|
|
|
|
/*
|
|
================
|
|
rvClientMoveable::rvClientMoveable
|
|
================
|
|
*/
|
|
rvClientMoveable::rvClientMoveable ( void ) {
|
|
memset ( &renderEntity, 0, sizeof(renderEntity) );
|
|
entityDefHandle = -1;
|
|
aorLayout = NULL;
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvClientMoveable::~rvClientMoveable
|
|
================
|
|
*/
|
|
rvClientMoveable::~rvClientMoveable ( void ) {
|
|
FreeEntityDef ( );
|
|
gameEdit->DestroyRenderEntity( renderEntity );
|
|
|
|
// Remove any trail effect if there is one
|
|
if ( trailEffect ) {
|
|
trailEffect->Stop ( );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvClientMoveable::FreeEntityDef
|
|
================
|
|
*/
|
|
void rvClientMoveable::FreeEntityDef ( void ) {
|
|
if ( entityDefHandle >= 0 ) {
|
|
gameRenderWorld->FreeEntityDef ( entityDefHandle );
|
|
entityDefHandle = -1;
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvClientMoveable::Spawn
|
|
================
|
|
*/
|
|
void rvClientMoveable::Spawn( const idDict* args, int _effectSet ) {
|
|
float bouncyness = 0.5f;
|
|
float density = 0.5f;
|
|
|
|
spawnArgs = args;
|
|
assert( spawnArgs );
|
|
|
|
effectSet = _effectSet;
|
|
|
|
// parse static models the same way the editor display does
|
|
gameEdit->ParseSpawnArgsToRenderEntity( *spawnArgs, renderEntity );
|
|
|
|
idTraceModel trm;
|
|
int clipShrink;
|
|
|
|
|
|
const char* clipModelName = spawnArgs->GetString( "cm_model" );
|
|
if ( !gameLocal.clip.LoadTraceModel( clipModelName, trm ) ) {
|
|
gameLocal.Error( "rvClientMoveable '%d': cannot load collision model %s", entityNumber, clipModelName );
|
|
return;
|
|
}
|
|
|
|
// if the model should be shrunk
|
|
clipShrink = spawnArgs->GetInt( "clipshrink" );
|
|
if ( clipShrink != 0 ) {
|
|
trm.Shrink( clipShrink * CM_CLIP_EPSILON );
|
|
}
|
|
|
|
physicsObj.SetSelf( gameLocal.entities[ENTITYNUM_CLIENT] );
|
|
physicsObj.SetClipModel( new idClipModel( trm, false ), spawnArgs->GetFloat ( "density", "0.5" ), 0 );
|
|
physicsObj.SetOrigin( worldOrigin );
|
|
physicsObj.SetAxis( worldAxis );
|
|
physicsObj.SetBouncyness( spawnArgs->GetFloat( "bouncyness", "0.6" ) );
|
|
physicsObj.SetBuoyancy( spawnArgs->GetFloat( "buoyancy", "0.3" ) );
|
|
|
|
aorLayout = gameLocal.declAORType[ spawnArgs->GetString( "aor_layout", "missile" ) ];
|
|
|
|
float friction = spawnArgs->GetFloat( "friction", "0.05" );
|
|
|
|
physicsObj.SetFriction( 0.6f, 0.6f, friction );
|
|
float gravity;
|
|
if ( spawnArgs->GetFloat( "gravity", "0", gravity ) ) {
|
|
physicsObj.SetGravity( idVec3( 0.0f, 0.0f, -gravity ) );
|
|
} else {
|
|
physicsObj.SetGravity( gameLocal.GetGravity() );
|
|
}
|
|
|
|
physicsObj.SetContents( 0, 0 );
|
|
// TODO: These contents flags can surely be done using masks....
|
|
physicsObj.SetClipMask( MASK_SOLID | CONTENTS_BODY | CONTENTS_SLIDEMOVER | CONTENTS_CORPSE | CONTENTS_MOVEABLECLIP | CONTENTS_WATER | CONTENTS_FORCEFIELD, 0 );
|
|
physicsObj.Activate();
|
|
|
|
idVec3 center = physicsObj.GetBounds().GetCenter() * worldAxis + worldOrigin;
|
|
const char* trailEffectName = "fx_trail";
|
|
if ( effectSet != 0 ) {
|
|
trailEffectName = va( "fx_trail_%i", effectSet );
|
|
}
|
|
trailEffect = gameLocal.PlayEffect( *spawnArgs, colorWhite.ToVec3(), trailEffectName, NULL, center, worldAxis, true );
|
|
trailAttenuateSpeed = spawnArgs->GetFloat ( "trailAttenuateSpeed", "200" );
|
|
|
|
bounceSoundShader = gameLocal.declSoundShaderType[ spawnArgs->GetString( "snd_bounce" ) ];
|
|
bounceSoundTime = 0;
|
|
|
|
firstBounce = true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvClientMoveable::Think
|
|
================
|
|
*/
|
|
void rvClientMoveable::Think ( void ) {
|
|
bool runPhysics = true;
|
|
if ( gameLocal.SetupClientAoR() ) {
|
|
int aorFlags = gameLocal.aorManager.GetFlagsForPoint( aorLayout, worldOrigin );
|
|
if ( ( aorFlags & AOR_INHIBIT_PHYSICS ) != 0 ) {
|
|
runPhysics = false;
|
|
}
|
|
}
|
|
|
|
if ( runPhysics ) {
|
|
RunPhysics();
|
|
}
|
|
|
|
// Special case the sound update to use the center mass since the origin may be in an odd place
|
|
if ( refSound.referenceSound ) {
|
|
refSound.origin = worldOrigin;
|
|
refSound.referenceSound->UpdateEmitter( refSound.origin, refSound.listenerId, &refSound.parms );
|
|
}
|
|
|
|
renderEntity.origin = worldOrigin;
|
|
renderEntity.axis = worldAxis;
|
|
|
|
// Keep the trail effect following
|
|
if ( trailEffect ) {
|
|
float speed;
|
|
speed = idMath::ClampFloat ( 0, trailAttenuateSpeed, physicsObj.GetLinearVelocity ( ).LengthFast ( ) );
|
|
if ( physicsObj.IsAtRest ( ) ) {
|
|
trailEffect->Stop ( );
|
|
trailEffect = NULL;
|
|
} else {
|
|
idVec3 center = physicsObj.GetBounds().GetCenter() * worldAxis + worldOrigin;
|
|
trailEffect->SetOrigin ( center );
|
|
trailEffect->SetAxis ( worldAxis );
|
|
trailEffect->Attenuate ( speed / trailAttenuateSpeed );
|
|
}
|
|
}
|
|
|
|
// add to refresh list
|
|
if ( entityDefHandle == -1 ) {
|
|
entityDefHandle = gameRenderWorld->AddEntityDef( &renderEntity );
|
|
} else {
|
|
gameRenderWorld->UpdateEntityDef( entityDefHandle, &renderEntity );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvClientMoveable::GetPhysics
|
|
================
|
|
*/
|
|
idPhysics* rvClientMoveable::GetPhysics ( void ) const {
|
|
return (idPhysics*)&physicsObj;
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvClientMoveable::Collide
|
|
================
|
|
*/
|
|
bool rvClientMoveable::Collide ( const trace_t &collision, const idVec3 &velocity ) {
|
|
if ( firstBounce ) {
|
|
// first bounce, play effect
|
|
const char* bounceEffectName = "fx_firstbounce";
|
|
if ( effectSet != 0 ) {
|
|
bounceEffectName = va( "fx_firstbounce_%i", effectSet );
|
|
}
|
|
const idVec3& origin = physicsObj.GetOrigin();
|
|
idMat3 axis = ( idVec3( 0.0f, 0.0f, 1.0f ) ).ToMat3();
|
|
gameLocal.PlayEffect( *spawnArgs, colorWhite.ToVec3(), bounceEffectName, NULL, origin, axis );
|
|
firstBounce = false;
|
|
}
|
|
|
|
if ( bounceSoundShader && gameLocal.time > bounceSoundTime ) {
|
|
float speed;
|
|
speed = velocity.LengthFast ( );
|
|
if ( speed > BOUNCE_SOUND_MIN_VELOCITY ) {
|
|
StartSoundShader ( bounceSoundShader, SND_ANY, 0 );
|
|
bounceSoundTime = BOUNCE_SOUND_DELAY;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvClientMoveable::Event_FadeOut
|
|
================
|
|
*/
|
|
void rvClientMoveable::Event_FadeOut ( int duration ) {
|
|
renderEntity.flags.noShadow = true;
|
|
renderEntity.shaderParms[ SHADERPARM_TIME_OF_DEATH ] = gameLocal.time * 0.001f;
|
|
PostEventMS ( &EV_Remove, duration );
|
|
}
|