mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-21 05:02:28 +02:00
Quake 4 integrated with DoomRTX
This commit is contained in:
@@ -0,0 +1,696 @@
|
||||
//----------------------------------------------------------------
|
||||
// ClientAFEntity.cpp
|
||||
//
|
||||
// Copyright 2002-2006 Raven Software
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
rvClientAFEntity
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
CLASS_DECLARATION( rvAnimatedClientEntity, rvClientAFEntity )
|
||||
END_CLASS
|
||||
|
||||
static const float BOUNCE_SOUND_MIN_VELOCITY = 80.0f;
|
||||
static const float BOUNCE_SOUND_MAX_VELOCITY = 200.0f;
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFEntity::rvClientAFEntity
|
||||
================
|
||||
*/
|
||||
rvClientAFEntity::rvClientAFEntity( void ) {
|
||||
combatModel = NULL;
|
||||
combatModelContents = 0;
|
||||
nextSoundTime = 0;
|
||||
spawnOrigin.Zero();
|
||||
spawnAxis.Identity();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
idAFEntity_Base::~idAFEntity_Base
|
||||
================
|
||||
*/
|
||||
rvClientAFEntity::~rvClientAFEntity( void ) {
|
||||
delete combatModel;
|
||||
combatModel = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFEntity::Spawn
|
||||
================
|
||||
*/
|
||||
void rvClientAFEntity::Spawn( void ) {
|
||||
spawnOrigin = worldOrigin;
|
||||
spawnAxis = worldAxis;
|
||||
nextSoundTime = 0;
|
||||
|
||||
//if ( !LoadAF() ) {
|
||||
// gameLocal.Error( "Couldn't load af file on entity %d", entityNumber );
|
||||
//}
|
||||
|
||||
SetCombatModel();
|
||||
|
||||
//af.GetPhysics()->PutToRest();
|
||||
//if ( !spawnArgs.GetBool( "nodrop", "0" ) ) {
|
||||
// af.GetPhysics()->Activate();
|
||||
//}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFEntity::LoadAF
|
||||
================
|
||||
*/
|
||||
bool rvClientAFEntity::LoadAF( const char* keyname ) {
|
||||
idStr fileName;
|
||||
|
||||
if ( !keyname || !*keyname ) {
|
||||
keyname = "articulatedFigure";
|
||||
}
|
||||
|
||||
if ( !spawnArgs.GetString( keyname, "*unknown*", fileName ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
af.SetAnimator( GetAnimator() );
|
||||
|
||||
idDict args = gameLocal.entities[ ENTITYNUM_CLIENT ]->spawnArgs;
|
||||
gameLocal.entities[ ENTITYNUM_CLIENT ]->spawnArgs = spawnArgs;
|
||||
|
||||
if ( !af.Load( gameLocal.entities[ ENTITYNUM_CLIENT ], fileName ) ) {
|
||||
gameLocal.Error( "rvClientAFEntity::LoadAF: Couldn't load af file '%s' on client entity %d", fileName.c_str(), entityNumber );
|
||||
}
|
||||
gameLocal.entities[ ENTITYNUM_CLIENT ]->spawnArgs = args;
|
||||
|
||||
af.Start();
|
||||
|
||||
af.GetPhysics()->Rotate( spawnAxis.ToRotation() );
|
||||
af.GetPhysics()->Translate( spawnOrigin );
|
||||
|
||||
LoadState( spawnArgs );
|
||||
|
||||
af.UpdateAnimation();
|
||||
animator.CreateFrame( gameLocal.time, true );
|
||||
UpdateVisuals();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFEntity::Think
|
||||
================
|
||||
*/
|
||||
void rvClientAFEntity::Think( void ) {
|
||||
RunPhysics();
|
||||
UpdateAnimation();
|
||||
|
||||
Present();
|
||||
LinkCombat();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFEntity::BodyForClipModelId
|
||||
================
|
||||
*/
|
||||
int rvClientAFEntity::BodyForClipModelId( int id ) const {
|
||||
return af.BodyForClipModelId( id );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFEntity::SaveState
|
||||
================
|
||||
*/
|
||||
void rvClientAFEntity::SaveState( idDict &args ) const {
|
||||
const idKeyValue *kv;
|
||||
|
||||
// save the ragdoll pose
|
||||
af.SaveState( args );
|
||||
|
||||
// save all the bind constraints
|
||||
kv = spawnArgs.MatchPrefix( "bindConstraint ", NULL );
|
||||
while ( kv ) {
|
||||
args.Set( kv->GetKey(), kv->GetValue() );
|
||||
kv = spawnArgs.MatchPrefix( "bindConstraint ", kv );
|
||||
}
|
||||
|
||||
// save the bind if it exists
|
||||
kv = spawnArgs.FindKey( "bind" );
|
||||
if ( kv ) {
|
||||
args.Set( kv->GetKey(), kv->GetValue() );
|
||||
}
|
||||
kv = spawnArgs.FindKey( "bindToJoint" );
|
||||
if ( kv ) {
|
||||
args.Set( kv->GetKey(), kv->GetValue() );
|
||||
}
|
||||
kv = spawnArgs.FindKey( "bindToBody" );
|
||||
if ( kv ) {
|
||||
args.Set( kv->GetKey(), kv->GetValue() );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFEntity::LoadState
|
||||
================
|
||||
*/
|
||||
void rvClientAFEntity::LoadState( const idDict &args ) {
|
||||
af.LoadState( args );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFEntity::AddBindConstraints
|
||||
================
|
||||
*/
|
||||
void rvClientAFEntity::AddBindConstraints( void ) {
|
||||
af.AddBindConstraints();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFEntity::RemoveBindConstraints
|
||||
================
|
||||
*/
|
||||
void rvClientAFEntity::RemoveBindConstraints( void ) {
|
||||
af.RemoveBindConstraints();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFEntity::GetImpactInfo
|
||||
================
|
||||
*/
|
||||
void rvClientAFEntity::GetImpactInfo( idEntity *ent, int id, const idVec3 &point, impactInfo_t *info ) {
|
||||
if ( af.IsActive() ) {
|
||||
af.GetImpactInfo( ent, id, point, info );
|
||||
} else {
|
||||
rvClientEntity::GetImpactInfo( ent, id, point, info );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFEntity::ApplyImpulse
|
||||
================
|
||||
*/
|
||||
void rvClientAFEntity::ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse, bool splash ) {
|
||||
if ( af.IsLoaded() ) {
|
||||
af.ApplyImpulse( ent, id, point, impulse );
|
||||
}
|
||||
if ( !af.IsActive() ) {
|
||||
rvClientEntity::ApplyImpulse( ent, id, point, impulse, splash );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFEntity::AddForce
|
||||
================
|
||||
*/
|
||||
void rvClientAFEntity::AddForce( idEntity *ent, int id, const idVec3 &point, const idVec3 &force ) {
|
||||
if ( af.IsLoaded() ) {
|
||||
af.AddForce( ent, id, point, force );
|
||||
}
|
||||
if ( !af.IsActive() ) {
|
||||
rvClientEntity::AddForce( ent, id, point, force );
|
||||
}
|
||||
}
|
||||
|
||||
bool rvClientAFEntity::CanPlayImpactEffect ( idEntity* attacker, idEntity* target ) {
|
||||
// stubbed out
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFEntity::Collide
|
||||
================
|
||||
*/
|
||||
bool rvClientAFEntity::Collide( const trace_t &collision, const idVec3 &velocity ) {
|
||||
float v, f;
|
||||
|
||||
if ( af.IsActive() ) {
|
||||
v = -( velocity * collision.c.normal );
|
||||
if ( v > BOUNCE_SOUND_MIN_VELOCITY && gameLocal.time > nextSoundTime ) {
|
||||
// RAVEN BEGIN
|
||||
// jscott: fixed negative sqrt call
|
||||
if( v > BOUNCE_SOUND_MAX_VELOCITY ) {
|
||||
f = 1.0f;
|
||||
} else if( v <= BOUNCE_SOUND_MIN_VELOCITY ) {
|
||||
f = 0.0f;
|
||||
} else {
|
||||
f = ( v - BOUNCE_SOUND_MIN_VELOCITY ) * ( 1.0f / ( BOUNCE_SOUND_MAX_VELOCITY - BOUNCE_SOUND_MIN_VELOCITY ) );
|
||||
}
|
||||
// RAVEN END
|
||||
if ( StartSound( "snd_bounce", SND_CHANNEL_ANY, 0, false, NULL ) ) {
|
||||
// don't set the volume unless there is a bounce sound as it overrides the entire channel
|
||||
// which causes footsteps on ai's to not honor their shader parms
|
||||
SetSoundVolume( f );
|
||||
}
|
||||
nextSoundTime = gameLocal.time + 500;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFEntity::GetPhysicsToVisualTransform
|
||||
================
|
||||
*/
|
||||
bool rvClientAFEntity::GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ) {
|
||||
if ( af.IsActive() ) {
|
||||
af.GetPhysicsToVisualTransform( origin, axis );
|
||||
return true;
|
||||
}
|
||||
return rvClientModel::GetPhysicsToVisualTransform( origin, axis );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFEntity::UpdateAnimationControllers
|
||||
================
|
||||
*/
|
||||
bool rvClientAFEntity::UpdateAnimationControllers( void ) {
|
||||
if ( af.IsActive() ) {
|
||||
if ( af.UpdateAnimation() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFEntity::SetCombatModel
|
||||
================
|
||||
*/
|
||||
void rvClientAFEntity::SetCombatModel( void ) {
|
||||
if ( combatModel ) {
|
||||
combatModel->Unlink();
|
||||
combatModel->LoadModel( entityDefHandle );
|
||||
} else {
|
||||
RV_PUSH_HEAP_MEM(this);
|
||||
combatModel = new idClipModel( entityDefHandle );
|
||||
RV_POP_HEAP();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFEntity::GetCombatModel
|
||||
================
|
||||
*/
|
||||
idClipModel *rvClientAFEntity::GetCombatModel( void ) const {
|
||||
return combatModel;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFEntity::SetCombatContents
|
||||
================
|
||||
*/
|
||||
void rvClientAFEntity::SetCombatContents( bool enable ) {
|
||||
assert( combatModel );
|
||||
if ( enable && combatModelContents ) {
|
||||
assert( !combatModel->GetContents() );
|
||||
combatModel->SetContents( combatModelContents );
|
||||
combatModelContents = 0;
|
||||
} else if ( !enable && combatModel->GetContents() ) {
|
||||
assert( !combatModelContents );
|
||||
combatModelContents = combatModel->GetContents();
|
||||
combatModel->SetContents( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFEntity::LinkCombat
|
||||
================
|
||||
*/
|
||||
void rvClientAFEntity::LinkCombat( void ) {
|
||||
if ( combatModel ) {
|
||||
combatModel->Link( gameLocal.entities[ ENTITYNUM_CLIENT ], 0, renderEntity.origin, renderEntity.axis, entityDefHandle );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFEntity::UnlinkCombat
|
||||
================
|
||||
*/
|
||||
void rvClientAFEntity::UnlinkCombat( void ) {
|
||||
if ( combatModel ) {
|
||||
combatModel->Unlink();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFEntity::FreeEntityDef
|
||||
================
|
||||
*/
|
||||
void rvClientAFEntity::FreeEntityDef( void ) {
|
||||
UnlinkCombat();
|
||||
rvClientEntity::FreeEntityDef();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFEntity::GetNoPlayerImpactFX
|
||||
================
|
||||
*/
|
||||
bool rvClientAFEntity::GetNoPlayerImpactFX( void ) {
|
||||
// stubbed out
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
idAFAttachment
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
CLASS_DECLARATION( rvClientAFEntity, rvClientAFAttachment )
|
||||
END_CLASS
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvClientAFAttachment::rvClientAFAttachment
|
||||
=====================
|
||||
*/
|
||||
rvClientAFAttachment::rvClientAFAttachment( void ) {
|
||||
body = NULL;
|
||||
combatModel = NULL;
|
||||
idleAnim = 0;
|
||||
damageJoint = INVALID_JOINT;
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvClientAFAttachment::~rvClientAFAttachment
|
||||
=====================
|
||||
*/
|
||||
rvClientAFAttachment::~rvClientAFAttachment( void ) {
|
||||
delete combatModel;
|
||||
combatModel = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvClientAFAttachment::Spawn
|
||||
=====================
|
||||
*/
|
||||
void rvClientAFAttachment::Spawn( void ) {
|
||||
idleAnim = animator.GetAnim( "idle" );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvClientAFAttachment::InitCopyJoints
|
||||
=====================
|
||||
*/
|
||||
void rvClientAFAttachment::InitCopyJoints ( void ) {
|
||||
copyJoints_t copyJoint;
|
||||
const idKeyValue* kv;
|
||||
const char* jointName;
|
||||
idAnimator* bodyAnimator;
|
||||
|
||||
if ( !body ) {
|
||||
return;
|
||||
}
|
||||
|
||||
bodyAnimator = body->GetAnimator ( );
|
||||
|
||||
// set up the list of joints to copy to the head
|
||||
for( kv = spawnArgs.MatchPrefix( "copy_joint", NULL ); kv != NULL; kv = spawnArgs.MatchPrefix( "copy_joint", kv ) ) {
|
||||
if ( kv->GetValue() == "" ) {
|
||||
// probably clearing out inherited key, so skip it
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !body->spawnArgs.GetString ( va("copy_joint_world %s", kv->GetValue().c_str() ), kv->GetValue().c_str(), &jointName ) ) {
|
||||
copyJoint.mod = JOINTMOD_LOCAL_OVERRIDE;
|
||||
body->spawnArgs.GetString ( va("copy_joint %s", kv->GetValue().c_str() ), kv->GetValue().c_str(), &jointName );
|
||||
} else {
|
||||
copyJoint.mod = JOINTMOD_WORLD_OVERRIDE;
|
||||
}
|
||||
|
||||
copyJoint.from = bodyAnimator->GetJointHandle ( jointName );
|
||||
if ( copyJoint.from == INVALID_JOINT ) {
|
||||
gameLocal.Warning( "Unknown copy_joint '%s' on client entity %d", jointName, entityNumber );
|
||||
continue;
|
||||
}
|
||||
|
||||
copyJoint.to = animator.GetJointHandle( kv->GetValue() );
|
||||
if ( copyJoint.to == INVALID_JOINT ) {
|
||||
gameLocal.Warning( "Unknown copy_joint '%s' on head of entity %d", kv->GetValue().c_str(), entityNumber );
|
||||
continue;
|
||||
}
|
||||
|
||||
copyJoints.Append( copyJoint );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvClientAFAttachment::CopyJointsFromBody
|
||||
=====================
|
||||
*/
|
||||
void rvClientAFAttachment::CopyJointsFromBody ( void ) {
|
||||
MEM_SCOPED_TAG(tag,MA_ANIM);
|
||||
|
||||
idAnimator* bodyAnimator;
|
||||
int i;
|
||||
idMat3 mat;
|
||||
idMat3 axis;
|
||||
idVec3 pos;
|
||||
|
||||
if ( !body ) {
|
||||
return;
|
||||
}
|
||||
bodyAnimator = body->GetAnimator();
|
||||
|
||||
// copy the animation from the body to the head
|
||||
for( i = 0; i < copyJoints.Num(); i++ ) {
|
||||
if ( copyJoints[ i ].mod == JOINTMOD_WORLD_OVERRIDE ) {
|
||||
mat = GetPhysics()->GetAxis().Transpose();
|
||||
body->GetJointWorldTransform( copyJoints[ i ].from, gameLocal.time, pos, axis );
|
||||
pos -= GetPhysics()->GetOrigin();
|
||||
animator.SetJointPos( copyJoints[ i ].to, copyJoints[ i ].mod, pos * mat );
|
||||
animator.SetJointAxis( copyJoints[ i ].to, copyJoints[ i ].mod, axis * mat );
|
||||
} else {
|
||||
bodyAnimator->GetJointLocalTransform( copyJoints[ i ].from, gameLocal.time, pos, axis );
|
||||
animator.SetJointPos( copyJoints[ i ].to, copyJoints[ i ].mod, pos );
|
||||
animator.SetJointAxis( copyJoints[ i ].to, copyJoints[ i ].mod, axis );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvClientAFAttachment::SetBody
|
||||
=====================
|
||||
*/
|
||||
void rvClientAFAttachment::SetBody( idAnimatedEntity *bodyEnt, const char *model, jointHandle_t _damageJoint ) {
|
||||
body = bodyEnt;
|
||||
damageJoint = _damageJoint;
|
||||
SetModel( model );
|
||||
|
||||
spawnArgs.SetBool( "bleed", body->spawnArgs.GetBool( "bleed" ) );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvClientAFAttachment::ClearBody
|
||||
=====================
|
||||
*/
|
||||
void rvClientAFAttachment::ClearBody( void ) {
|
||||
body = NULL;
|
||||
damageJoint = INVALID_JOINT;
|
||||
Hide();
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvClientAFAttachment::GetBody
|
||||
=====================
|
||||
*/
|
||||
idEntity *rvClientAFAttachment::GetBody( void ) const {
|
||||
return body;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAFAttachment::Hide
|
||||
================
|
||||
*/
|
||||
void rvClientAFAttachment::Hide( void ) {
|
||||
UnlinkCombat();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAFAttachment::Show
|
||||
================
|
||||
*/
|
||||
void rvClientAFAttachment::Show( void ) {
|
||||
LinkCombat();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idAFAttachment::AddDamageEffect
|
||||
================
|
||||
*/
|
||||
void rvClientAFAttachment::AddDamageEffect( const trace_t &collision, const idVec3 &velocity, const char *damageDefName, idEntity* inflictor ) {
|
||||
if ( body ) {
|
||||
trace_t c = collision;
|
||||
c.c.id = JOINT_HANDLE_TO_CLIPMODEL_ID( damageJoint );
|
||||
body->AddDamageEffect( c, velocity, damageDefName, inflictor );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFAttachment::GetImpactInfo
|
||||
================
|
||||
*/
|
||||
void rvClientAFAttachment::GetImpactInfo( idEntity *ent, int id, const idVec3 &point, impactInfo_t *info ) {
|
||||
if ( body ) {
|
||||
body->GetImpactInfo( ent, JOINT_HANDLE_TO_CLIPMODEL_ID( damageJoint ), point, info );
|
||||
} else {
|
||||
rvClientAFAttachment::GetImpactInfo( ent, id, point, info );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFAttachment::CanPlayImpactEffect
|
||||
================
|
||||
*/
|
||||
bool rvClientAFAttachment::CanPlayImpactEffect ( idEntity* attacker, idEntity* target ) {
|
||||
return rvClientAFEntity::CanPlayImpactEffect( attacker, target );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFAttachment::ApplyImpulse
|
||||
================
|
||||
*/
|
||||
void rvClientAFAttachment::ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse, bool splash ) {
|
||||
if ( body ) {
|
||||
body->ApplyImpulse( ent, JOINT_HANDLE_TO_CLIPMODEL_ID( damageJoint ), point, impulse );
|
||||
} else {
|
||||
rvClientAFEntity::ApplyImpulse( ent, id, point, impulse );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFAttachment::AddForce
|
||||
================
|
||||
*/
|
||||
void rvClientAFAttachment::AddForce( idEntity *ent, int id, const idVec3 &point, const idVec3 &force ) {
|
||||
if ( body ) {
|
||||
body->AddForce( ent, JOINT_HANDLE_TO_CLIPMODEL_ID( damageJoint ), point, force );
|
||||
} else {
|
||||
rvClientAFEntity::AddForce( ent, id, point, force );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFAttachment::PlayIdleAnim
|
||||
================
|
||||
*/
|
||||
void rvClientAFAttachment::PlayIdleAnim( int channel, int blendTime ) {
|
||||
if ( idleAnim && ( idleAnim != animator.CurrentAnim( channel )->AnimNum() ) ) {
|
||||
animator.CycleAnim( channel, idleAnim, gameLocal.time, blendTime );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFAttachment::Think
|
||||
================
|
||||
*/
|
||||
void rvClientAFAttachment::Think( void ) {
|
||||
rvClientAFEntity::Think();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFAttachment::UpdateAnimationControllers
|
||||
================
|
||||
*/
|
||||
bool rvClientAFAttachment::UpdateAnimationControllers( void ) {
|
||||
CopyJointsFromBody( );
|
||||
return rvClientAFEntity::UpdateAnimationControllers( );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFAttachment::SetCombatModel
|
||||
================
|
||||
*/
|
||||
void rvClientAFAttachment::SetCombatModel( void ) {
|
||||
if ( combatModel ) {
|
||||
combatModel->Unlink();
|
||||
combatModel->LoadModel( entityDefHandle );
|
||||
} else {
|
||||
RV_PUSH_HEAP_MEM(this);
|
||||
combatModel = new idClipModel( entityDefHandle );
|
||||
RV_POP_HEAP();
|
||||
}
|
||||
combatModel->SetOwner( body );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFAttachment::GetCombatModel
|
||||
================
|
||||
*/
|
||||
idClipModel *rvClientAFAttachment::GetCombatModel( void ) const {
|
||||
return combatModel;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFAttachment::LinkCombat
|
||||
================
|
||||
*/
|
||||
void rvClientAFAttachment::LinkCombat( void ) {
|
||||
if ( combatModel ) {
|
||||
combatModel->Link( gameLocal.entities[ ENTITYNUM_CLIENT ], 0, renderEntity.origin, renderEntity.axis, entityDefHandle );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientAFAttachment::UnlinkCombat
|
||||
================
|
||||
*/
|
||||
void rvClientAFAttachment::UnlinkCombat( void ) {
|
||||
if ( combatModel ) {
|
||||
combatModel->Unlink();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
//----------------------------------------------------------------
|
||||
// ClientAFEntity.h
|
||||
//
|
||||
// Copyright 2002-2006 Raven Software
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#ifndef __GAME_CLIENT_AFENTITY_H__
|
||||
#define __GAME_CLIENT_AFENTITY_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
rvClientAFEntity - a regular idAFEntity_Base spawned client-side
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
class rvClientAFEntity : public rvAnimatedClientEntity {
|
||||
public:
|
||||
CLASS_PROTOTYPE( rvClientAFEntity );
|
||||
|
||||
rvClientAFEntity( void );
|
||||
virtual ~rvClientAFEntity( void );
|
||||
|
||||
void Spawn( void );
|
||||
|
||||
virtual void Think( void );
|
||||
virtual void GetImpactInfo( idEntity *ent, int id, const idVec3 &point, impactInfo_t *info );
|
||||
virtual void ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse, bool splash = false );
|
||||
virtual void AddForce( idEntity *ent, int id, const idVec3 &point, const idVec3 &force );
|
||||
virtual bool CanPlayImpactEffect ( idEntity* attacker, idEntity* target );
|
||||
virtual bool Collide( const trace_t &collision, const idVec3 &velocity );
|
||||
virtual bool GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis );
|
||||
virtual bool UpdateAnimationControllers( void );
|
||||
virtual void FreeEntityDef( void );
|
||||
|
||||
virtual bool LoadAF( const char* keyname = NULL );
|
||||
bool IsActiveAF( void ) const { return af.IsActive(); }
|
||||
const char * GetAFName( void ) const { return af.GetName(); }
|
||||
idPhysics_AF * GetAFPhysics( void ) { return af.GetPhysics(); }
|
||||
|
||||
void SetCombatModel( void );
|
||||
idClipModel * GetCombatModel( void ) const;
|
||||
// contents of combatModel can be set to 0 or re-enabled (mp)
|
||||
void SetCombatContents( bool enable );
|
||||
virtual void LinkCombat( void );
|
||||
virtual void UnlinkCombat( void );
|
||||
|
||||
int BodyForClipModelId( int id ) const;
|
||||
|
||||
void SaveState( idDict &args ) const;
|
||||
void LoadState( const idDict &args );
|
||||
|
||||
void AddBindConstraints( void );
|
||||
void RemoveBindConstraints( void );
|
||||
|
||||
bool GetNoPlayerImpactFX( void );
|
||||
|
||||
protected:
|
||||
idAF af; // articulated figure
|
||||
idClipModel * combatModel; // render model for hit detection
|
||||
int combatModelContents;
|
||||
idVec3 spawnOrigin; // spawn origin
|
||||
idMat3 spawnAxis; // rotation axis used when spawned
|
||||
int nextSoundTime; // next time this can make a sound
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
rvClientAFAttachment - a regular idAFAttachment spawned client-side - links to an
|
||||
idAnimatedEntity rather than rvClientAnimatedEntity
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
class rvClientAFAttachment : public rvClientAFEntity {
|
||||
public:
|
||||
CLASS_PROTOTYPE( rvClientAFAttachment );
|
||||
|
||||
rvClientAFAttachment( void );
|
||||
virtual ~rvClientAFAttachment( void );
|
||||
|
||||
void Spawn( void );
|
||||
|
||||
void SetBody ( idAnimatedEntity* body, const char *headModel, jointHandle_t damageJoint );
|
||||
void SetDamageJoint ( jointHandle_t damageJoint );
|
||||
void ClearBody ( void );
|
||||
idEntity * GetBody ( void ) const;
|
||||
|
||||
virtual void Think ( void );
|
||||
|
||||
virtual void Hide ( void );
|
||||
virtual void Show ( void );
|
||||
|
||||
virtual bool UpdateAnimationControllers ( void );
|
||||
|
||||
void PlayIdleAnim( int channel, int blendTime );
|
||||
|
||||
virtual void GetImpactInfo( idEntity *ent, int id, const idVec3 &point, impactInfo_t *info );
|
||||
virtual void ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse, bool splash = false );
|
||||
virtual void AddForce( idEntity *ent, int id, const idVec3 &point, const idVec3 &force );
|
||||
|
||||
virtual bool CanPlayImpactEffect ( idEntity* attacker, idEntity* target );
|
||||
virtual void AddDamageEffect( const trace_t &collision, const idVec3 &velocity, const char *damageDefName, idEntity* inflictor );
|
||||
|
||||
void SetCombatModel( void );
|
||||
idClipModel * GetCombatModel( void ) const;
|
||||
virtual void LinkCombat( void );
|
||||
virtual void UnlinkCombat( void );
|
||||
|
||||
// Lipsync
|
||||
void InitCopyJoints ( void );
|
||||
|
||||
void CopyJointsFromBody ( void );
|
||||
|
||||
protected:
|
||||
idEntityPtr<idAnimatedEntity> body;
|
||||
idClipModel * combatModel; // render model for hit detection of head
|
||||
int idleAnim;
|
||||
jointHandle_t damageJoint;
|
||||
|
||||
idList<copyJoints_t> copyJoints; // copied from the body animation to the head model
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,497 @@
|
||||
//----------------------------------------------------------------
|
||||
// ClientEffect.cpp
|
||||
//
|
||||
// Copyright 2002-2004 Raven Software
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "../Game_local.h"
|
||||
#include "ClientEffect.h"
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
rvClientEffect
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
CLASS_DECLARATION( rvClientEntity, rvClientEffect )
|
||||
END_CLASS
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEffect::rvClientEffect
|
||||
================
|
||||
*/
|
||||
rvClientEffect::rvClientEffect ( void ) {
|
||||
Init( NULL );
|
||||
Spawn();
|
||||
}
|
||||
|
||||
rvClientEffect::rvClientEffect ( const idDecl *effect ) {
|
||||
Init( effect );
|
||||
Spawn();
|
||||
}
|
||||
|
||||
void rvClientEffect::Init ( const idDecl *effect ) {
|
||||
memset( &renderEffect, 0, sizeof( renderEffect ) );
|
||||
|
||||
renderEffect.declEffect = effect;
|
||||
renderEffect.startTime = -1.0f;
|
||||
renderEffect.referenceSoundHandle = -1;
|
||||
effectDefHandle = -1;
|
||||
endOriginJoint = INVALID_JOINT;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEffect::~rvClientEffect
|
||||
================
|
||||
*/
|
||||
rvClientEffect::~rvClientEffect( void ) {
|
||||
FreeEffectDef( );
|
||||
// Prevent a double free of a SoundEmitter resulting in broken in-game sounds, when
|
||||
// the second free releases a emitter that was reallocated to another sound. rvBSE caches
|
||||
// this referenceSoundHandle and rvBSE::Destroy also frees the sound. rvBSE::Destroy
|
||||
// is triggered by FreeEffectDef. Disable this free and let rvBSE do the releasing
|
||||
|
||||
// Actually, the freeing should be done here and not in BSE. The client effect allocates and
|
||||
// maintains the handle. Handling this here also allows emitters to be recycled for sparse
|
||||
// looping effects.
|
||||
soundSystem->FreeSoundEmitter( SOUNDWORLD_GAME, renderEffect.referenceSoundHandle, true );
|
||||
renderEffect.referenceSoundHandle = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEffect::GetEffectIndex
|
||||
================
|
||||
*/
|
||||
int rvClientEffect::GetEffectIndex( void )
|
||||
{
|
||||
if( renderEffect.declEffect ) {
|
||||
return( renderEffect.declEffect->Index() );
|
||||
}
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEffect::GetEffectName
|
||||
================
|
||||
*/
|
||||
const char *rvClientEffect::GetEffectName( void )
|
||||
{
|
||||
if( renderEffect.declEffect ) {
|
||||
return( renderEffect.declEffect->GetName() );
|
||||
}
|
||||
return( "unknown" );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEffect::FreeEffectDef
|
||||
================
|
||||
*/
|
||||
void rvClientEffect::FreeEffectDef ( void ) {
|
||||
if ( effectDefHandle != -1 && gameRenderWorld ) {
|
||||
gameRenderWorld->FreeEffectDef( effectDefHandle );
|
||||
}
|
||||
effectDefHandle = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEffect::UpdateBind
|
||||
================
|
||||
*/
|
||||
void rvClientEffect::UpdateBind ( void ) {
|
||||
rvClientEntity::UpdateBind ( );
|
||||
|
||||
renderEffect.origin = worldOrigin;
|
||||
|
||||
if ( endOriginJoint != INVALID_JOINT && bindMaster ) {
|
||||
idMat3 axis;
|
||||
idVec3 endOrigin;
|
||||
idVec3 dir;
|
||||
|
||||
static_cast<idAnimatedEntity*>(bindMaster.GetEntity())->GetJointWorldTransform ( endOriginJoint, gameLocal.time, endOrigin, axis );
|
||||
SetEndOrigin ( endOrigin );
|
||||
|
||||
dir = (endOrigin - worldOrigin);
|
||||
dir.Normalize ();
|
||||
renderEffect.axis = dir.ToMat3 ( );
|
||||
} else {
|
||||
renderEffect.axis = worldAxis;
|
||||
}
|
||||
|
||||
if ( bindMaster ) {
|
||||
renderEffect.groupID = bindMaster->entityNumber + 1;
|
||||
} else {
|
||||
renderEffect.groupID = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEffect::Think
|
||||
================
|
||||
*/
|
||||
void rvClientEffect::Think ( void ) {
|
||||
// If we are bound to an entity that is now hidden we can just not render if looping, otherwise stop the effect
|
||||
if( bindMaster && (bindMaster->GetRenderEntity()->hModel && bindMaster->GetModelDefHandle() == -1) ) {
|
||||
if ( renderEffect.loop ) {
|
||||
return;
|
||||
}
|
||||
Stop ( );
|
||||
}
|
||||
|
||||
// RAVEN BEGIN
|
||||
// jnewquist: Tag scope and callees to track allocations using "new".
|
||||
MEM_SCOPED_TAG(tag,MA_EFFECT);
|
||||
// RAVEN END
|
||||
// If there is a valid effect handle and we havent started playing
|
||||
// and effect yet then see if its time
|
||||
if( effectDefHandle < 0 && renderEffect.declEffect ) {
|
||||
if( renderEffect.startTime >= 0.0f ) {
|
||||
// Make sure our origins are all straight before starting the effect
|
||||
UpdateBind();
|
||||
renderEffect.attenuation = 1.0f;
|
||||
|
||||
// if the rendereffect needs sound give it an emitter.
|
||||
if( renderEffect.referenceSoundHandle <= 0 ) {
|
||||
if( gameRenderWorld->EffectDefHasSound( &renderEffect) )
|
||||
{
|
||||
renderEffect.referenceSoundHandle = soundSystem->AllocSoundEmitter( SOUNDWORLD_GAME );
|
||||
} else {
|
||||
renderEffect.referenceSoundHandle = -1;
|
||||
}
|
||||
}
|
||||
// Add the render effect
|
||||
effectDefHandle = gameRenderWorld->AddEffectDef( &renderEffect, gameLocal.time );
|
||||
if ( effectDefHandle < 0 ) {
|
||||
PostEventMS( &EV_Remove, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If we lost our effect def handle then just remove ourself
|
||||
if( effectDefHandle < 0 ) {
|
||||
PostEventMS ( &EV_Remove, 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
// Dont do anything else if its not a new client frame
|
||||
if( !gameLocal.isNewFrame ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check to see if the player can possibly see the effect or not
|
||||
renderEffect.inConnectedArea = true;
|
||||
if( bindMaster ) {
|
||||
renderEffect.inConnectedArea = gameLocal.InPlayerConnectedArea( bindMaster );
|
||||
}
|
||||
|
||||
// Update the bind
|
||||
UpdateBind();
|
||||
|
||||
// Update the actual render effect now
|
||||
if( gameRenderWorld->UpdateEffectDef( effectDefHandle, &renderEffect, gameLocal.time ) ) {
|
||||
FreeEffectDef ( );
|
||||
PostEventMS( &EV_Remove, 0 );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEffect::Play
|
||||
================
|
||||
*/
|
||||
bool rvClientEffect::Play ( int _startTime, bool _loop, const idVec3& endOrigin ) {
|
||||
if ( !renderEffect.declEffect ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize the render entity
|
||||
if ( bindMaster ) {
|
||||
renderEntity_t* renderEnt = bindMaster->GetRenderEntity ( );
|
||||
assert( renderEnt );
|
||||
|
||||
// Copy suppress values from parent entity
|
||||
renderEffect.allowSurfaceInViewID = renderEnt->allowSurfaceInViewID;
|
||||
renderEffect.suppressSurfaceInViewID = renderEnt->suppressSurfaceInViewID;
|
||||
renderEffect.weaponDepthHackInViewID = renderEnt->weaponDepthHackInViewID;
|
||||
}
|
||||
|
||||
renderEffect.shaderParms[SHADERPARM_RED] = 1.0f;
|
||||
renderEffect.shaderParms[SHADERPARM_GREEN] = 1.0f;
|
||||
renderEffect.shaderParms[SHADERPARM_BLUE] = 1.0f;
|
||||
renderEffect.shaderParms[SHADERPARM_ALPHA] = 1.0f;
|
||||
renderEffect.shaderParms[SHADERPARM_BRIGHTNESS] = 1.0f;
|
||||
renderEffect.shaderParms[SHADERPARM_TIMEOFFSET] = MS2SEC( gameLocal.time );
|
||||
renderEffect.hasEndOrigin = ( endOrigin != vec3_origin );
|
||||
renderEffect.endOrigin = endOrigin;
|
||||
renderEffect.loop = _loop;
|
||||
|
||||
assert( effectDefHandle < 0 );
|
||||
|
||||
renderEffect.startTime = MS2SEC( _startTime );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEffect::Stop
|
||||
================
|
||||
*/
|
||||
void rvClientEffect::Stop ( bool destroyParticles ) {
|
||||
if( effectDefHandle < 0 ) {
|
||||
renderEffect.startTime = -1.0f;
|
||||
renderEffect.declEffect = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( destroyParticles ) {
|
||||
// Clear the effect index to make sure the effect isnt started again. This is
|
||||
// an indirect way of making the effect not think
|
||||
renderEffect.declEffect = NULL;
|
||||
|
||||
FreeEffectDef ( );
|
||||
PostEventMS( &EV_Remove, 0 );
|
||||
} else {
|
||||
gameRenderWorld->StopEffectDef( effectDefHandle );
|
||||
// this will ensure the effect doesn't re-up when loaded from a save.
|
||||
renderEffect.startTime = -1.0f;
|
||||
Unbind ( );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEffect::Restart
|
||||
================
|
||||
*/
|
||||
void rvClientEffect::Restart ( void ) {
|
||||
FreeEffectDef ( );
|
||||
|
||||
if ( renderEffect.loop ) {
|
||||
Play ( gameLocal.time, true, renderEffect.endOrigin );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEffect::Attenuate
|
||||
================
|
||||
*/
|
||||
void rvClientEffect::Attenuate ( float attenuation ) {
|
||||
renderEffect.attenuation = attenuation;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEffect::GetDuration
|
||||
================
|
||||
*/
|
||||
float rvClientEffect::GetDuration( void ) const {
|
||||
if( effectDefHandle < 0 ) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return bse->EffectDuration( gameRenderWorld->GetEffectDef( effectDefHandle ) );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEffect::DrawDebugInfo
|
||||
================
|
||||
*/
|
||||
void rvClientEffect::DrawDebugInfo ( void ) const {
|
||||
rvClientEntity::DrawDebugInfo ( );
|
||||
|
||||
if ( !gameLocal.GetLocalPlayer() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if( !renderEffect.declEffect ) {
|
||||
return;
|
||||
}
|
||||
|
||||
idMat3 axis = gameLocal.GetLocalPlayer()->viewAngles.ToMat3();
|
||||
idVec3 up = axis[ 2 ] * 5.0f;
|
||||
|
||||
gameRenderWorld->DrawText ( renderEffect.declEffect->GetName(), worldOrigin + up, 0.1f, colorWhite, axis, 1 );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEffect::Save
|
||||
================
|
||||
*/
|
||||
void rvClientEffect::Save( idSaveGame *savefile ) const {
|
||||
savefile->WriteRenderEffect( renderEffect );
|
||||
savefile->WriteJoint( endOriginJoint );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEffect::Restore
|
||||
================
|
||||
*/
|
||||
void rvClientEffect::Restore( idRestoreGame *savefile ) {
|
||||
savefile->ReadRenderEffect( renderEffect );
|
||||
effectDefHandle = -1;
|
||||
savefile->ReadJoint( endOriginJoint );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEffect::FreeEntityDef
|
||||
================
|
||||
*/
|
||||
void rvClientEffect::FreeEntityDef( void ) {
|
||||
FreeEffectDef();
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
rvClientCrawlEffect
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
CLASS_DECLARATION( rvClientEffect, rvClientCrawlEffect )
|
||||
END_CLASS
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientCrawlEffect::rvClientCrawlEffect
|
||||
================
|
||||
*/
|
||||
rvClientCrawlEffect::rvClientCrawlEffect ( void ) {
|
||||
}
|
||||
|
||||
rvClientCrawlEffect::rvClientCrawlEffect ( const idDecl *effect, idEntity* ent, int _crawlTime, idList<jointHandle_t>* joints ) : rvClientEffect ( effect ) {
|
||||
int i;
|
||||
|
||||
// Crawl effects require an animated entity
|
||||
crawlEnt = dynamic_cast<idAnimatedEntity*>(ent);
|
||||
if ( !crawlEnt) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Specific joint list provided?
|
||||
if ( joints && joints->Num () ) {
|
||||
crawlJoints.Clear ( );
|
||||
for ( i = 0; i < joints->Num(); i ++ ) {
|
||||
crawlJoints.Append ( (*joints)[i] );
|
||||
}
|
||||
} else {
|
||||
// Use only parent joints and skip joint zero which is presumed to be the origin
|
||||
for ( i = ent->GetAnimator()->NumJoints() - 1; i > 0; i -- ) {
|
||||
if ( i != ent->GetAnimator()->GetFirstChild ( (jointHandle_t)i ) ) {
|
||||
crawlJoints.Append ( (jointHandle_t)i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//no joints? abort!
|
||||
if ( !crawlJoints.Num() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
jointStart = gameLocal.random.RandomInt ( crawlJoints.Num() );
|
||||
crawlDir = gameLocal.random.RandomInt ( 2 ) > 0 ? 1 : -1;
|
||||
jointEnd = (jointStart + crawlDir + crawlJoints.Num() ) % crawlJoints.Num();
|
||||
crawlTime = _crawlTime;
|
||||
nextCrawl = gameLocal.time + crawlTime;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientCrawlEffect::Think
|
||||
================
|
||||
*/
|
||||
void rvClientCrawlEffect::Think ( void ) {
|
||||
|
||||
// If there is no crawl entity or no crawl joints then just free ourself
|
||||
if ( !crawlEnt || !crawlJoints.Num() ) {
|
||||
PostEventMS ( &EV_Remove, 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
// Move to the next joint if its time
|
||||
if ( gameLocal.time > nextCrawl ) {
|
||||
jointStart = (jointStart + crawlDir + crawlJoints.Num() ) % crawlJoints.Num();
|
||||
jointEnd = (jointStart + crawlDir + crawlJoints.Num() ) % crawlJoints.Num();
|
||||
nextCrawl = gameLocal.time + crawlTime;
|
||||
}
|
||||
|
||||
idVec3 offsetStart;
|
||||
idVec3 offsetEnd;
|
||||
idVec3 dir;
|
||||
idMat3 axis;
|
||||
|
||||
// Get the start origin
|
||||
crawlEnt->GetJointWorldTransform ( crawlJoints[jointStart], gameLocal.time, offsetStart, axis );
|
||||
SetOrigin ( offsetStart );
|
||||
|
||||
// Get the end origin
|
||||
crawlEnt->GetJointWorldTransform ( crawlJoints[jointEnd], gameLocal.time, offsetEnd, axis );
|
||||
SetEndOrigin ( offsetEnd );
|
||||
|
||||
// Update the axis to point at the bone
|
||||
dir = offsetEnd - offsetStart;
|
||||
dir.Normalize();
|
||||
SetAxis ( dir.ToMat3( ) );
|
||||
|
||||
rvClientEffect::Think ( );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientCrawlEffect::Save
|
||||
================
|
||||
*/
|
||||
void rvClientCrawlEffect::Save( idSaveGame *savefile ) const {
|
||||
savefile->WriteInt( crawlJoints.Num() );
|
||||
for( int ix = 0; ix < crawlJoints.Num(); ++ix ) {
|
||||
savefile->WriteJoint( crawlJoints[ix] );
|
||||
}
|
||||
|
||||
savefile->WriteInt( crawlTime );
|
||||
savefile->WriteInt( nextCrawl );
|
||||
savefile->WriteInt( jointStart );
|
||||
savefile->WriteInt( jointEnd );
|
||||
savefile->WriteInt( crawlDir );
|
||||
crawlEnt.Save( savefile );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientCrawlEffect::Restore
|
||||
================
|
||||
*/
|
||||
void rvClientCrawlEffect::Restore( idRestoreGame *savefile ) {
|
||||
int numJoints = 0;
|
||||
savefile->ReadInt( numJoints );
|
||||
crawlJoints.SetNum( numJoints );
|
||||
for( int ix = 0; ix < numJoints; ++ix ) {
|
||||
savefile->ReadJoint( crawlJoints[ix] );
|
||||
}
|
||||
|
||||
savefile->ReadInt( crawlTime );
|
||||
savefile->ReadInt( nextCrawl );
|
||||
savefile->ReadInt( jointStart );
|
||||
savefile->ReadInt( jointEnd );
|
||||
savefile->ReadInt( crawlDir );
|
||||
crawlEnt.Restore( savefile );
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
//----------------------------------------------------------------
|
||||
// ClientEffect.h
|
||||
//
|
||||
// Copyright 2002-2004 Raven Software
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#ifndef __GAME_CLIENT_EFFECT_H__
|
||||
#define __GAME_CLIENT_EFFECT_H__
|
||||
|
||||
class rvClientEffect : public rvClientEntity {
|
||||
public:
|
||||
|
||||
CLASS_PROTOTYPE( rvClientEffect );
|
||||
|
||||
rvClientEffect( void );
|
||||
rvClientEffect( const idDecl *effect );
|
||||
virtual ~rvClientEffect( void );
|
||||
|
||||
virtual void Think ( void );
|
||||
virtual void DrawDebugInfo ( void ) const;
|
||||
virtual void FreeEntityDef ( void );
|
||||
virtual void UpdateBind ( void );
|
||||
|
||||
bool Play ( int startTime, bool loop = false, const idVec3& origin = vec3_origin );
|
||||
void Stop ( bool destroyParticles = false );
|
||||
void Restart ( void );
|
||||
|
||||
int GetEffectIndex ( void );
|
||||
const char * GetEffectName ( void );
|
||||
|
||||
void Attenuate ( float attenuation );
|
||||
|
||||
float GetDuration ( void ) const;
|
||||
renderEffect_t* GetRenderEffect ( void ) { return &renderEffect; }
|
||||
|
||||
void SetEndOrigin ( const idVec3& endOrigin );
|
||||
void SetEndOrigin ( jointHandle_t joint ) { endOriginJoint = joint; }
|
||||
|
||||
void SetGravity ( const idVec3& gravity ) { renderEffect.gravity = gravity; }
|
||||
|
||||
void SetColor ( const idVec4& color );
|
||||
void SetBrightness ( float brightness ) { renderEffect.shaderParms[SHADERPARM_BRIGHTNESS] = brightness; }
|
||||
void SetAmbient ( bool in ) { renderEffect.ambient = in; }
|
||||
|
||||
void Save ( idSaveGame *savefile ) const;
|
||||
void Restore ( idRestoreGame *savefile );
|
||||
protected:
|
||||
|
||||
void Init ( const idDecl *effect );
|
||||
void FreeEffectDef ( void );
|
||||
|
||||
renderEffect_t renderEffect;
|
||||
int effectDefHandle;
|
||||
jointHandle_t endOriginJoint;
|
||||
};
|
||||
|
||||
ID_INLINE void rvClientEffect::SetEndOrigin ( const idVec3& endOrigin ) {
|
||||
renderEffect.endOrigin = endOrigin;
|
||||
renderEffect.hasEndOrigin = !(endOrigin == vec3_origin);
|
||||
}
|
||||
|
||||
ID_INLINE void rvClientEffect::SetColor ( const idVec4& color ) {
|
||||
renderEffect.shaderParms[SHADERPARM_RED] = color[0];
|
||||
renderEffect.shaderParms[SHADERPARM_GREEN] = color[1];
|
||||
renderEffect.shaderParms[SHADERPARM_BLUE] = color[2];
|
||||
renderEffect.shaderParms[SHADERPARM_ALPHA] = color[3];
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// rvClientCrawlEffect
|
||||
//----------------------------------------------------------------
|
||||
|
||||
class idAnimatedEntity;
|
||||
|
||||
class rvClientCrawlEffect : public rvClientEffect {
|
||||
public:
|
||||
|
||||
CLASS_PROTOTYPE( rvClientCrawlEffect );
|
||||
|
||||
rvClientCrawlEffect ( void );
|
||||
rvClientCrawlEffect ( const idDecl *effect, idEntity* ent, int crawlTime, idList<jointHandle_t>* joints = NULL );
|
||||
~rvClientCrawlEffect ( void ) {}
|
||||
|
||||
virtual void Think ( void );
|
||||
|
||||
void Save ( idSaveGame *savefile ) const;
|
||||
void Restore ( idRestoreGame *savefile );
|
||||
|
||||
protected:
|
||||
|
||||
idList<jointHandle_t> crawlJoints;
|
||||
int crawlTime;
|
||||
int nextCrawl;
|
||||
int jointStart;
|
||||
int jointEnd;
|
||||
int crawlDir;
|
||||
idEntityPtr<idAnimatedEntity> crawlEnt;
|
||||
};
|
||||
|
||||
typedef rvClientEntityPtr<rvClientEffect> rvClientEffectPtr;
|
||||
|
||||
#endif // __GAME_CLIENT_EFFECT_H__
|
||||
@@ -0,0 +1,651 @@
|
||||
//----------------------------------------------------------------
|
||||
// ClientEntity.cpp
|
||||
//
|
||||
// Copyright 2002-2004 Raven Software
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "../Game_local.h"
|
||||
|
||||
ABSTRACT_DECLARATION( idClass, rvClientEntity )
|
||||
END_CLASS
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::rvClientEntity
|
||||
================
|
||||
*/
|
||||
rvClientEntity::rvClientEntity( void ) {
|
||||
bindMaster = NULL;
|
||||
entityNumber = -1;
|
||||
|
||||
bindOrigin.Zero();
|
||||
bindAxis.Identity();
|
||||
bindJoint = INVALID_JOINT;
|
||||
bindOrientated = false;
|
||||
|
||||
memset( &refSound, 0, sizeof(refSound) );
|
||||
refSound.referenceSoundHandle = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::~rvClientEntity
|
||||
================
|
||||
*/
|
||||
rvClientEntity::~rvClientEntity( void ) {
|
||||
Unbind();
|
||||
gameLocal.UnregisterClientEntity( this );
|
||||
|
||||
// Free sound emitter
|
||||
soundSystem->FreeSoundEmitter( SOUNDWORLD_GAME, refSound.referenceSoundHandle, true );
|
||||
refSound.referenceSoundHandle = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::Spawn
|
||||
================
|
||||
*/
|
||||
void rvClientEntity::Spawn( void ) {
|
||||
idVec3 origin;
|
||||
idMat3 axis;
|
||||
|
||||
gameLocal.RegisterClientEntity( this );
|
||||
|
||||
spawnNode.SetOwner( this );
|
||||
bindNode.SetOwner( this );
|
||||
|
||||
origin = spawnArgs.GetVector( "origin", "0 0 0" );
|
||||
axis = spawnArgs.GetMatrix( "axis", "1 0 0 0 1 0 0 0 1" );
|
||||
|
||||
InitDefaultPhysics( origin, axis );
|
||||
|
||||
SetOrigin( origin );
|
||||
SetAxis( axis );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::Present
|
||||
================
|
||||
*/
|
||||
void rvClientEntity::Present ( void ) {
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::FreeEntityDef
|
||||
================
|
||||
*/
|
||||
void rvClientEntity::FreeEntityDef ( void ) {
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::Think
|
||||
================
|
||||
*/
|
||||
void rvClientEntity::Think ( void ) {
|
||||
UpdateBind();
|
||||
UpdateSound();
|
||||
Present();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::Bind
|
||||
================
|
||||
*/
|
||||
void rvClientEntity::Bind ( idEntity* master, jointHandle_t joint, bool isOrientated ) {
|
||||
Unbind();
|
||||
|
||||
if ( joint != INVALID_JOINT && !dynamic_cast<idAnimatedEntity*>(master) ) {
|
||||
gameLocal.Warning( "rvClientEntity::Bind: entity '%s' cannot support skeletal models.", master->GetName() );
|
||||
joint = INVALID_JOINT;
|
||||
}
|
||||
|
||||
bindMaster = master;
|
||||
bindJoint = joint;
|
||||
bindOrigin = worldOrigin;
|
||||
bindAxis = worldAxis;
|
||||
|
||||
bindNode.AddToEnd ( bindMaster->clientEntities );
|
||||
|
||||
bindOrientated = isOrientated;
|
||||
if( physics ) {
|
||||
physics->SetMaster( bindMaster, bindOrientated );
|
||||
}
|
||||
|
||||
UpdateBind();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::Bind
|
||||
================
|
||||
*/
|
||||
void rvClientEntity::Unbind ( void ) {
|
||||
if ( !bindMaster ) {
|
||||
return;
|
||||
}
|
||||
|
||||
bindMaster = NULL;
|
||||
bindNode.Remove ( );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::SetOrigin
|
||||
================
|
||||
*/
|
||||
void rvClientEntity::SetOrigin( const idVec3& origin ) {
|
||||
if ( bindMaster ) {
|
||||
bindOrigin = origin;
|
||||
} else {
|
||||
worldOrigin = origin;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::SetAxis
|
||||
================
|
||||
*/
|
||||
void rvClientEntity::SetAxis( const idMat3& axis ) {
|
||||
if ( bindMaster ) {
|
||||
bindAxis = axis * bindMaster->GetRenderEntity()->axis.Transpose();
|
||||
} else {
|
||||
worldAxis = axis;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::UpdateBind
|
||||
================
|
||||
*/
|
||||
void rvClientEntity::UpdateBind ( void ) {
|
||||
if ( !bindMaster ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( bindJoint != INVALID_JOINT ) {
|
||||
static_cast<idAnimatedEntity*>(bindMaster.GetEntity())->GetJointWorldTransform ( bindJoint, gameLocal.time, worldOrigin, worldAxis );
|
||||
} else {
|
||||
bindMaster->GetPosition( worldOrigin, worldAxis );
|
||||
//if ( !bindMaster->GetPhysicsToVisualTransform( worldOrigin, worldAxis ) ) {
|
||||
// bindMaster->GetPosition( worldOrigin, worldAxis );
|
||||
//}
|
||||
}
|
||||
|
||||
worldOrigin += (bindOrigin * worldAxis);
|
||||
worldAxis = bindAxis * worldAxis;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::IsClient
|
||||
================
|
||||
*/
|
||||
bool rvClientEntity::IsClient ( void ) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::DrawDebugInfo
|
||||
================
|
||||
*/
|
||||
void rvClientEntity::DrawDebugInfo ( void ) const {
|
||||
idBounds bounds ( idVec3(-8,-8,-8), idVec3(8,8,8) );
|
||||
|
||||
gameRenderWorld->DebugBounds ( colorGreen, bounds, worldOrigin );
|
||||
|
||||
if ( gameLocal.GetLocalPlayer() ) {
|
||||
gameRenderWorld->DrawText ( GetClassname ( ), worldOrigin, 0.1f, colorWhite, gameLocal.GetLocalPlayer()->viewAngles.ToMat3(), 1 );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::UpdateSound
|
||||
================
|
||||
*/
|
||||
void rvClientEntity::UpdateSound( void ) {
|
||||
idSoundEmitter *emitter = soundSystem->EmitterForIndex( SOUNDWORLD_GAME, refSound.referenceSoundHandle );
|
||||
if ( emitter ) {
|
||||
refSound.origin = worldOrigin;
|
||||
refSound.velocity = vec3_origin;
|
||||
emitter->UpdateEmitter( refSound.origin, refSound.velocity, refSound.listenerId, &refSound.parms );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::SetSoundVolume
|
||||
================
|
||||
*/
|
||||
void rvClientEntity::SetSoundVolume( float volume ) {
|
||||
refSound.parms.volume = volume;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::StartSound
|
||||
================
|
||||
*/
|
||||
bool rvClientEntity::StartSound( const char *soundName, const s_channelType channel, int soundShaderFlags, bool broadcast, int *length ) {
|
||||
const idSoundShader *shader;
|
||||
const char *sound;
|
||||
|
||||
if ( length ) {
|
||||
*length = 0;
|
||||
}
|
||||
|
||||
idStr soundNameStr = soundName;
|
||||
if( soundNameStr.CmpPrefix( "snd_" ) && soundNameStr.CmpPrefix( "lipsync_" ) ) {
|
||||
common->Warning( "Non precached sound \'%s\'", soundName );
|
||||
}
|
||||
|
||||
if ( !spawnArgs.GetString( soundName, "", &sound ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( *sound == '\0' ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !gameLocal.isNewFrame ) {
|
||||
// don't play the sound, but don't report an error
|
||||
return true;
|
||||
}
|
||||
|
||||
shader = declManager->FindSound( sound );
|
||||
return StartSoundShader( shader, channel, soundShaderFlags );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::StartSoundShader
|
||||
================
|
||||
*/
|
||||
int rvClientEntity::StartSoundShader ( const idSoundShader* shader, const s_channelType channel, int soundShaderFlags ) {
|
||||
if ( !shader ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
idSoundEmitter *emitter = soundSystem->EmitterForIndex( SOUNDWORLD_GAME, refSound.referenceSoundHandle );
|
||||
if ( !emitter ) {
|
||||
refSound.referenceSoundHandle = soundSystem->AllocSoundEmitter( SOUNDWORLD_GAME );
|
||||
}
|
||||
|
||||
UpdateSound();
|
||||
|
||||
emitter = soundSystem->EmitterForIndex( SOUNDWORLD_GAME, refSound.referenceSoundHandle );
|
||||
if( !emitter ) {
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
emitter->UpdateEmitter( refSound.origin, refSound.velocity, refSound.listenerId, &refSound.parms );
|
||||
return emitter->StartSound( shader, channel, gameLocal.random.RandomFloat(), soundShaderFlags );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::Size
|
||||
|
||||
Returns Returns memory size of an rvClientEntity.
|
||||
================
|
||||
*/
|
||||
|
||||
size_t rvClientEntity::Size ( void ) const {
|
||||
return sizeof( rvClientEntity );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::Save
|
||||
================
|
||||
*/
|
||||
void rvClientEntity::Save( idSaveGame *savefile ) const {
|
||||
savefile->WriteInt( entityNumber );
|
||||
|
||||
// idLinkList<rvClientEntity> spawnNode; - reconstructed in the master entity load
|
||||
// idLinkList<rvClientEntity> bindNode; - reconstructed in the master entity load
|
||||
|
||||
savefile->WriteVec3( worldOrigin );
|
||||
savefile->WriteVec3( worldVelocity );
|
||||
savefile->WriteMat3( worldAxis );
|
||||
|
||||
bindMaster.Save( savefile );
|
||||
savefile->WriteVec3( bindOrigin );
|
||||
savefile->WriteMat3( bindAxis );
|
||||
savefile->WriteJoint( bindJoint );
|
||||
|
||||
savefile->WriteRefSound( refSound );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::Restore
|
||||
================
|
||||
*/
|
||||
void rvClientEntity::Restore( idRestoreGame *savefile ) {
|
||||
savefile->ReadInt( entityNumber );
|
||||
|
||||
// idLinkList<rvClientEntity> spawnNode; - reconstructed in the master entity load
|
||||
// idLinkList<rvClientEntity> bindNode; - reconstructed in the master entity load
|
||||
|
||||
savefile->ReadVec3( worldOrigin );
|
||||
savefile->ReadVec3( worldVelocity );
|
||||
savefile->ReadMat3( worldAxis );
|
||||
|
||||
bindMaster.Restore( savefile );
|
||||
savefile->ReadVec3( bindOrigin );
|
||||
savefile->ReadMat3( bindAxis );
|
||||
savefile->ReadJoint( bindJoint );
|
||||
|
||||
savefile->ReadRefSound( refSound );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::RunPhysics
|
||||
================
|
||||
*/
|
||||
void rvClientEntity::RunPhysics ( void ) {
|
||||
idPhysics* physics = GetPhysics( );
|
||||
if( !physics ) {
|
||||
return;
|
||||
}
|
||||
|
||||
rvClientPhysics* clientPhysics = (rvClientPhysics*)gameLocal.entities[ENTITYNUM_CLIENT];
|
||||
static_cast<rvClientPhysics*>( clientPhysics )->currentEntityNumber = entityNumber;
|
||||
|
||||
// order important: 1) set client physics bind master to client ent's bind master
|
||||
// 2) set physics to client ent's physics, which sets physics
|
||||
// master to client ent's master
|
||||
// 3) set client physics origin to client ent origin, depends on
|
||||
// proper bind master from 1
|
||||
clientPhysics->PushBindInfo( bindMaster, bindJoint, bindOrientated );
|
||||
clientPhysics->SetPhysics( physics );
|
||||
clientPhysics->PushOriginInfo( bindMaster ? bindOrigin : worldOrigin, bindMaster ? bindAxis : worldAxis );
|
||||
|
||||
physics->Evaluate ( gameLocal.time - gameLocal.previousTime, gameLocal.time );
|
||||
|
||||
worldOrigin = physics->GetOrigin();
|
||||
worldVelocity = physics->GetLinearVelocity();
|
||||
worldAxis = physics->GetAxis();
|
||||
|
||||
// order important: 1) restore previous bind master
|
||||
// 2) reset physics with previous bind master
|
||||
// 3) reset origin with previous bind master
|
||||
clientPhysics->PopBindInfo();
|
||||
clientPhysics->SetPhysics( NULL );
|
||||
clientPhysics->PopOriginInfo();
|
||||
|
||||
UpdateAnimationControllers();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::GetPhysics
|
||||
================
|
||||
*/
|
||||
idPhysics* rvClientEntity::GetPhysics ( void ) const {
|
||||
return physics;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::Collide
|
||||
================
|
||||
*/
|
||||
bool rvClientEntity::Collide ( const trace_t &collision, const idVec3 &velocity ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::GetImpactInfo
|
||||
================
|
||||
*/
|
||||
void rvClientEntity::GetImpactInfo( idEntity *ent, int id, const idVec3 &point, impactInfo_t *info ) {
|
||||
GetPhysics()->GetImpactInfo( id, point, info );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::ApplyImpulse
|
||||
================
|
||||
*/
|
||||
void rvClientEntity::ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse, bool splash ) {
|
||||
GetPhysics()->ApplyImpulse( id, point, impulse );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::AddForce
|
||||
================
|
||||
*/
|
||||
void rvClientEntity::AddForce( idEntity *ent, int id, const idVec3 &point, const idVec3 &force ) {
|
||||
GetPhysics()->AddForce( id, point, force );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::UpdateAnimationControllers
|
||||
================
|
||||
*/
|
||||
bool rvClientEntity::UpdateAnimationControllers( void ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientEntity::InitDefaultPhysics
|
||||
================
|
||||
*/
|
||||
void rvClientEntity::InitDefaultPhysics( const idVec3 &origin, const idMat3 &axis ) {
|
||||
const char *temp;
|
||||
idClipModel *clipModel = NULL;
|
||||
|
||||
// check if a clipmodel key/value pair is set
|
||||
if ( spawnArgs.GetString( "clipmodel", "", &temp ) ) {
|
||||
// RAVEN BEGIN
|
||||
// mwhitlock: Dynamic memory consolidation
|
||||
RV_PUSH_HEAP_MEM(this);
|
||||
// RAVEN END
|
||||
clipModel = new idClipModel( temp );
|
||||
// RAVEN BEGIN
|
||||
// mwhitlock: Dynamic memory consolidation
|
||||
RV_POP_HEAP();
|
||||
// RAVEN END
|
||||
}
|
||||
|
||||
if ( !spawnArgs.GetBool( "noclipmodel", "0" ) ) {
|
||||
|
||||
// check if mins/maxs or size key/value pairs are set
|
||||
if ( !clipModel ) {
|
||||
idVec3 size;
|
||||
idBounds bounds;
|
||||
bool setClipModel = false;
|
||||
|
||||
if ( spawnArgs.GetVector( "mins", NULL, bounds[0] ) &&
|
||||
spawnArgs.GetVector( "maxs", NULL, bounds[1] ) ) {
|
||||
setClipModel = true;
|
||||
if ( bounds[0][0] > bounds[1][0] || bounds[0][1] > bounds[1][1] || bounds[0][2] > bounds[1][2] ) {
|
||||
gameLocal.Error( "Invalid bounds '%s'-'%s' on client entity '%d'", bounds[0].ToString(), bounds[1].ToString(), entityNumber );
|
||||
}
|
||||
} else if ( spawnArgs.GetVector( "size", NULL, size ) ) {
|
||||
if ( ( size.x < 0.0f ) || ( size.y < 0.0f ) || ( size.z < 0.0f ) ) {
|
||||
gameLocal.Error( "Invalid size '%s' on client entity '%d'", size.ToString(), entityNumber );
|
||||
}
|
||||
bounds[0].Set( size.x * -0.5f, size.y * -0.5f, 0.0f );
|
||||
bounds[1].Set( size.x * 0.5f, size.y * 0.5f, size.z );
|
||||
setClipModel = true;
|
||||
}
|
||||
|
||||
if ( setClipModel ) {
|
||||
int numSides;
|
||||
idTraceModel trm;
|
||||
|
||||
if ( spawnArgs.GetInt( "cylinder", "0", numSides ) && numSides > 0 ) {
|
||||
trm.SetupCylinder( bounds, numSides < 3 ? 3 : numSides );
|
||||
} else if ( spawnArgs.GetInt( "cone", "0", numSides ) && numSides > 0 ) {
|
||||
trm.SetupCone( bounds, numSides < 3 ? 3 : numSides );
|
||||
// RAVEN BEGIN
|
||||
// bdube: added dodecahedron
|
||||
} else if ( spawnArgs.GetInt( "dodecahedron", "0", numSides ) && numSides > 0 ) {
|
||||
trm.SetupDodecahedron ( bounds );
|
||||
// RAVEN END
|
||||
} else {
|
||||
trm.SetupBox( bounds );
|
||||
}
|
||||
// RAVEN BEGIN
|
||||
// mwhitlock: Dynamic memory consolidation
|
||||
RV_PUSH_HEAP_MEM(this);
|
||||
// RAVEN END
|
||||
clipModel = new idClipModel( trm );
|
||||
// RAVEN BEGIN
|
||||
// mwhitlock: Dynamic memory consolidation
|
||||
RV_POP_HEAP();
|
||||
// RAVEN END
|
||||
}
|
||||
}
|
||||
|
||||
// check if the visual model can be used as collision model
|
||||
if ( !clipModel ) {
|
||||
temp = spawnArgs.GetString( "model" );
|
||||
if ( ( temp != NULL ) && ( *temp != 0 ) ) {
|
||||
// RAVEN BEGIN
|
||||
// jscott:slash problems
|
||||
idStr canonical = temp;
|
||||
canonical.BackSlashesToSlashes();
|
||||
// RAVEN BEGIN
|
||||
// mwhitlock: Dynamic memory consolidation
|
||||
RV_PUSH_HEAP_MEM(this);
|
||||
// RAVEN END
|
||||
clipModel = new idClipModel();
|
||||
if ( !clipModel->LoadModel( canonical ) ) {
|
||||
delete clipModel;
|
||||
clipModel = NULL;
|
||||
}
|
||||
// RAVEN BEGIN
|
||||
// mwhitlock: Dynamic memory consolidation
|
||||
RV_POP_HEAP();
|
||||
// RAVEN END
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defaultPhysicsObj.SetSelf( gameLocal.entities[ENTITYNUM_CLIENT] );
|
||||
defaultPhysicsObj.SetClipModel( clipModel, 1.0f );
|
||||
defaultPhysicsObj.SetOrigin( origin );
|
||||
defaultPhysicsObj.SetAxis( axis );
|
||||
|
||||
physics = &defaultPhysicsObj;
|
||||
|
||||
// by default no collision
|
||||
physics->SetContents( 0 );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
rvClientPhysics
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
CLASS_DECLARATION( idEntity, rvClientPhysics )
|
||||
END_CLASS
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvClientPhysics::Spawn
|
||||
=====================
|
||||
*/
|
||||
void rvClientPhysics::Spawn( void ) {
|
||||
pushedOrientated = false;
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvClientPhysics::Collide
|
||||
=====================
|
||||
*/
|
||||
bool rvClientPhysics::Collide( const trace_t &collision, const idVec3 &velocity ) {
|
||||
assert ( currentEntityNumber >= 0 && currentEntityNumber < MAX_CENTITIES );
|
||||
|
||||
rvClientEntity* cent;
|
||||
cent = gameLocal.clientEntities [ currentEntityNumber ];
|
||||
if ( cent ) {
|
||||
return cent->Collide ( collision, velocity );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvClientPhysics::PushBindInfo
|
||||
=====================
|
||||
*/
|
||||
void rvClientPhysics::PushBindInfo( idEntity* master, jointHandle_t joint, bool orientated ) {
|
||||
pushedBindJoint = joint;
|
||||
pushedBindMaster = master;
|
||||
pushedOrientated = fl.bindOrientated;
|
||||
|
||||
bindMaster = master;
|
||||
bindJoint = joint;
|
||||
fl.bindOrientated = orientated;
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvClientPhysics::PopBindInfo
|
||||
=====================
|
||||
*/
|
||||
void rvClientPhysics::PopBindInfo( void ) {
|
||||
bindMaster = pushedBindMaster;
|
||||
bindJoint = pushedBindJoint;
|
||||
fl.bindOrientated = pushedOrientated;
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvClientPhysics::PushOriginInfo
|
||||
=====================
|
||||
*/
|
||||
void rvClientPhysics::PushOriginInfo( const idVec3& origin, const idMat3& axis ) {
|
||||
if( !GetPhysics() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
pushedOrigin = GetPhysics()->GetOrigin();
|
||||
pushedAxis = GetPhysics()->GetAxis();
|
||||
|
||||
GetPhysics()->SetOrigin( origin );
|
||||
GetPhysics()->SetAxis( axis );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvClientPhysics::PopOriginInfo
|
||||
=====================
|
||||
*/
|
||||
void rvClientPhysics::PopOriginInfo( void ) {
|
||||
if( !GetPhysics() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
GetPhysics()->SetOrigin( pushedOrigin );
|
||||
GetPhysics()->SetAxis( pushedAxis );
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
//----------------------------------------------------------------
|
||||
// ClientEntity.h
|
||||
//
|
||||
// Copyright 2002-2004 Raven Software
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#ifndef __GAME_CLIENT_ENTITY_H__
|
||||
#define __GAME_CLIENT_ENTITY_H__
|
||||
|
||||
class rvClientEntity : public idClass {
|
||||
public:
|
||||
|
||||
ABSTRACT_PROTOTYPE( rvClientEntity );
|
||||
|
||||
rvClientEntity ( void );
|
||||
|
||||
virtual ~rvClientEntity ( void );
|
||||
|
||||
void Spawn ( void );
|
||||
|
||||
virtual void Present ( void );
|
||||
virtual void Think ( void );
|
||||
virtual idPhysics* GetPhysics ( void ) const;
|
||||
virtual bool Collide ( const trace_t &collision, const idVec3 &velocity );
|
||||
|
||||
void SetOrigin ( const idVec3& origin );
|
||||
void SetAxis ( const idMat3& axis );
|
||||
const idVec3& GetOrigin ( void );
|
||||
const idMat3& GetAxis ( void );
|
||||
|
||||
void Bind ( idEntity* master, jointHandle_t joint = INVALID_JOINT, bool isOrientated = false );
|
||||
void Unbind ( void );
|
||||
|
||||
virtual bool IsClient ( void ) const;
|
||||
virtual void DrawDebugInfo ( void ) const;
|
||||
|
||||
void SetSoundVolume( float volume );
|
||||
bool StartSound( const char *soundName, const s_channelType channel, int soundShaderFlags, bool broadcast, int *length );
|
||||
int StartSoundShader ( const idSoundShader *shader, const s_channelType channel, int soundShaderFlags );
|
||||
|
||||
// I'm guessing someone may decide to derive from rvClientEntity, so this virtual.
|
||||
virtual size_t Size ( void ) const;
|
||||
|
||||
virtual void FreeEntityDef ( void );
|
||||
|
||||
const idEntityPtr<idEntity>& GetBindMaster( void ) const;
|
||||
|
||||
void Save ( idSaveGame *savefile ) const;
|
||||
void Restore ( idRestoreGame *savefile );
|
||||
|
||||
virtual void GetImpactInfo ( idEntity *ent, int id, const idVec3 &point, impactInfo_t *info );
|
||||
virtual void ApplyImpulse ( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse, bool splash );
|
||||
virtual void AddForce ( idEntity *ent, int id, const idVec3 &point, const idVec3 &force );
|
||||
|
||||
virtual bool UpdateAnimationControllers( void );
|
||||
|
||||
void InitDefaultPhysics ( const idVec3 &origin, const idMat3 &axis );
|
||||
protected:
|
||||
|
||||
void RunPhysics ( void );
|
||||
|
||||
virtual void UpdateBind ( void );
|
||||
void UpdateSound ( void );
|
||||
|
||||
public:
|
||||
|
||||
int entityNumber;
|
||||
|
||||
idLinkList<rvClientEntity> spawnNode;
|
||||
idLinkList<rvClientEntity> bindNode;
|
||||
|
||||
idDict spawnArgs;
|
||||
|
||||
protected:
|
||||
idPhysics_Static defaultPhysicsObj; // default physics object
|
||||
idPhysics* physics;
|
||||
|
||||
idVec3 worldOrigin;
|
||||
idVec3 worldVelocity;
|
||||
idMat3 worldAxis;
|
||||
|
||||
idEntityPtr<idEntity> bindMaster;
|
||||
idVec3 bindOrigin;
|
||||
idMat3 bindAxis;
|
||||
jointHandle_t bindJoint;
|
||||
bool bindOrientated;
|
||||
refSound_t refSound;
|
||||
};
|
||||
|
||||
ID_INLINE const idVec3& rvClientEntity::GetOrigin ( void ) {
|
||||
return worldOrigin;
|
||||
}
|
||||
|
||||
ID_INLINE const idMat3& rvClientEntity::GetAxis ( void ) {
|
||||
return worldAxis;
|
||||
}
|
||||
|
||||
ID_INLINE const idEntityPtr<idEntity>& rvClientEntity::GetBindMaster( void ) const {
|
||||
return bindMaster;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
template< class type >
|
||||
class rvClientEntityPtr {
|
||||
public:
|
||||
rvClientEntityPtr();
|
||||
|
||||
rvClientEntityPtr<type> & operator=( type* cent );
|
||||
|
||||
int GetSpawnId ( void ) const { return spawnId; }
|
||||
bool SetSpawnId ( int id );
|
||||
bool UpdateSpawnId ( void );
|
||||
|
||||
bool IsValid ( void ) const;
|
||||
type * GetEntity ( void ) const;
|
||||
int GetEntityNum ( void ) const;
|
||||
|
||||
type * operator-> ( void ) const { return GetEntity ( ); }
|
||||
operator type* ( void ) const { return GetEntity ( ); }
|
||||
|
||||
void Save ( idSaveGame *savefile ) const;
|
||||
void Restore ( idRestoreGame *savefile );
|
||||
|
||||
private:
|
||||
int spawnId;
|
||||
};
|
||||
|
||||
template< class type >
|
||||
ID_INLINE rvClientEntityPtr<type>::rvClientEntityPtr() {
|
||||
spawnId = 0;
|
||||
}
|
||||
|
||||
template< class type >
|
||||
ID_INLINE rvClientEntityPtr<type> &rvClientEntityPtr<type>::operator=( type *cent ) {
|
||||
if ( cent == NULL ) {
|
||||
spawnId = 0;
|
||||
} else {
|
||||
spawnId = ( gameLocal.clientSpawnIds[cent->entityNumber] << CENTITYNUM_BITS ) | cent->entityNumber;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< class type >
|
||||
ID_INLINE bool rvClientEntityPtr<type>::SetSpawnId( int id ) {
|
||||
if ( id == spawnId ) {
|
||||
return false;
|
||||
}
|
||||
if ( ( id >> CENTITYNUM_BITS ) == gameLocal.clientSpawnIds[ id & ( ( 1 << CENTITYNUM_BITS ) - 1 ) ] ) {
|
||||
spawnId = id;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template< class type >
|
||||
ID_INLINE bool rvClientEntityPtr<type>::IsValid( void ) const {
|
||||
return ( gameLocal.clientSpawnIds[ spawnId & ( ( 1 << CENTITYNUM_BITS ) - 1 ) ] == ( ( spawnId >> CENTITYNUM_BITS ) & ( 0xffffffff >> CENTITYNUM_BITS ) ) );
|
||||
}
|
||||
|
||||
template< class type >
|
||||
ID_INLINE type *rvClientEntityPtr<type>::GetEntity( void ) const {
|
||||
int entityNum = spawnId & ( ( 1 << CENTITYNUM_BITS ) - 1 );
|
||||
if ( ( gameLocal.clientSpawnIds[ entityNum ] == ( ( spawnId >> CENTITYNUM_BITS ) & ( 0xffffffff >> CENTITYNUM_BITS ) ) ) ) {
|
||||
return static_cast<type *>( gameLocal.clientEntities[ entityNum ] );
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template< class type >
|
||||
ID_INLINE int rvClientEntityPtr<type>::GetEntityNum( void ) const {
|
||||
return ( spawnId & ( ( 1 << CENTITYNUM_BITS ) - 1 ) );
|
||||
}
|
||||
|
||||
template< class type >
|
||||
ID_INLINE void rvClientEntityPtr<type>::Save( idSaveGame *savefile ) const {
|
||||
savefile->WriteInt( spawnId );
|
||||
}
|
||||
|
||||
template< class type >
|
||||
ID_INLINE void rvClientEntityPtr<type>::Restore( idRestoreGame *savefile ) {
|
||||
savefile->ReadInt( spawnId );
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
rvClientPhysics
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
class rvClientPhysics : public idEntity {
|
||||
public:
|
||||
|
||||
CLASS_PROTOTYPE( rvClientPhysics );
|
||||
|
||||
rvClientPhysics( void ) { currentEntityNumber = -1; }
|
||||
|
||||
void Spawn( void );
|
||||
|
||||
virtual bool Collide( const trace_t &collision, const idVec3 &velocity );
|
||||
virtual void PushBindInfo( idEntity* master, jointHandle_t joint, bool orientated );
|
||||
virtual void PopBindInfo( void );
|
||||
|
||||
virtual void PushOriginInfo( const idVec3& origin, const idMat3& axis );
|
||||
virtual void PopOriginInfo( void );
|
||||
|
||||
// client side entities. make sure the networking doesn't fuck around with this
|
||||
virtual bool ClientStale( void ) { assert( false ); return false; }
|
||||
virtual void ClientUnstale( void ) { assert( false ); }
|
||||
|
||||
int currentEntityNumber;
|
||||
private:
|
||||
idEntity* pushedBindMaster;
|
||||
jointHandle_t pushedBindJoint;
|
||||
idVec3 pushedOrigin;
|
||||
idMat3 pushedAxis;
|
||||
bool pushedOrientated;
|
||||
};
|
||||
|
||||
#endif // __GAME_CLIENT_ENTITY_H__
|
||||
@@ -0,0 +1,450 @@
|
||||
//----------------------------------------------------------------
|
||||
// ClientModel.cpp
|
||||
//
|
||||
// A non-interactive client-side model
|
||||
//
|
||||
// Copyright 2002-2004 Raven Software
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "../Game_local.h"
|
||||
#include "ClientModel.h"
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
rvClientModel
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
CLASS_DECLARATION( rvClientEntity, rvClientModel )
|
||||
END_CLASS
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientModel::rvClientModel
|
||||
================
|
||||
*/
|
||||
rvClientModel::rvClientModel ( void ) {
|
||||
memset ( &renderEntity, 0, sizeof(renderEntity) );
|
||||
worldAxis = mat3_identity;
|
||||
entityDefHandle = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientModel::~rvClientModel
|
||||
================
|
||||
*/
|
||||
rvClientModel::~rvClientModel ( void ) {
|
||||
FreeEntityDef ( );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientModel::FreeEntityDef
|
||||
================
|
||||
*/
|
||||
void rvClientModel::FreeEntityDef ( void ) {
|
||||
if ( entityDefHandle >= 0 ) {
|
||||
gameRenderWorld->FreeEntityDef ( entityDefHandle );
|
||||
entityDefHandle = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientModel::Spawn
|
||||
================
|
||||
*/
|
||||
void rvClientModel::Spawn ( void ) {
|
||||
const char* spawnarg;
|
||||
|
||||
spawnArgs.GetString ( "classname", "", classname );
|
||||
|
||||
// parse static models the same way the editor display does
|
||||
gameEdit->ParseSpawnArgsToRenderEntity( &spawnArgs, &renderEntity );
|
||||
|
||||
renderEntity.entityNum = entityNumber;
|
||||
|
||||
spawnarg = spawnArgs.GetString( "model" );
|
||||
if ( spawnarg && *spawnarg ) {
|
||||
SetModel( spawnarg );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientModel::Think
|
||||
================
|
||||
*/
|
||||
void rvClientModel::Think ( void ) {
|
||||
if( bindMaster && (bindMaster->GetRenderEntity()->hModel && bindMaster->GetModelDefHandle() == -1) ) {
|
||||
return;
|
||||
}
|
||||
UpdateBind();
|
||||
Present();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientModel::Present
|
||||
================
|
||||
*/
|
||||
void rvClientModel::Present(void) {
|
||||
// Hide client entities bound to a hidden entity
|
||||
if ( bindMaster && (bindMaster->IsHidden ( ) || (bindMaster->GetRenderEntity()->hModel && bindMaster->GetModelDefHandle() == -1) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
renderEntity.origin = worldOrigin;
|
||||
renderEntity.axis = worldAxis;
|
||||
|
||||
// add to refresh list
|
||||
if ( entityDefHandle == -1 ) {
|
||||
entityDefHandle = gameRenderWorld->AddEntityDef( &renderEntity );
|
||||
} else {
|
||||
gameRenderWorld->UpdateEntityDef( entityDefHandle, &renderEntity );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientModel::SetCustomShader
|
||||
================
|
||||
*/
|
||||
bool rvClientModel::SetCustomShader ( const char* shaderName ) {
|
||||
if ( shaderName == NULL ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const idMaterial* material = declManager->FindMaterial( shaderName );
|
||||
|
||||
if ( material == NULL ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
renderEntity.customShader = material;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientModel::Save
|
||||
================
|
||||
*/
|
||||
void rvClientModel::Save( idSaveGame *savefile ) const {
|
||||
savefile->WriteRenderEntity( renderEntity );
|
||||
savefile->WriteInt( entityDefHandle );
|
||||
|
||||
savefile->WriteString ( classname ); // cnicholson: Added unsaved var
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientModel::Restore
|
||||
================
|
||||
*/
|
||||
void rvClientModel::Restore( idRestoreGame *savefile ) {
|
||||
savefile->ReadRenderEntity( renderEntity, NULL );
|
||||
savefile->ReadInt( entityDefHandle );
|
||||
|
||||
savefile->ReadString ( classname ); // cnicholson: Added unrestored var
|
||||
|
||||
// restore must retrieve entityDefHandle from the renderer
|
||||
if ( entityDefHandle != -1 ) {
|
||||
entityDefHandle = gameRenderWorld->AddEntityDef( &renderEntity );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientModel::SetModel
|
||||
================
|
||||
*/
|
||||
void rvClientModel::SetModel( const char* modelname ) {
|
||||
FreeEntityDef();
|
||||
|
||||
renderEntity.hModel = renderModelManager->FindModel( modelname );
|
||||
|
||||
if ( renderEntity.hModel ) {
|
||||
renderEntity.hModel->Reset();
|
||||
}
|
||||
|
||||
renderEntity.callback = NULL;
|
||||
renderEntity.numJoints = 0;
|
||||
renderEntity.joints = NULL;
|
||||
if ( renderEntity.hModel ) {
|
||||
renderEntity.bounds = renderEntity.hModel->Bounds( &renderEntity );
|
||||
} else {
|
||||
renderEntity.bounds.Zero();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
rvClientModel::ProjectOverlay
|
||||
==============
|
||||
*/
|
||||
void rvClientModel::ProjectOverlay( const idVec3 &origin, const idVec3 &dir, float size, const char *material ) {
|
||||
float s, c;
|
||||
idMat3 axis, axistemp;
|
||||
idVec3 localOrigin, localAxis[2];
|
||||
idPlane localPlane[2];
|
||||
|
||||
// make sure the entity has a valid model handle
|
||||
if ( entityDefHandle < 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// only do this on dynamic md5 models
|
||||
if ( renderEntity.hModel->IsDynamicModel() != DM_CACHED ) {
|
||||
return;
|
||||
}
|
||||
|
||||
idMath::SinCos16( gameLocal.random.RandomFloat() * idMath::TWO_PI, s, c );
|
||||
|
||||
axis[2] = -dir;
|
||||
axis[2].NormalVectors( axistemp[0], axistemp[1] );
|
||||
axis[0] = axistemp[ 0 ] * c + axistemp[ 1 ] * -s;
|
||||
axis[1] = axistemp[ 0 ] * -s + axistemp[ 1 ] * -c;
|
||||
|
||||
renderEntity.axis.ProjectVector( origin - renderEntity.origin, localOrigin );
|
||||
renderEntity.axis.ProjectVector( axis[0], localAxis[0] );
|
||||
renderEntity.axis.ProjectVector( axis[1], localAxis[1] );
|
||||
|
||||
size = 1.0f / size;
|
||||
localAxis[0] *= size;
|
||||
localAxis[1] *= size;
|
||||
|
||||
localPlane[0] = localAxis[0];
|
||||
localPlane[0][3] = -( localOrigin * localAxis[0] ) + 0.5f;
|
||||
|
||||
localPlane[1] = localAxis[1];
|
||||
localPlane[1][3] = -( localOrigin * localAxis[1] ) + 0.5f;
|
||||
|
||||
const idMaterial *mtr = declManager->FindMaterial( material );
|
||||
|
||||
// project an overlay onto the model
|
||||
gameRenderWorld->ProjectOverlay( entityDefHandle, localPlane, mtr );
|
||||
|
||||
// make sure non-animating models update their overlay
|
||||
UpdateVisuals();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientModel::UpdateRenderEntity
|
||||
================
|
||||
*/
|
||||
bool rvClientModel::UpdateRenderEntity( renderEntity_s *renderEntity, const renderView_t *renderView ) {
|
||||
if ( gameLocal.inCinematic && gameLocal.skipCinematic ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
idAnimator *animator = GetAnimator();
|
||||
if ( animator ) {
|
||||
return animator->CreateFrame( gameLocal.time, false );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientModel::ModelCallback
|
||||
|
||||
NOTE: may not change the game state whatsoever!
|
||||
================
|
||||
*/
|
||||
bool rvClientModel::ModelCallback( renderEntity_s *renderEntity, const renderView_t *renderView ) {
|
||||
rvClientEntity *cent;
|
||||
|
||||
cent = gameLocal.clientEntities[ renderEntity->entityNum ];
|
||||
if ( !cent ) {
|
||||
gameLocal.Error( "rvClientModel::ModelCallback: callback with NULL client entity '%d'", renderEntity->entityNum );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !cent->IsType( rvClientModel::GetClassType() ) ) {
|
||||
gameLocal.Error( "rvClientModel::ModelCallback: callback with non-client model on client entity '%d'", renderEntity->entityNum );
|
||||
return false;
|
||||
}
|
||||
|
||||
return ((rvClientModel*)cent)->UpdateRenderEntity( renderEntity, renderView );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientModel::GetPhysicsToVisualTransform
|
||||
================
|
||||
*/
|
||||
bool rvClientModel::GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientModel::UpdateModelTransform
|
||||
================
|
||||
*/
|
||||
void rvClientModel::UpdateModelTransform( void ) {
|
||||
idVec3 origin;
|
||||
idMat3 axis;
|
||||
|
||||
if ( GetPhysicsToVisualTransform( origin, axis ) ) {
|
||||
renderEntity.axis = axis * worldAxis;
|
||||
renderEntity.origin = worldOrigin + origin * renderEntity.axis;
|
||||
} else {
|
||||
renderEntity.axis = worldAxis;
|
||||
renderEntity.origin = worldOrigin;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientModel::UpdateModel
|
||||
================
|
||||
*/
|
||||
void rvClientModel::UpdateModel( void ) {
|
||||
UpdateModelTransform();
|
||||
|
||||
idAnimator *animator = GetAnimator();
|
||||
if ( animator && animator->ModelHandle() ) {
|
||||
// set the callback to update the joints
|
||||
renderEntity.callback = rvClientModel::ModelCallback;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientModel::UpdateVisuals
|
||||
================
|
||||
*/
|
||||
void rvClientModel::UpdateVisuals( void ) {
|
||||
UpdateModel();
|
||||
UpdateSound();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientModel::SetSkin
|
||||
================
|
||||
*/
|
||||
void rvClientModel::SetSkin( const idDeclSkin *skin ) {
|
||||
renderEntity.customSkin = skin;
|
||||
UpdateVisuals();
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
rvAnimatedClientEntity
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
CLASS_DECLARATION( rvClientModel, rvAnimatedClientEntity )
|
||||
END_CLASS
|
||||
|
||||
/*
|
||||
================
|
||||
rvAnimatedClientEntity::rvAnimatedClientEntity
|
||||
================
|
||||
*/
|
||||
rvAnimatedClientEntity::rvAnimatedClientEntity ( void ) {
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvAnimatedClientEntity::~rvAnimatedClientEntity
|
||||
================
|
||||
*/
|
||||
rvAnimatedClientEntity::~rvAnimatedClientEntity ( void ) {
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvAnimatedClientEntity::Spawn
|
||||
================
|
||||
*/
|
||||
void rvAnimatedClientEntity::Spawn( void ) {
|
||||
SetModel( spawnArgs.GetString( "model" ) );
|
||||
}
|
||||
/*
|
||||
================
|
||||
rvAnimatedClientEntity::Think
|
||||
================
|
||||
*/
|
||||
void rvAnimatedClientEntity::Think ( void ) {
|
||||
UpdateAnimation();
|
||||
|
||||
rvClientEntity::Think();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvAnimatedClientEntity::UpdateAnimation
|
||||
================
|
||||
*/
|
||||
void rvAnimatedClientEntity::UpdateAnimation( void ) {
|
||||
// is the model an MD5?
|
||||
if ( !animator.ModelHandle() ) {
|
||||
// no, so nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
// call any frame commands that have happened in the past frame
|
||||
animator.ServiceAnims( gameLocal.previousTime, gameLocal.time );
|
||||
|
||||
// if the model is animating then we have to update it
|
||||
if ( !animator.FrameHasChanged( gameLocal.time ) ) {
|
||||
// still fine the way it was
|
||||
return;
|
||||
}
|
||||
|
||||
// get the latest frame bounds
|
||||
animator.GetBounds( gameLocal.time, renderEntity.bounds );
|
||||
if ( renderEntity.bounds.IsCleared() ) {
|
||||
gameLocal.DPrintf( "rvAnimatedClientEntity %s %d: inside out bounds - %d\n", GetClassname(), entityNumber, gameLocal.time );
|
||||
}
|
||||
|
||||
// update the renderEntity
|
||||
UpdateVisuals();
|
||||
Present();
|
||||
|
||||
// the animation is updated
|
||||
animator.ClearForceUpdate();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvAnimatedClientEntity::SetModel
|
||||
================
|
||||
*/
|
||||
void rvAnimatedClientEntity::SetModel( const char *modelname ) {
|
||||
FreeEntityDef();
|
||||
|
||||
renderEntity.hModel = animator.SetModel( modelname );
|
||||
if ( !renderEntity.hModel ) {
|
||||
rvClientModel::SetModel( modelname );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !renderEntity.customSkin ) {
|
||||
renderEntity.customSkin = animator.ModelDef()->GetDefaultSkin();
|
||||
}
|
||||
|
||||
// set the callback to update the joints
|
||||
renderEntity.callback = rvClientModel::ModelCallback;
|
||||
animator.GetJoints( &renderEntity.numJoints, &renderEntity.joints );
|
||||
animator.GetBounds( gameLocal.time, renderEntity.bounds );
|
||||
|
||||
//UpdateVisuals();
|
||||
Present();
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
//----------------------------------------------------------------
|
||||
// ClientModel.h
|
||||
//
|
||||
// A non-interactive client-side model
|
||||
//
|
||||
// Copyright 2002-2004 Raven Software
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#ifndef __GAME_CLIENT_MODEL_H__
|
||||
#define __GAME_CLIENT_MODEL_H__
|
||||
|
||||
class rvClientModel : public rvClientEntity {
|
||||
public:
|
||||
|
||||
CLASS_PROTOTYPE( rvClientModel );
|
||||
|
||||
rvClientModel ( void );
|
||||
virtual ~rvClientModel ( void );
|
||||
|
||||
void Spawn ( void );
|
||||
virtual void Think ( void );
|
||||
|
||||
virtual renderEntity_t* GetRenderEntity ( void );
|
||||
const char* GetClassname ( void ) const;
|
||||
|
||||
virtual bool SetCustomShader ( const char* shaderName );
|
||||
|
||||
void Save ( idSaveGame *savefile ) const;
|
||||
void Restore ( idRestoreGame *savefile );
|
||||
|
||||
virtual void FreeEntityDef ( void );
|
||||
|
||||
virtual void SetModel( const char *modelname );
|
||||
|
||||
virtual const idAnimator* GetAnimator( void ) const { return NULL; }
|
||||
virtual idAnimator* GetAnimator( void ) { return NULL; }
|
||||
|
||||
|
||||
bool UpdateRenderEntity( renderEntity_s *renderEntity, const renderView_t *renderView );
|
||||
static bool ModelCallback( renderEntity_s *renderEntity, const renderView_t *renderView );
|
||||
|
||||
virtual bool GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis );
|
||||
void ProjectOverlay( const idVec3 &origin, const idVec3 &dir, float size, const char *material );
|
||||
|
||||
void UpdateVisuals( void );
|
||||
void UpdateModel( void );
|
||||
void UpdateModelTransform( void );
|
||||
|
||||
void SetSkin( const idDeclSkin* skin );
|
||||
int GetModelDefHandle( void );
|
||||
protected:
|
||||
void Present( void );
|
||||
|
||||
renderEntity_t renderEntity;
|
||||
int entityDefHandle;
|
||||
|
||||
idStr classname;
|
||||
};
|
||||
|
||||
ID_INLINE renderEntity_t* rvClientModel::GetRenderEntity ( void ) {
|
||||
return &renderEntity;
|
||||
}
|
||||
|
||||
ID_INLINE const char* rvClientModel::GetClassname ( void ) const {
|
||||
return classname.c_str();
|
||||
}
|
||||
|
||||
ID_INLINE int rvClientModel::GetModelDefHandle( void ) {
|
||||
return entityDefHandle;
|
||||
}
|
||||
|
||||
class rvAnimatedClientEntity : public rvClientModel {
|
||||
public:
|
||||
CLASS_PROTOTYPE( rvAnimatedClientEntity );
|
||||
|
||||
rvAnimatedClientEntity ( void );
|
||||
virtual ~rvAnimatedClientEntity ( void );
|
||||
|
||||
void Spawn( void );
|
||||
virtual void Think( void );
|
||||
virtual void UpdateAnimation( void );
|
||||
|
||||
virtual void SetModel( const char *modelname );
|
||||
|
||||
virtual const idAnimator* GetAnimator( void ) const { return &animator; }
|
||||
virtual idAnimator* GetAnimator( void ) { return &animator; }
|
||||
|
||||
protected:
|
||||
idAnimator animator;
|
||||
};
|
||||
|
||||
#endif // __GAME_CLIENT_MODEL_H__
|
||||
@@ -0,0 +1,379 @@
|
||||
//----------------------------------------------------------------
|
||||
// ClientMoveable.cpp
|
||||
//
|
||||
// Copyright 2002-2004 Raven Software
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "../Game_local.h"
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
rvClientMoveable
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
const idEventDef CL_FadeOut( "<fadeOut>", "d" );
|
||||
const idEventDef CL_ClearDepthHack ( "<clearDepthHack>" );
|
||||
|
||||
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 )
|
||||
EVENT( CL_ClearDepthHack, rvClientMoveable::Event_ClearDepthHack )
|
||||
END_CLASS
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientMoveable::rvClientMoveable
|
||||
================
|
||||
*/
|
||||
rvClientMoveable::rvClientMoveable ( void ) {
|
||||
memset ( &renderEntity, 0, sizeof(renderEntity) );
|
||||
entityDefHandle = -1;
|
||||
scale.Init( 0, 0, 1.0f, 1.0f );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientMoveable::~rvClientMoveable
|
||||
================
|
||||
*/
|
||||
rvClientMoveable::~rvClientMoveable ( void ) {
|
||||
FreeEntityDef ( );
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
idVec3 simpleTri[3] =
|
||||
{
|
||||
idVec3( -1.0, -1.0, 0.0 ),
|
||||
idVec3( 0.0, 2.0, 0.0 ),
|
||||
idVec3( 2.0, 0.0, 0.0 )
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientMoveable::Spawn
|
||||
================
|
||||
*/
|
||||
void rvClientMoveable::Spawn ( void ) {
|
||||
// parse static models the same way the editor display does
|
||||
gameEdit->ParseSpawnArgsToRenderEntity( &spawnArgs, &renderEntity );
|
||||
|
||||
idTraceModel trm;
|
||||
int clipShrink;
|
||||
idStr clipModelName;
|
||||
|
||||
// check if a clip model is set
|
||||
spawnArgs.GetString( "clipmodel", "", clipModelName );
|
||||
if ( !clipModelName.Length () ) {
|
||||
clipModelName = spawnArgs.GetString( "model" ); // use the visual model
|
||||
}
|
||||
|
||||
if ( clipModelName == SIMPLE_TRI_NAME ) {
|
||||
trm.SetupPolygon( simpleTri, 3 );
|
||||
} else {
|
||||
clipModelName.BackSlashesToSlashes();
|
||||
|
||||
if ( !collisionModelManager->TrmFromModel( gameLocal.GetMapName(), clipModelName, trm ) ) {
|
||||
gameLocal.Error( "rvClientMoveable '%d': cannot load collision model %s", entityNumber, clipModelName.c_str() );
|
||||
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 ), spawnArgs.GetFloat ( "density", "0.5" ), entityNumber );
|
||||
|
||||
physicsObj.SetOrigin( GetOrigin() );
|
||||
physicsObj.SetAxis( GetAxis() );
|
||||
physicsObj.SetBouncyness( spawnArgs.GetFloat( "bouncyness", "0.6" ) );
|
||||
physicsObj.SetFriction( spawnArgs.GetFloat("linear_friction", "0.6"), spawnArgs.GetFloat( "angular_friction", "0.6"), spawnArgs.GetFloat("friction", "0.05") );
|
||||
physicsObj.SetGravity( gameLocal.GetCurrentGravity(this) );
|
||||
physicsObj.SetContents( 0 );
|
||||
// abahr: changed to MASK_SHOT_RENDERMODEL because brass was getting pinched between the player and the wall in some cases
|
||||
// may want to try something cheaper.
|
||||
physicsObj.SetClipMask( CONTENTS_OPAQUE ); // MASK_SHOT_RENDERMODEL | CONTENTS_CORPSE | CONTENTS_MOVEABLECLIP | CONTENTS_WATER );
|
||||
physicsObj.Activate ( );
|
||||
|
||||
trailEffect = gameLocal.PlayEffect ( spawnArgs, "fx_trail", physicsObj.GetCenterMass(), GetAxis(), true );
|
||||
trailAttenuateSpeed = spawnArgs.GetFloat ( "trailAttenuateSpeed", "200" );
|
||||
|
||||
bounceSoundShader = declManager->FindSound ( spawnArgs.GetString ( "snd_bounce" ), false );
|
||||
bounceSoundTime = 0;
|
||||
mPlayBounceSoundOnce = spawnArgs.GetBool("bounce_sound_once");
|
||||
mHasBounced = false;
|
||||
|
||||
scale.Init( gameLocal.GetTime(), SEC2MS(spawnArgs.GetFloat("scale_reset_duration", "0.2")), Max(VECTOR_EPSILON, spawnArgs.GetFloat("scale", "1.0f")), 1.0f );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientMoveable::SetOrigin
|
||||
================
|
||||
*/
|
||||
void rvClientMoveable::SetOrigin( const idVec3& origin ) {
|
||||
rvClientEntity::SetOrigin( origin );
|
||||
physicsObj.SetOrigin( origin );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientMoveable::SetAxis
|
||||
================
|
||||
*/
|
||||
void rvClientMoveable::SetAxis( const idMat3& axis ) {
|
||||
rvClientEntity::SetAxis( axis );
|
||||
physicsObj.SetAxis( axis );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientMoveable::SetOwner
|
||||
================
|
||||
*/
|
||||
void rvClientMoveable::SetOwner( idEntity* owner ) {
|
||||
physicsObj.GetClipModel()->SetOwner( owner );
|
||||
physicsObj.GetClipModel()->SetEntity( owner );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientMoveable::Think
|
||||
================
|
||||
*/
|
||||
void rvClientMoveable::Think ( void ) {
|
||||
if( bindMaster && (bindMaster->GetRenderEntity()->hModel && bindMaster->GetModelDefHandle() == -1) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
RunPhysics ( );
|
||||
|
||||
// Special case the sound update to use the center mass since the origin may be in an odd place
|
||||
idSoundEmitter *emitter = soundSystem->EmitterForIndex( SOUNDWORLD_GAME, refSound.referenceSoundHandle );
|
||||
if ( emitter ) {
|
||||
refSound.origin = worldOrigin;
|
||||
refSound.velocity = worldVelocity;
|
||||
emitter->UpdateEmitter( refSound.origin, refSound.velocity, refSound.listenerId, &refSound.parms );
|
||||
}
|
||||
|
||||
// Keep the trail effect following
|
||||
if ( trailEffect ) {
|
||||
float speed;
|
||||
speed = idMath::ClampFloat ( 0, trailAttenuateSpeed, worldVelocity.LengthFast ( ) );
|
||||
if ( physicsObj.IsAtRest ( ) ) {
|
||||
trailEffect->Stop ( );
|
||||
trailEffect = NULL;
|
||||
} else {
|
||||
trailEffect->SetOrigin ( worldOrigin );
|
||||
trailEffect->SetAxis ( worldAxis );
|
||||
trailEffect->Attenuate ( speed / trailAttenuateSpeed );
|
||||
}
|
||||
}
|
||||
|
||||
renderEntity.origin = worldOrigin;
|
||||
renderEntity.axis = worldAxis * scale.GetCurrentValue( gameLocal.GetTime() );
|
||||
|
||||
// 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 (mPlayBounceSoundOnce && mHasBounced)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ( bounceSoundShader && gameLocal.time > bounceSoundTime ) {
|
||||
float speed;
|
||||
speed = velocity.LengthFast ( );
|
||||
if ( speed > BOUNCE_SOUND_MIN_VELOCITY ) {
|
||||
StartSoundShader ( bounceSoundShader, SND_CHANNEL_BODY, 0 );
|
||||
bounceSoundTime = BOUNCE_SOUND_DELAY;
|
||||
mHasBounced = true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientMoveable::Save
|
||||
================
|
||||
*/
|
||||
void rvClientMoveable::Save( idSaveGame *savefile ) const {
|
||||
savefile->WriteRenderEntity( renderEntity );
|
||||
savefile->WriteInt( entityDefHandle );
|
||||
|
||||
trailEffect.Save( savefile );
|
||||
savefile->WriteFloat( trailAttenuateSpeed );
|
||||
|
||||
savefile->WriteStaticObject( physicsObj );
|
||||
|
||||
savefile->WriteInt( bounceSoundTime );
|
||||
savefile->WriteSoundShader( bounceSoundShader );
|
||||
|
||||
savefile->WriteBool(mPlayBounceSoundOnce);
|
||||
savefile->WriteBool(mHasBounced);
|
||||
|
||||
// TOSAVE: idInterpolate<float> scale;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientMoveable::Restore
|
||||
================
|
||||
*/
|
||||
void rvClientMoveable::Restore( idRestoreGame *savefile ) {
|
||||
savefile->ReadRenderEntity( renderEntity, NULL );
|
||||
savefile->ReadInt( entityDefHandle );
|
||||
|
||||
trailEffect.Restore( savefile );
|
||||
savefile->ReadFloat( trailAttenuateSpeed );
|
||||
|
||||
savefile->ReadStaticObject( physicsObj );
|
||||
|
||||
savefile->ReadInt( bounceSoundTime );
|
||||
savefile->ReadSoundShader( bounceSoundShader );
|
||||
|
||||
savefile->ReadBool(mPlayBounceSoundOnce);
|
||||
savefile->ReadBool(mHasBounced);
|
||||
|
||||
// restore must retrieve entityDefHandle from the renderer
|
||||
if ( entityDefHandle != -1 ) {
|
||||
entityDefHandle = gameRenderWorld->AddEntityDef( &renderEntity );
|
||||
}
|
||||
|
||||
// TORESTORE: idInterpolate<float> scale;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientMoveable::Event_FadeOut
|
||||
================
|
||||
*/
|
||||
void rvClientMoveable::Event_FadeOut ( int duration ) {
|
||||
renderEntity.noShadow = true;
|
||||
renderEntity.shaderParms[ SHADERPARM_TIME_OF_DEATH ] = gameLocal.time * 0.001f;
|
||||
PostEventMS ( &EV_Remove, duration );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientMoveable::Event_ClearDepthHack
|
||||
================
|
||||
*/
|
||||
void rvClientMoveable::Event_ClearDepthHack ( void ) {
|
||||
renderEntity.weaponDepthHackInViewID = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvClientMoveable::SpawnClientMoveables
|
||||
================
|
||||
*/
|
||||
void rvClientMoveable::SpawnClientMoveables( idEntity* ent, const char *type, idList<rvClientMoveable *>* list ) {
|
||||
const idKeyValue *kv;
|
||||
idVec3 origin;
|
||||
idMat3 axis;
|
||||
|
||||
if( list == NULL || type == NULL ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// drop all items
|
||||
kv = ent->spawnArgs.MatchPrefix( va( "def_%s", type ), NULL );
|
||||
while ( kv ) {
|
||||
origin = ent->GetPhysics()->GetOrigin();
|
||||
axis = ent->GetPhysics()->GetAxis();
|
||||
|
||||
// RAVEN BEGIN
|
||||
// jnewquist: Use accessor for static class type
|
||||
if( ent->IsType( idAnimatedEntity::GetClassType() ) ) {
|
||||
// RAVEN END
|
||||
idAnimatedEntity* animEnt = static_cast<idAnimatedEntity*>(ent);
|
||||
jointHandle_t clientMoveableJoint;
|
||||
|
||||
const char* clientMoveableJointName = ent->spawnArgs.GetString( va( "%s_joint", kv->GetKey().c_str() + 4 ) );
|
||||
|
||||
// use a joint if specified
|
||||
if ( idStr::Icmp( clientMoveableJointName, "") ) {
|
||||
clientMoveableJoint = animEnt->GetAnimator()->GetJointHandle( clientMoveableJointName );
|
||||
|
||||
if ( !animEnt->GetJointWorldTransform( clientMoveableJoint, gameLocal.time, origin, axis ) ) {
|
||||
gameLocal.Warning( "%s refers to invalid joint '%s' on entity '%s'\n", va( "%s_joint", kv->GetKey().c_str() + 4 ), clientMoveableJointName, ent->name.c_str() );
|
||||
origin = ent->GetPhysics()->GetOrigin();
|
||||
axis = ent->GetPhysics()->GetAxis();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// spawn the entity
|
||||
const idDict* entityDef = gameLocal.FindEntityDefDict ( kv->GetValue().c_str(), false );
|
||||
|
||||
if ( entityDef == NULL ) {
|
||||
gameLocal.Warning( "%s refers to invalid entity def '%s' on entity '%s'\n", kv->GetKey().c_str(), kv->GetValue().c_str(), ent->name.c_str() );
|
||||
break;
|
||||
}
|
||||
|
||||
rvClientMoveable* newModel = NULL;
|
||||
// force spawnclass to rvClientMoveable
|
||||
gameLocal.SpawnClientEntityDef( *entityDef, (rvClientEntity**)(&newModel), false, "rvClientMoveable" );
|
||||
|
||||
if( !newModel ) {
|
||||
gameLocal.Warning( "error spawning client moveable (invalid entity def '%s' on entity '%s')\n", kv->GetValue().c_str(), ent->name.c_str() );
|
||||
break;
|
||||
}
|
||||
newModel->SetOrigin ( origin );
|
||||
newModel->SetAxis( axis );
|
||||
|
||||
list->Append( newModel );
|
||||
kv = ent->spawnArgs.MatchPrefix( va( "def_%s", type ), kv );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
//----------------------------------------------------------------
|
||||
// ClientMoveable.h
|
||||
//
|
||||
// Copyright 2002-2004 Raven Software
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#ifndef __GAME_CLIENT_MOVEABLE_H__
|
||||
#define __GAME_CLIENT_MOVEABLE_H__
|
||||
|
||||
class rvClientMoveable : public rvClientEntity {
|
||||
public:
|
||||
|
||||
CLASS_PROTOTYPE( rvClientMoveable );
|
||||
|
||||
rvClientMoveable ( void );
|
||||
virtual ~rvClientMoveable ( void );
|
||||
|
||||
virtual void Spawn ( void );
|
||||
virtual void Think ( void );
|
||||
virtual idPhysics* GetPhysics ( void ) const;
|
||||
virtual bool Collide ( const trace_t &collision, const idVec3 &velocity );
|
||||
|
||||
renderEntity_t* GetRenderEntity ( void );
|
||||
|
||||
void Save ( idSaveGame *savefile ) const;
|
||||
void Restore ( idRestoreGame *savefile );
|
||||
|
||||
static void SpawnClientMoveables ( idEntity* ent, const char *type, idList<rvClientMoveable *>* list );
|
||||
|
||||
virtual void FreeEntityDef ( void );
|
||||
|
||||
void SetOwner ( idEntity* ent );
|
||||
|
||||
void SetOrigin ( const idVec3& origin );
|
||||
void SetAxis ( const idMat3& axis );
|
||||
protected:
|
||||
renderEntity_t renderEntity;
|
||||
int entityDefHandle;
|
||||
|
||||
rvClientEffectPtr trailEffect;
|
||||
float trailAttenuateSpeed;
|
||||
|
||||
idPhysics_RigidBody physicsObj;
|
||||
|
||||
int bounceSoundTime;
|
||||
const idSoundShader* bounceSoundShader;
|
||||
bool mPlayBounceSoundOnce;
|
||||
bool mHasBounced;
|
||||
|
||||
idInterpolate<float> scale;
|
||||
|
||||
private:
|
||||
|
||||
void Event_FadeOut ( int duration );
|
||||
void Event_ClearDepthHack ( void );
|
||||
};
|
||||
|
||||
ID_INLINE renderEntity_t* rvClientMoveable::GetRenderEntity ( void ) {
|
||||
return &renderEntity;
|
||||
}
|
||||
|
||||
extern const idEventDef CL_FadeOut;
|
||||
extern const idEventDef CL_ClearDepthHack;
|
||||
|
||||
#define SIMPLE_TRI_NAME "simpletri"
|
||||
|
||||
extern idVec3 simpleTri[3];
|
||||
|
||||
|
||||
#endif // __GAME_CLIENT_MOVEABLE_H__
|
||||
Reference in New Issue
Block a user