824 lines
22 KiB
C++
824 lines
22 KiB
C++
|
// Copyright (C) 2007 Id Software, Inc.
|
||
|
//
|
||
|
|
||
|
#include "../precompiled.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#if defined( _DEBUG ) && !defined( ID_REDIRECT_NEWDELETE )
|
||
|
#define new DEBUG_NEW
|
||
|
#undef THIS_FILE
|
||
|
static char THIS_FILE[] = __FILE__;
|
||
|
#endif
|
||
|
|
||
|
#include "JetPack.h"
|
||
|
#include "TransportComponents.h"
|
||
|
#include "../ContentMask.h"
|
||
|
#include "../client/ClientEntity.h"
|
||
|
#include "VehicleView.h"
|
||
|
#include "VehicleControl.h"
|
||
|
|
||
|
|
||
|
|
||
|
#define ENABLE_JP_FLOAT_CHECKS
|
||
|
#if defined( ENABLE_JP_FLOAT_CHECKS )
|
||
|
#undef FLOAT_CHECK_BAD
|
||
|
#undef VEC_CHECK_BAD
|
||
|
|
||
|
#define FLOAT_CHECK_BAD( x ) \
|
||
|
if ( FLOAT_IS_NAN( x ) ) gameLocal.Error( "Bad floating point number in %s(%i): " #x " is NAN", __FILE__, __LINE__ ); \
|
||
|
if ( FLOAT_IS_INF( x ) ) gameLocal.Error( "Bad floating point number in %s(%i): " #x " is INF", __FILE__, __LINE__ ); \
|
||
|
if ( FLOAT_IS_IND( x ) ) gameLocal.Error( "Bad floating point number in %s(%i): " #x " is IND", __FILE__, __LINE__ ); \
|
||
|
if ( FLOAT_IS_DENORMAL( x ) ) gameLocal.Error( "Bad floating point number in %s(%i): " #x " is DEN", __FILE__, __LINE__ ); \
|
||
|
|
||
|
|
||
|
#define VEC_CHECK_BAD( vec ) FLOAT_CHECK_BAD( ( vec ).x ); FLOAT_CHECK_BAD( ( vec ).y ); FLOAT_CHECK_BAD( ( vec ).z );
|
||
|
#define MAT_CHECK_BAD( m ) VEC_CHECK_BAD( m[ 0 ] ); VEC_CHECK_BAD( m[ 1 ] ); VEC_CHECK_BAD( m[ 2 ] );
|
||
|
#define ANG_CHECK_BAD( ang ) FLOAT_CHECK_BAD( ( ang ).pitch ); FLOAT_CHECK_BAD( ( ang ).roll ); FLOAT_CHECK_BAD( ( ang ).yaw );
|
||
|
#else
|
||
|
#define MAT_CHECK_BAD( m )
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/*
|
||
|
===============================================================================
|
||
|
|
||
|
sdJetPack
|
||
|
|
||
|
===============================================================================
|
||
|
*/
|
||
|
|
||
|
extern const idEventDef EV_GetViewAngles;
|
||
|
|
||
|
const idEventDef EV_GetChargeFraction( "getChargeFraction", 'f', DOC_TEXT( "Returns the fraction of boost charge left." ), 0, NULL );
|
||
|
|
||
|
CLASS_DECLARATION( sdTransport, sdJetPack )
|
||
|
EVENT( EV_GetChargeFraction, sdJetPack::Event_GetChargeFraction )
|
||
|
EVENT( EV_GetViewAngles, sdJetPack::Event_GetViewAngles )
|
||
|
END_CLASS
|
||
|
|
||
|
CLASS_DECLARATION( sdClientAnimated, sdJetPackVisuals )
|
||
|
END_CLASS
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::sdJetPack
|
||
|
================
|
||
|
*/
|
||
|
sdJetPack::sdJetPack( void ) {
|
||
|
lastAngles.Zero();
|
||
|
visuals = NULL;
|
||
|
collideDamage = NULL;
|
||
|
fallDamage = NULL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::~sdJetPack
|
||
|
================
|
||
|
*/
|
||
|
sdJetPack::~sdJetPack( void ) {
|
||
|
positionManager.EjectAllPlayers();
|
||
|
|
||
|
if ( visuals.IsValid() ) {
|
||
|
visuals->Dispose();
|
||
|
visuals = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::DoLoadVehicleScript
|
||
|
================
|
||
|
*/
|
||
|
void sdJetPack::DoLoadVehicleScript( void ) {
|
||
|
LoadParts( VPT_SIMPLE_PART | VPT_ANTIGRAV | VPT_SCRIPTED_PART );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::LoadParts
|
||
|
================
|
||
|
*/
|
||
|
void sdJetPack::LoadParts( int partTypes ) {
|
||
|
ClearDriveObjects();
|
||
|
|
||
|
int i;
|
||
|
|
||
|
if ( partTypes & VPT_SIMPLE_PART ) {
|
||
|
for( i = 0; i < vehicleScript->parts.Num(); i++ ) {
|
||
|
if ( vehicleScript->parts[ i ].type != VPT_SIMPLE_PART ) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
sdVehiclePartSimple* part = new sdVehiclePartSimple;
|
||
|
part->SetIndex( driveObjects.Num() );
|
||
|
part->Init( *vehicleScript->parts[ i ].part, this );
|
||
|
|
||
|
AddDriveObject( part );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( partTypes & VPT_ANTIGRAV ) {
|
||
|
for( i = 0; i < vehicleScript->parts.Num(); i++ ) {
|
||
|
if ( vehicleScript->parts[ i ].type != VPT_ANTIGRAV ) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
sdVehicleRigidBodyAntiGrav* part = new sdVehicleRigidBodyAntiGrav;
|
||
|
part->SetIndex( driveObjects.Num() );
|
||
|
part->Init( *vehicleScript->parts[ i ].part, this );
|
||
|
part->SetClientParent( visuals );
|
||
|
|
||
|
AddDriveObject( part );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( partTypes & VPT_SCRIPTED_PART ) {
|
||
|
for( i = 0; i < vehicleScript->parts.Num(); i++ ) {
|
||
|
if ( vehicleScript->parts[ i ].type != VPT_SCRIPTED_PART ) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
sdVehiclePartScripted* part = new sdVehiclePartScripted;
|
||
|
part->SetIndex( driveObjects.Num() );
|
||
|
part->Init( *vehicleScript->parts[ i ].part, this );
|
||
|
|
||
|
AddDriveObject( part );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::Spawn
|
||
|
================
|
||
|
*/
|
||
|
void sdJetPack::Spawn( void ) {
|
||
|
maxJumpCharge = spawnArgs.GetFloat( "max_jump_charge", "100" );
|
||
|
currentJumpCharge = maxJumpCharge;
|
||
|
dischargeRate = spawnArgs.GetFloat( "rate_discharge", "10" );
|
||
|
chargeRate = spawnArgs.GetFloat( "rate_charge", "5" );
|
||
|
|
||
|
float maxStepHeight;
|
||
|
if ( !spawnArgs.GetFloat( "max_step_height", "0", maxStepHeight ) ) {
|
||
|
maxStepHeight = pm_stepsize.GetFloat();
|
||
|
}
|
||
|
|
||
|
physicsObj.SetMaxStepHeight( maxStepHeight );
|
||
|
|
||
|
lastAngles = GetPhysics()->GetAxis().ToAngles();
|
||
|
lastAxis = GetPhysics()->GetAxis();
|
||
|
|
||
|
ANG_CHECK_BAD( lastAngles );
|
||
|
MAT_CHECK_BAD( lastAxis );
|
||
|
|
||
|
physicsObj.SetSelf( this );
|
||
|
|
||
|
//
|
||
|
// Set the main clip model
|
||
|
//
|
||
|
idBounds bounds;
|
||
|
idVec3 cmbounds = spawnArgs.GetVector( "cm_bounds" );
|
||
|
bounds[ 0 ].Set( -cmbounds.x, -cmbounds.x, cmbounds.y );
|
||
|
bounds[ 1 ].Set( cmbounds.x, cmbounds.x, cmbounds.z );
|
||
|
|
||
|
idClipModel* newClip = new idClipModel( idTraceModel( bounds ), false );
|
||
|
newClip->SetContents( CONTENTS_SLIDEMOVER );
|
||
|
newClip->Translate( physicsObj.GetCurrentOrigin(), gameLocal.clip );
|
||
|
physicsObj.SetClipModel( newClip, 1.0f );
|
||
|
physicsObj.SetClipMask( MASK_PLAYERSOLID );
|
||
|
|
||
|
//
|
||
|
// Set the shot clip model
|
||
|
//
|
||
|
idVec3 shotmins;
|
||
|
idVec3 shotmaxs;
|
||
|
if ( spawnArgs.GetVector( "cm_shot_mins", "0 0 0", shotmins )
|
||
|
&& spawnArgs.GetVector( "cm_shot_maxs", "0 0 0", shotmaxs ) ) {
|
||
|
bounds[ 0 ] = shotmins;
|
||
|
bounds[ 1 ] = shotmaxs;
|
||
|
}
|
||
|
|
||
|
idClipModel* shotClip = new idClipModel( idTraceModel( bounds ), false );
|
||
|
shotClip->SetContents( CONTENTS_RENDERMODEL );
|
||
|
shotClip->Translate( physicsObj.GetCurrentOrigin(), gameLocal.clip );
|
||
|
physicsObj.SetClipModel( shotClip, 1.0f, 1 );
|
||
|
|
||
|
physicsObj.SetGravity( GetPhysics()->GetGravityNormal() * spawnArgs.GetFloat( "gravity", DEFAULT_GRAVITY_STRING ) );
|
||
|
|
||
|
physicsObj.SetMass( spawnArgs.GetFloat( "mass", "100" ) );
|
||
|
physicsObj.SetOrigin( GetPhysics()->GetOrigin() );
|
||
|
|
||
|
// parameters specific to the jetpack
|
||
|
physicsObj.SetMaxSpeed( spawnArgs.GetFloat( "max_speed", "320" ) );
|
||
|
physicsObj.SetMaxBoostSpeed( spawnArgs.GetFloat( "max_boost_speed", "500" ) );
|
||
|
physicsObj.SetWalkForceScale( spawnArgs.GetFloat( "walk_force_scale", "0.4" ) );
|
||
|
physicsObj.SetKineticFriction( spawnArgs.GetFloat( "kinetic_friction", "10" ) );
|
||
|
physicsObj.SetJumpForce( spawnArgs.GetFloat( "jump_force", "4800" ) );
|
||
|
physicsObj.SetBoostForce( spawnArgs.GetFloat( "boost_force", "1200" ) );
|
||
|
|
||
|
SetPhysics( &physicsObj );
|
||
|
|
||
|
// create the visual model
|
||
|
idDict args;
|
||
|
args.Set( "classname", spawnArgs.GetString( "def_visuals" ) );
|
||
|
rvClientEntity* vis = NULL;
|
||
|
if ( !gameLocal.SpawnClientEntityDef( args, &vis ) && gameLocal.DoClientSideStuff() ) {
|
||
|
gameLocal.Error( "sdJetPack::Spawn - couldn't spawn jetpack client entity" );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
visuals = vis;
|
||
|
if ( visuals ) {
|
||
|
visuals->SetOrigin( GetPhysics()->GetOrigin() );
|
||
|
}
|
||
|
|
||
|
const char* damagename = spawnArgs.GetString( "dmg_collide" );
|
||
|
if ( *damagename ) {
|
||
|
collideDamage = gameLocal.declDamageType.LocalFind( damagename, false );
|
||
|
if( !collideDamage ) {
|
||
|
gameLocal.Warning( "sdJetPack::Spawn Invalid Damage Type '%s'", damagename );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
damagename = spawnArgs.GetString( "dmg_fall" );
|
||
|
if ( *damagename ) {
|
||
|
fallDamage = gameLocal.declDamageType.LocalFind( damagename, false );
|
||
|
if( !fallDamage ) {
|
||
|
gameLocal.Warning( "sdJetPack::Spawn Invalid Damage Type '%s'", damagename );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
minFallDamageSpeed = spawnArgs.GetFloat( "fall_damage_speed_min", "80" );
|
||
|
maxFallDamageSpeed = spawnArgs.GetFloat( "fall_damage_speed_max", "2000" );
|
||
|
|
||
|
nextSelfCollisionTime = gameLocal.time + SEC2MS( 5 ); // 5s spawn invulnerability to allow it to drop to the ground
|
||
|
nextCollisionTime = 0;
|
||
|
|
||
|
LoadVehicleScript();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::WantsToThink
|
||
|
================
|
||
|
*/
|
||
|
bool sdJetPack::WantsToThink( void ) {
|
||
|
if ( currentJumpCharge != maxJumpCharge ) {
|
||
|
return true;
|
||
|
}
|
||
|
return sdTransport::WantsToThink();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::Think
|
||
|
================
|
||
|
*/
|
||
|
void sdJetPack::Think( void ) {
|
||
|
idPlayer* driver = GetPositionManager().FindDriver();
|
||
|
|
||
|
usercmd_t cmd;
|
||
|
if ( driver ) {
|
||
|
cmd = gameLocal.usercmds[ driver->entityNumber ];
|
||
|
lastAngles = driver->clientViewAngles;
|
||
|
ANG_CHECK_BAD( lastAngles );
|
||
|
physicsObj.SetPlayerInput( cmd, lastAngles, true );
|
||
|
} else {
|
||
|
memset( &cmd, 0, sizeof( cmd ) );
|
||
|
ANG_CHECK_BAD( lastAngles );
|
||
|
physicsObj.SetPlayerInput( cmd, lastAngles, true );
|
||
|
}
|
||
|
|
||
|
if ( cmd.buttons.btn.sprint && !IsTeleporting() && !IsEMPed() ) {
|
||
|
currentJumpCharge -= MS2SEC( gameLocal.msec ) * dischargeRate;
|
||
|
if ( currentJumpCharge < 0.f ) {
|
||
|
currentJumpCharge = 0.f;
|
||
|
}
|
||
|
physicsObj.SetBoost( currentJumpCharge == 0.f ? 0.f : 1.0f );
|
||
|
} else {
|
||
|
currentJumpCharge += MS2SEC( gameLocal.msec ) * chargeRate;
|
||
|
if ( currentJumpCharge > maxJumpCharge ) {
|
||
|
currentJumpCharge = maxJumpCharge;
|
||
|
}
|
||
|
physicsObj.SetBoost( 0.0f );
|
||
|
}
|
||
|
|
||
|
if ( IsEMPed() ) {
|
||
|
physicsObj.SetComeToRest( true );
|
||
|
} else {
|
||
|
physicsObj.SetComeToRest( false );
|
||
|
}
|
||
|
|
||
|
// update the lastAxis
|
||
|
lastAngles.FixDenormals();
|
||
|
lastAxis = lastAngles.ToMat3();
|
||
|
lastAxis.FixDenormals();
|
||
|
MAT_CHECK_BAD( lastAxis );
|
||
|
|
||
|
sdTransport::Think();
|
||
|
|
||
|
LinkCombat();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::UpdateJetPackVisuals
|
||
|
================
|
||
|
*/
|
||
|
void sdJetPack::UpdateJetPackVisuals( void ) {
|
||
|
if ( visuals ) {
|
||
|
if ( !visuals->IsBound() ) {
|
||
|
idMat3 axis;
|
||
|
idAngles::YawToMat3( lastAngles.yaw, axis );
|
||
|
MAT_CHECK_BAD( axis );
|
||
|
|
||
|
idPlayer* driver = GetPositionManager().FindDriver();
|
||
|
if ( driver ) {
|
||
|
idVec3 offset( 4.0f, 0.0f, 39.0f );
|
||
|
|
||
|
idVec3 baseOrigin = physicsObj.GetOrigin();
|
||
|
|
||
|
sdTeleporter* teleportEnt = GetTeleportEntity();
|
||
|
if ( teleportEnt != NULL ) {
|
||
|
idPlayer* player = gameLocal.GetLocalViewPlayer();
|
||
|
if ( player != NULL && player->GetProxyEntity() == this ) {
|
||
|
idEntity* viewer = teleportEnt->GetViewEntity();
|
||
|
if ( viewer != NULL ) {
|
||
|
baseOrigin = viewer->GetPhysics()->GetOrigin();
|
||
|
axis = viewer->GetPhysics()->GetAxis();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
idVec3 posToMatchTo;
|
||
|
idMat3 axisToMatchTo;
|
||
|
driver->GetAnimator()->GetJointTransform( driver->GetAnimator()->GetJointHandle( "hips" ), gameLocal.time, posToMatchTo, axisToMatchTo );
|
||
|
|
||
|
const renderEntity_t* re = driver->GetRenderEntity();
|
||
|
posToMatchTo = posToMatchTo * re->axis + re->origin;
|
||
|
|
||
|
idVec3 posToMatch = baseOrigin + offset * axis;
|
||
|
idVec3 offsetNeeded = posToMatchTo - posToMatch;
|
||
|
|
||
|
visuals->SetOrigin( baseOrigin + offsetNeeded );
|
||
|
visuals->SetAxis( axis );
|
||
|
} else {
|
||
|
visuals->SetAxis( axis );
|
||
|
visuals->SetOrigin( physicsObj.GetOrigin() );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::UpdateModelTransform
|
||
|
================
|
||
|
*/
|
||
|
void sdJetPack::UpdateModelTransform( void ) {
|
||
|
sdTeleporter* teleportEnt = teleportEntity;
|
||
|
idPlayer* player = gameLocal.GetLocalViewPlayer();
|
||
|
if ( teleportEnt != NULL ) {
|
||
|
if ( player != NULL && player->GetProxyEntity() == this ) {
|
||
|
idEntity* viewer = teleportEnt->GetViewEntity();
|
||
|
if ( viewer ) {
|
||
|
renderEntity.axis = viewer->GetPhysics()->GetAxis();
|
||
|
renderEntity.origin = viewer->GetPhysics()->GetOrigin();
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
idAngles::YawToMat3( lastAngles.yaw, renderEntity.axis );
|
||
|
MAT_CHECK_BAD( renderEntity.axis );
|
||
|
renderEntity.origin = physicsObj.GetOrigin();
|
||
|
|
||
|
if ( !player || player->GetProxyEntity() != this ) {
|
||
|
DoPredictionErrorDecay();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::Present
|
||
|
================
|
||
|
*/
|
||
|
void sdJetPack::Present( void ) {
|
||
|
sdTransport::Present();
|
||
|
|
||
|
// add to interpolate list just after the driver
|
||
|
idPlayer* driver = GetPositionManager().FindDriver();
|
||
|
if ( !gameLocal.unlock.unlockedDraw && driver != NULL && driver->interpolateNode.InList() ) {
|
||
|
interpolateNode.InsertAfter( driver->interpolateNode );
|
||
|
}
|
||
|
|
||
|
UpdateJetPackVisuals();
|
||
|
if ( visuals.IsValid() ) {
|
||
|
visuals->ClientUpdateView();
|
||
|
|
||
|
renderEntity.origin = visuals->GetRenderEntity()->origin;
|
||
|
renderEntity.axis = visuals->GetRenderEntity()->axis;
|
||
|
lastPushedOrigin = renderEntity.origin;
|
||
|
lastPushedAxis = renderEntity.axis;
|
||
|
}
|
||
|
|
||
|
// update the antigrav parts again so that their effect appears in the right place
|
||
|
// Yes! This is horrible!
|
||
|
for ( int i = 0; i < activeObjects.Num(); i++ ) {
|
||
|
sdVehicleRigidBodyAntiGrav* antiGrav = activeObjects[ i ]->Cast< sdVehicleRigidBodyAntiGrav >();
|
||
|
if ( antiGrav ) {
|
||
|
antiGrav->UpdateEffect();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::GetChargeFraction
|
||
|
================
|
||
|
*/
|
||
|
float sdJetPack::GetChargeFraction( void ) const {
|
||
|
return currentJumpCharge / maxJumpCharge;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::Event_GetChargeFraction
|
||
|
================
|
||
|
*/
|
||
|
void sdJetPack::Event_GetChargeFraction( void ) {
|
||
|
sdProgram::ReturnFloat( GetChargeFraction() );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::Event_GetViewAngles
|
||
|
================
|
||
|
*/
|
||
|
void sdJetPack::Event_GetViewAngles( void ) {
|
||
|
sdProgram::ReturnVector( idVec3( lastAngles[ 0 ], lastAngles[ 1 ], lastAngles[ 2 ] ) );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::SetAxis
|
||
|
================
|
||
|
*/
|
||
|
void sdJetPack::SetAxis( const idMat3& axis ) {
|
||
|
idPlayer* driver = GetPositionManager().FindDriver();
|
||
|
if ( driver ) {
|
||
|
driver->SetAxis( axis );
|
||
|
}
|
||
|
|
||
|
lastAngles = axis.ToAngles();
|
||
|
lastAxis = axis;
|
||
|
|
||
|
ANG_CHECK_BAD( lastAngles );
|
||
|
MAT_CHECK_BAD( lastAxis );
|
||
|
|
||
|
// if ( predictionErrorDecay != NULL ) {
|
||
|
// predictionErrorDecay->Reset( GetPhysics()->GetOrigin(), GetPhysics()->GetAxis() );
|
||
|
// }
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::OnGround
|
||
|
================
|
||
|
*/
|
||
|
bool sdJetPack::OnGround() {
|
||
|
return physicsObj.OnGround();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::UpdateVisibility
|
||
|
================
|
||
|
*/
|
||
|
void sdJetPack::UpdateVisibility( void ) {
|
||
|
// jetpack always has hidden main entity
|
||
|
Hide();
|
||
|
|
||
|
bool hide = false;
|
||
|
bool disableInView = false;
|
||
|
|
||
|
idPlayer* viewPlayer = gameLocal.GetLocalViewPlayer();
|
||
|
|
||
|
if ( viewPlayer != NULL && viewPlayer->GetProxyEntity() == this ) {
|
||
|
renderEntity.flags.disableLODs = true;
|
||
|
} else {
|
||
|
renderEntity.flags.disableLODs = false;
|
||
|
}
|
||
|
|
||
|
if ( vehicleFlags.modelDisabled ) {
|
||
|
hide = true;
|
||
|
} else {
|
||
|
if ( viewPlayer && viewPlayer->GetProxyEntity() == this ) {
|
||
|
if ( GetViewForPlayer( viewPlayer ).GetViewParms().hideVehicle ) {
|
||
|
disableInView = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( visuals ) {
|
||
|
sdClientAnimated* animated = visuals->Cast< sdClientAnimated >();
|
||
|
|
||
|
if ( animated ) {
|
||
|
if ( hide ) {
|
||
|
animated->Hide();
|
||
|
} else if ( disableInView ) {
|
||
|
animated->Show();
|
||
|
|
||
|
visuals->GetRenderEntity()->suppressSurfaceInViewID = viewPlayer->entityNumber + 1;
|
||
|
visuals->GetRenderEntity()->suppressShadowInViewID = viewPlayer->entityNumber + 1;
|
||
|
} else {
|
||
|
animated->Show();
|
||
|
|
||
|
visuals->GetRenderEntity()->suppressSurfaceInViewID = 0;
|
||
|
visuals->GetRenderEntity()->suppressShadowInViewID = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::OnPlayerEntered
|
||
|
================
|
||
|
*/
|
||
|
void sdJetPack::OnPlayerEntered( idPlayer* player, int position, int oldPosition ) {
|
||
|
sdTransport::OnPlayerEntered( player, position, oldPosition );
|
||
|
|
||
|
if ( visuals ) {
|
||
|
visuals->SetOrigin( vec3_origin );
|
||
|
// visuals->Bind( player, player->GetAnimator()->GetJointHandle( "Spine1" ) );
|
||
|
}
|
||
|
|
||
|
// Gordon: force an update so we don't get a flicker
|
||
|
Think();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::OnPlayerExited
|
||
|
================
|
||
|
*/
|
||
|
void sdJetPack::OnPlayerExited( idPlayer* player, int position ) {
|
||
|
sdTransport::OnPlayerExited( player, position );
|
||
|
|
||
|
if ( visuals ) {
|
||
|
visuals->Unbind();
|
||
|
|
||
|
idMat3 axis;
|
||
|
idAngles::YawToMat3( lastAngles.yaw, axis );
|
||
|
MAT_CHECK_BAD( axis );
|
||
|
visuals->SetAxis( axis );
|
||
|
visuals->SetOrigin( physicsObj.GetOrigin() );
|
||
|
}
|
||
|
|
||
|
if ( player == gameLocal.GetLocalViewPlayer() ) {
|
||
|
ResetPredictionErrorDecay();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::SetTeleportEntity
|
||
|
================
|
||
|
*/
|
||
|
void sdJetPack::SetTeleportEntity( sdTeleporter* teleporter ) {
|
||
|
idPlayer* driver = positionManager.FindDriver();
|
||
|
idMat3 oldAxis;
|
||
|
if ( driver != NULL ) {
|
||
|
oldAxis = driver->GetAxis();
|
||
|
MAT_CHECK_BAD( oldAxis );
|
||
|
}
|
||
|
|
||
|
if ( teleporter != NULL ) {
|
||
|
idEntity* viewer = teleporter->GetViewEntity();
|
||
|
if ( viewer != NULL ) {
|
||
|
oldAxis = viewer->GetPhysics()->GetAxis();
|
||
|
lastAxis = oldAxis;
|
||
|
lastAngles = lastAxis.ToAngles();
|
||
|
MAT_CHECK_BAD( lastAxis );
|
||
|
ANG_CHECK_BAD( lastAngles );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sdTransport::SetTeleportEntity( teleporter );
|
||
|
|
||
|
if ( driver != NULL ) {
|
||
|
driver->SetAxis( oldAxis );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::LinkCombat
|
||
|
================
|
||
|
*/
|
||
|
void sdJetPack::LinkCombat( void ) {
|
||
|
renderEntity_t* re = NULL;
|
||
|
if ( visuals ) {
|
||
|
re = visuals->GetRenderEntity();
|
||
|
} else {
|
||
|
re = GetRenderEntity();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::Collide
|
||
|
================
|
||
|
*/
|
||
|
bool sdJetPack::Collide( const trace_t &collision, const idVec3 &velocity, int bodyId ) {
|
||
|
// FIXME: This stuff should be done on collisions against us too.
|
||
|
idVec3 normal = -collision.c.normal;
|
||
|
float length = ( velocity * normal );
|
||
|
idVec3 v = length * normal;
|
||
|
idEntity* driver = positionManager.FindDriver();
|
||
|
idPlayer* playerDriver = NULL;
|
||
|
|
||
|
if ( driver != NULL ) {
|
||
|
playerDriver = driver->Cast< idPlayer >();
|
||
|
assert( playerDriver != NULL );
|
||
|
}
|
||
|
|
||
|
// do falling damage
|
||
|
if ( length > 40.0f && !( collision.c.material != NULL && collision.c.material->GetSurfaceFlags() & SURF_NODAMAGE ) ) {
|
||
|
|
||
|
const float VELOCITY_LAND_HARD = 0.7f;
|
||
|
const float VELOCITY_LAND_MEDIUM = 0.4f;
|
||
|
const float VELOCITY_LAND_LIGHT = 0.1f;
|
||
|
const float VELOCITY_LAND_SOFT = 500.0f;
|
||
|
|
||
|
float damageScale = ( length - minFallDamageSpeed ) / ( maxFallDamageSpeed - minFallDamageSpeed );
|
||
|
damageScale = idMath::ClampFloat( -1.0f, 1.0f, damageScale );
|
||
|
|
||
|
// player animations
|
||
|
if ( playerDriver != NULL ) {
|
||
|
playerDriver->AI_HARDLANDING = false;
|
||
|
playerDriver->AI_SOFTLANDING = false;
|
||
|
|
||
|
if ( damageScale > VELOCITY_LAND_HARD ) {
|
||
|
playerDriver->AI_HARDLANDING = true;
|
||
|
StartSound( "snd_fall_hard", SND_VEHICLE_MISC, 0, NULL );
|
||
|
} else if ( damageScale > VELOCITY_LAND_MEDIUM ) {
|
||
|
playerDriver->AI_HARDLANDING = true;
|
||
|
StartSound( "snd_fall_medium", SND_VEHICLE_MISC, 0, NULL );
|
||
|
} else if ( damageScale > VELOCITY_LAND_LIGHT ) {
|
||
|
playerDriver->AI_HARDLANDING = true;
|
||
|
StartSound( "snd_fall_light", SND_VEHICLE_MISC, 0, NULL );
|
||
|
} else if ( length > VELOCITY_LAND_SOFT ) {
|
||
|
playerDriver->AI_SOFTLANDING = true;
|
||
|
StartSound( "snd_fall_soft", SND_VEHICLE_MISC, 0, NULL );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( fallDamage != NULL && damageScale > 0.0f ) {
|
||
|
Damage( NULL, NULL, idVec3( 0.0f, 0.0f, -1.0f ), fallDamage, damageScale, 0 );
|
||
|
if ( driver != NULL ) {
|
||
|
driver->Damage( NULL, NULL, idVec3( 0.0f, 0.0f, -1.0f ), fallDamage, damageScale, 0 );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return sdTransport::Collide( collision, velocity, bodyId );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::ApplyNetworkState
|
||
|
================
|
||
|
*/
|
||
|
void sdJetPack::ApplyNetworkState( networkStateMode_t mode, const sdEntityStateNetworkData& newState ) {
|
||
|
if ( mode == NSM_VISIBLE ) {
|
||
|
NET_GET_NEW( sdJetPackNetworkData );
|
||
|
|
||
|
currentJumpCharge = newData.currentJumpCharge;
|
||
|
}
|
||
|
|
||
|
sdTransport::ApplyNetworkState( mode, newState );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::ReadNetworkState
|
||
|
================
|
||
|
*/
|
||
|
void sdJetPack::ReadNetworkState( networkStateMode_t mode, const sdEntityStateNetworkData& baseState, sdEntityStateNetworkData& newState, const idBitMsg& msg ) const {
|
||
|
if ( mode == NSM_VISIBLE ) {
|
||
|
NET_GET_STATES( sdJetPackNetworkData );
|
||
|
|
||
|
newData.currentJumpCharge = msg.ReadDeltaFloat( baseData.currentJumpCharge );
|
||
|
}
|
||
|
|
||
|
sdTransport::ReadNetworkState( mode, baseState, newState, msg );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::WriteNetworkState
|
||
|
================
|
||
|
*/
|
||
|
void sdJetPack::WriteNetworkState( networkStateMode_t mode, const sdEntityStateNetworkData& baseState, sdEntityStateNetworkData& newState, idBitMsg& msg ) const {
|
||
|
if ( mode == NSM_VISIBLE ) {
|
||
|
NET_GET_STATES( sdJetPackNetworkData );
|
||
|
|
||
|
newData.currentJumpCharge = currentJumpCharge;
|
||
|
|
||
|
msg.WriteDeltaFloat( baseData.currentJumpCharge, newData.currentJumpCharge );
|
||
|
}
|
||
|
|
||
|
sdTransport::WriteNetworkState( mode, baseState, newState, msg );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::CheckNetworkStateChanges
|
||
|
================
|
||
|
*/
|
||
|
bool sdJetPack::CheckNetworkStateChanges( networkStateMode_t mode, const sdEntityStateNetworkData& baseState ) const {
|
||
|
if ( mode == NSM_VISIBLE ) {
|
||
|
NET_GET_BASE( sdJetPackNetworkData );
|
||
|
NET_CHECK_FIELD( currentJumpCharge, currentJumpCharge );
|
||
|
}
|
||
|
|
||
|
return sdTransport::CheckNetworkStateChanges( mode, baseState );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPack::CreateTransportNetworkStructure
|
||
|
================
|
||
|
*/
|
||
|
sdTransportNetworkData* sdJetPack::CreateTransportNetworkStructure( void ) const {
|
||
|
return new sdJetPackNetworkData();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===============================================================================
|
||
|
|
||
|
sdJetPackVisuals
|
||
|
|
||
|
===============================================================================
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPackVisuals::UpdateRenderEntity
|
||
|
================
|
||
|
*/
|
||
|
bool sdJetPackVisuals::UpdateRenderEntity( renderEntity_t* renderEntity, const renderView_t* renderView, int& lastGameModifiedTime ) {
|
||
|
if ( animator.CreateFrame( gameLocal.time, false ) || lastGameModifiedTime != animator.GetTransformCount() ) {
|
||
|
lastGameModifiedTime = animator.GetTransformCount();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
===============================================================================
|
||
|
|
||
|
sdJetPackNetworkData
|
||
|
|
||
|
===============================================================================
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPackNetworkData::MakeDefault
|
||
|
================
|
||
|
*/
|
||
|
void sdJetPackNetworkData::MakeDefault( void ) {
|
||
|
sdTransportNetworkData::MakeDefault();
|
||
|
|
||
|
currentJumpCharge = 0.0f;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPackNetworkData::Write
|
||
|
================
|
||
|
*/
|
||
|
void sdJetPackNetworkData::Write( idFile* file ) const {
|
||
|
sdTransportNetworkData::Write( file );
|
||
|
|
||
|
file->WriteFloat( currentJumpCharge );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdJetPackNetworkData::Read
|
||
|
================
|
||
|
*/
|
||
|
void sdJetPackNetworkData::Read( idFile* file ) {
|
||
|
sdTransportNetworkData::Read( file );
|
||
|
|
||
|
file->ReadFloat( currentJumpCharge );
|
||
|
}
|
||
|
|