mirror of
https://github.com/nillerusr/source-engine.git
synced 2024-12-23 06:36:54 +00:00
1118 lines
35 KiB
C++
1118 lines
35 KiB
C++
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
// $NoKeywords: $
|
|
//=============================================================================//
|
|
|
|
#include "cbase.h"
|
|
#include "vehicle_base.h"
|
|
#include "engine/IEngineSound.h"
|
|
#include "in_buttons.h"
|
|
#include "soundenvelope.h"
|
|
#include "soundent.h"
|
|
#include "physics_saverestore.h"
|
|
#include "vphysics/constraints.h"
|
|
#include "vcollide_parse.h"
|
|
#include "ndebugoverlay.h"
|
|
#include "npc_vehicledriver.h"
|
|
#include "vehicle_crane.h"
|
|
#include "hl2_player.h"
|
|
#include "rumble_shared.h"
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
#define VEHICLE_HITBOX_DRIVER 1
|
|
|
|
extern ConVar g_debug_vehicledriver;
|
|
|
|
// Crane spring constants
|
|
#define CRANE_SPRING_CONSTANT_HANGING 2e5f
|
|
#define CRANE_SPRING_CONSTANT_INITIAL_RAISING (CRANE_SPRING_CONSTANT_HANGING * 0.5)
|
|
#define CRANE_SPRING_CONSTANT_LOWERING 30.0f
|
|
#define CRANE_SPRING_DAMPING 2e5f
|
|
#define CRANE_SPRING_RELATIVE_DAMPING 2
|
|
|
|
// Crane bones that have physics followers
|
|
static const char *pCraneFollowerBoneNames[] =
|
|
{
|
|
"base",
|
|
"arm",
|
|
"platform",
|
|
};
|
|
|
|
// Crane tip
|
|
LINK_ENTITY_TO_CLASS( crane_tip, CCraneTip );
|
|
|
|
BEGIN_DATADESC( CCraneTip )
|
|
|
|
DEFINE_PHYSPTR( m_pSpring ),
|
|
|
|
END_DATADESC()
|
|
|
|
// Crane
|
|
LINK_ENTITY_TO_CLASS( prop_vehicle_crane, CPropCrane );
|
|
|
|
BEGIN_DATADESC( CPropCrane )
|
|
|
|
// Inputs
|
|
DEFINE_INPUTFUNC( FIELD_VOID, "Lock", InputLock ),
|
|
DEFINE_INPUTFUNC( FIELD_VOID, "Unlock", InputUnlock ),
|
|
DEFINE_INPUTFUNC( FIELD_VOID, "ForcePlayerIn", InputForcePlayerIn ),
|
|
|
|
// Keys
|
|
DEFINE_EMBEDDED( m_ServerVehicle ),
|
|
DEFINE_EMBEDDED( m_BoneFollowerManager ),
|
|
|
|
DEFINE_FIELD( m_hPlayer, FIELD_EHANDLE ),
|
|
DEFINE_FIELD( m_bMagnetOn, FIELD_BOOLEAN ),
|
|
DEFINE_FIELD( m_hNPCDriver, FIELD_EHANDLE ),
|
|
DEFINE_FIELD( m_nNPCButtons, FIELD_INTEGER ),
|
|
DEFINE_FIELD( m_bLocked, FIELD_BOOLEAN ),
|
|
DEFINE_FIELD( m_bEnterAnimOn, FIELD_BOOLEAN ),
|
|
DEFINE_FIELD( m_bExitAnimOn, FIELD_BOOLEAN ),
|
|
DEFINE_FIELD( m_vecEyeExitEndpoint, FIELD_POSITION_VECTOR ),
|
|
DEFINE_OUTPUT( m_playerOn, "PlayerOn" ),
|
|
DEFINE_OUTPUT( m_playerOff, "PlayerOff" ),
|
|
DEFINE_FIELD( m_iTurning, FIELD_INTEGER ),
|
|
DEFINE_FIELD( m_bStartSoundAtCrossover, FIELD_BOOLEAN ),
|
|
DEFINE_FIELD( m_flTurn, FIELD_FLOAT ),
|
|
DEFINE_FIELD( m_bExtending, FIELD_BOOLEAN ),
|
|
DEFINE_FIELD( m_flExtension, FIELD_FLOAT ),
|
|
DEFINE_FIELD( m_flExtensionRate, FIELD_FLOAT ),
|
|
DEFINE_FIELD( m_bDropping, FIELD_BOOLEAN ),
|
|
//DEFINE_FIELD( m_flNextDangerSoundTime, FIELD_TIME ),
|
|
//DEFINE_FIELD( m_flNextCreakSound, FIELD_TIME ),
|
|
DEFINE_FIELD( m_flNextDropAllowedTime, FIELD_TIME ),
|
|
DEFINE_FIELD( m_flSlowRaiseTime, FIELD_TIME ),
|
|
DEFINE_FIELD( m_flMaxExtensionSpeed, FIELD_FLOAT ),
|
|
DEFINE_FIELD( m_flMaxTurnSpeed, FIELD_FLOAT ),
|
|
DEFINE_FIELD( m_flExtensionAccel, FIELD_FLOAT ),
|
|
DEFINE_FIELD( m_flExtensionDecel, FIELD_FLOAT ),
|
|
DEFINE_FIELD( m_flTurnAccel, FIELD_FLOAT ),
|
|
DEFINE_FIELD( m_flTurnDecel, FIELD_FLOAT ),
|
|
DEFINE_KEYFIELD( m_iszMagnetName, FIELD_STRING, "magnetname" ),
|
|
DEFINE_FIELD( m_hCraneMagnet, FIELD_EHANDLE ),
|
|
DEFINE_FIELD( m_hCraneTip, FIELD_EHANDLE ),
|
|
DEFINE_FIELD( m_hRope, FIELD_EHANDLE ),
|
|
DEFINE_PHYSPTR( m_pConstraintGroup ),
|
|
DEFINE_KEYFIELD( m_vehicleScript, FIELD_STRING, "vehiclescript" ),
|
|
|
|
END_DATADESC()
|
|
|
|
IMPLEMENT_SERVERCLASS_ST(CPropCrane, DT_PropCrane)
|
|
SendPropEHandle(SENDINFO(m_hPlayer)),
|
|
SendPropBool(SENDINFO(m_bMagnetOn)),
|
|
SendPropBool(SENDINFO(m_bEnterAnimOn)),
|
|
SendPropBool(SENDINFO(m_bExitAnimOn)),
|
|
SendPropVector(SENDINFO(m_vecEyeExitEndpoint), -1, SPROP_COORD),
|
|
END_SEND_TABLE();
|
|
|
|
|
|
//------------------------------------------------
|
|
// Precache
|
|
//------------------------------------------------
|
|
void CPropCrane::Precache( void )
|
|
{
|
|
BaseClass::Precache();
|
|
m_ServerVehicle.Initialize( STRING(m_vehicleScript) );
|
|
}
|
|
|
|
|
|
//------------------------------------------------
|
|
// Spawn
|
|
//------------------------------------------------
|
|
void CPropCrane::Spawn( void )
|
|
{
|
|
Precache();
|
|
SetModel( STRING( GetModelName() ) );
|
|
SetCollisionGroup( COLLISION_GROUP_VEHICLE );
|
|
|
|
BaseClass::Spawn();
|
|
|
|
SetSolid( SOLID_BBOX );
|
|
AddSolidFlags( FSOLID_NOT_SOLID );
|
|
SetMoveType( MOVETYPE_NOCLIP );
|
|
|
|
m_takedamage = DAMAGE_EVENTS_ONLY;
|
|
m_flTurn = 0;
|
|
m_flExtension = 0;
|
|
m_flNextDangerSoundTime = 0;
|
|
m_flNextCreakSound = 0;
|
|
m_flNextDropAllowedTime = 0;
|
|
m_flSlowRaiseTime = 0;
|
|
m_bDropping = false;
|
|
m_bMagnetOn = false;
|
|
|
|
InitCraneSpeeds();
|
|
|
|
SetPoseParameter( "armextensionpose", m_flExtension );
|
|
|
|
CreateVPhysics();
|
|
SetNextThink( gpGlobals->curtime );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CPropCrane::Activate( void )
|
|
{
|
|
BaseClass::Activate();
|
|
|
|
// If we load a game, we don't need to set this all up again.
|
|
if ( m_hCraneMagnet )
|
|
return;
|
|
|
|
// Find our magnet
|
|
if ( m_iszMagnetName == NULL_STRING )
|
|
{
|
|
Warning( "prop_vehicle_crane %s has no magnet entity specified!\n", STRING(GetEntityName()) );
|
|
UTIL_Remove( this );
|
|
return;
|
|
}
|
|
|
|
m_hCraneMagnet = dynamic_cast<CPhysMagnet *>(gEntList.FindEntityByName( NULL, STRING(m_iszMagnetName) ));
|
|
if ( !m_hCraneMagnet )
|
|
{
|
|
Warning( "prop_vehicle_crane %s failed to find magnet %s.\n", STRING(GetEntityName()), STRING(m_iszMagnetName) );
|
|
UTIL_Remove( this );
|
|
return;
|
|
}
|
|
|
|
// We want the magnet to cast a long shadow
|
|
m_hCraneMagnet->SetShadowCastDistance( 2048 );
|
|
|
|
// Create our constraint group
|
|
constraint_groupparams_t group;
|
|
group.Defaults();
|
|
m_pConstraintGroup = physenv->CreateConstraintGroup( group );
|
|
m_hCraneMagnet->SetConstraintGroup( m_pConstraintGroup );
|
|
|
|
// Create our crane tip
|
|
Vector vecOrigin;
|
|
QAngle vecAngles;
|
|
GetCraneTipPosition( &vecOrigin, &vecAngles );
|
|
m_hCraneTip = CCraneTip::Create( m_hCraneMagnet, m_pConstraintGroup, vecOrigin, vecAngles );
|
|
if ( !m_hCraneTip )
|
|
{
|
|
UTIL_Remove( this );
|
|
return;
|
|
}
|
|
m_pConstraintGroup->Activate();
|
|
|
|
// Make a rope to connect 'em
|
|
int iIndex = m_hCraneMagnet->LookupAttachment("magnetcable_a");
|
|
m_hRope = CRopeKeyframe::Create( this, m_hCraneMagnet, 1, iIndex );
|
|
if ( m_hRope )
|
|
{
|
|
m_hRope->m_Width = 3;
|
|
m_hRope->m_nSegments = ROPE_MAX_SEGMENTS / 2;
|
|
m_hRope->EnableWind( false );
|
|
m_hRope->SetupHangDistance( 0 );
|
|
m_hRope->m_RopeLength = (m_hCraneMagnet->GetAbsOrigin() - m_hCraneTip->GetAbsOrigin()).Length() * 1.1;
|
|
}
|
|
|
|
// Start with the magnet off
|
|
TurnMagnetOff();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Output : Returns true on success, false on failure.
|
|
//-----------------------------------------------------------------------------
|
|
bool CPropCrane::CreateVPhysics( void )
|
|
{
|
|
BaseClass::CreateVPhysics();
|
|
m_BoneFollowerManager.InitBoneFollowers( this, ARRAYSIZE(pCraneFollowerBoneNames), pCraneFollowerBoneNames );
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CPropCrane::UpdateOnRemove( void )
|
|
{
|
|
m_BoneFollowerManager.DestroyBoneFollowers();
|
|
BaseClass::UpdateOnRemove();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CPropCrane::InitCraneSpeeds( void )
|
|
{
|
|
m_flMaxExtensionSpeed = CRANE_EXTENSION_RATE_MAX * 2;
|
|
m_flMaxTurnSpeed = CRANE_TURN_RATE_MAX * 2;
|
|
m_flExtensionAccel = CRANE_EXTENSION_ACCEL * 2;
|
|
m_flExtensionDecel = CRANE_EXTENSION_DECEL * 2;
|
|
m_flTurnAccel = CRANE_TURN_ACCEL * 2;
|
|
m_flTurnDecel = CRANE_DECEL * 2;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CPropCrane::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator )
|
|
{
|
|
if ( ptr->hitbox == VEHICLE_HITBOX_DRIVER )
|
|
{
|
|
if ( m_hPlayer != NULL )
|
|
{
|
|
m_hPlayer->TakeDamage( info );
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
int CPropCrane::OnTakeDamage( const CTakeDamageInfo &inputInfo )
|
|
{
|
|
//Do scaled up physics damage to the car
|
|
CTakeDamageInfo info = inputInfo;
|
|
info.ScaleDamage( 25 );
|
|
|
|
// reset the damage
|
|
info.SetDamage( inputInfo.GetDamage() );
|
|
|
|
//Check to do damage to driver
|
|
if ( m_hPlayer != NULL )
|
|
{
|
|
//Take no damage from physics damages
|
|
if ( info.GetDamageType() & DMG_CRUSH )
|
|
return 0;
|
|
|
|
//Take the damage
|
|
m_hPlayer->TakeDamage( info );
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
Vector CPropCrane::BodyTarget( const Vector &posSrc, bool bNoisy )
|
|
{
|
|
Vector shotPos;
|
|
matrix3x4_t matrix;
|
|
|
|
int eyeAttachmentIndex = LookupAttachment("vehicle_driver_eyes");
|
|
GetAttachment( eyeAttachmentIndex, matrix );
|
|
MatrixGetColumn( matrix, 3, shotPos );
|
|
|
|
if ( bNoisy )
|
|
{
|
|
shotPos[0] += random->RandomFloat( -8.0f, 8.0f );
|
|
shotPos[1] += random->RandomFloat( -8.0f, 8.0f );
|
|
shotPos[2] += random->RandomFloat( -8.0f, 8.0f );
|
|
}
|
|
|
|
return shotPos;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CPropCrane::Think(void)
|
|
{
|
|
SetNextThink( gpGlobals->curtime + 0.1 );
|
|
|
|
if ( GetDriver() )
|
|
{
|
|
BaseClass::Think();
|
|
|
|
if ( m_hNPCDriver )
|
|
{
|
|
GetServerVehicle()->NPC_DriveVehicle();
|
|
}
|
|
|
|
// play enter animation
|
|
StudioFrameAdvance();
|
|
|
|
// If the enter or exit animation has finished, tell the server vehicle
|
|
if ( IsSequenceFinished() && (m_bExitAnimOn || m_bEnterAnimOn) )
|
|
{
|
|
if ( m_bEnterAnimOn )
|
|
{
|
|
// Finished entering, display the hint for using the crane
|
|
UTIL_HudHintText( m_hPlayer, "#Valve_Hint_CraneKeys" );
|
|
}
|
|
|
|
GetServerVehicle()->HandleEntryExitFinish( m_bExitAnimOn, true );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Run the crane's movement
|
|
RunCraneMovement( 0.1 );
|
|
}
|
|
|
|
// Update follower bones
|
|
m_BoneFollowerManager.UpdateBoneFollowers(this);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : *player -
|
|
//-----------------------------------------------------------------------------
|
|
void CPropCrane::ItemPostFrame( CBasePlayer *player )
|
|
{
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CPropCrane::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
CBasePlayer *pPlayer = ToBasePlayer( pActivator );
|
|
if ( !pPlayer )
|
|
return;
|
|
|
|
ResetUseKey( pPlayer );
|
|
|
|
GetServerVehicle()->HandlePassengerEntry( pPlayer, (value>0) );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Return true of the player's allowed to enter / exit the vehicle
|
|
//-----------------------------------------------------------------------------
|
|
bool CPropCrane::CanEnterVehicle( CBaseEntity *pEntity )
|
|
{
|
|
// Prevent entering if the vehicle's being driven by an NPC
|
|
if ( GetDriver() && GetDriver() != pEntity )
|
|
return false;
|
|
|
|
// Prevent entering if the vehicle's locked
|
|
return ( !m_bLocked );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Return true of the player's allowed to enter / exit the vehicle
|
|
//-----------------------------------------------------------------------------
|
|
bool CPropCrane::CanExitVehicle( CBaseEntity *pEntity )
|
|
{
|
|
// Prevent exiting if the vehicle's locked, or rotating
|
|
// Adrian: Check also if I'm currently jumping in or out.
|
|
return ( !m_bLocked && (GetLocalAngularVelocity() == vec3_angle) && m_bExitAnimOn == false && m_bEnterAnimOn == false );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Override base class to add display
|
|
//-----------------------------------------------------------------------------
|
|
void CPropCrane::DrawDebugGeometryOverlays(void)
|
|
{
|
|
// Draw if BBOX is on
|
|
if ( m_debugOverlays & OVERLAY_BBOX_BIT )
|
|
{
|
|
Vector vecPoint = m_hCraneMagnet->GetAbsOrigin();
|
|
int iIndex = m_hCraneMagnet->LookupAttachment("magnetcable_a");
|
|
if ( iIndex >= 0 )
|
|
{
|
|
m_hCraneMagnet->GetAttachment( iIndex, vecPoint );
|
|
}
|
|
|
|
NDebugOverlay::Line( m_hCraneTip->GetAbsOrigin(), vecPoint, 255,255,255, true, 0.1 );
|
|
}
|
|
|
|
BaseClass::DrawDebugGeometryOverlays();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CPropCrane::EnterVehicle( CBaseCombatCharacter *pPassenger )
|
|
{
|
|
if ( pPassenger == NULL )
|
|
return;
|
|
|
|
CBasePlayer *pPlayer = ToBasePlayer( pPassenger );
|
|
if ( pPlayer != NULL )
|
|
{
|
|
// Remove any player who may be in the vehicle at the moment
|
|
if ( m_hPlayer )
|
|
{
|
|
ExitVehicle( VEHICLE_ROLE_DRIVER );
|
|
}
|
|
|
|
m_hPlayer = pPlayer;
|
|
m_playerOn.FireOutput( pPlayer, this, 0 );
|
|
|
|
m_hPlayer->RumbleEffect( RUMBLE_FLAT_BOTH, 0, RUMBLE_FLAG_LOOP );
|
|
m_hPlayer->RumbleEffect( RUMBLE_FLAT_BOTH, 10, RUMBLE_FLAG_UPDATE_SCALE );
|
|
|
|
m_ServerVehicle.SoundStart();
|
|
}
|
|
else
|
|
{
|
|
// NPCs not yet supported - jdw
|
|
Assert( 0 );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CPropCrane::ExitVehicle( int nRole )
|
|
{
|
|
CBasePlayer *pPlayer = m_hPlayer;
|
|
if ( !pPlayer )
|
|
return;
|
|
|
|
m_hPlayer = NULL;
|
|
ResetUseKey( pPlayer );
|
|
m_playerOff.FireOutput( pPlayer, this, 0 );
|
|
m_bEnterAnimOn = false;
|
|
|
|
m_ServerVehicle.SoundShutdown( 1.0 );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CPropCrane::ResetUseKey( CBasePlayer *pPlayer )
|
|
{
|
|
pPlayer->m_afButtonPressed &= ~IN_USE;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Pass player movement into the crane's driving system
|
|
//-----------------------------------------------------------------------------
|
|
void CPropCrane::SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move )
|
|
{
|
|
// If the player's entering/exiting the vehicle, prevent movement
|
|
if ( !m_bEnterAnimOn && !m_bExitAnimOn )
|
|
{
|
|
int buttons = ucmd->buttons;
|
|
if ( !(buttons & (IN_MOVELEFT|IN_MOVERIGHT)) )
|
|
{
|
|
if ( ucmd->sidemove < 0 )
|
|
{
|
|
buttons |= IN_MOVELEFT;
|
|
}
|
|
else if ( ucmd->sidemove > 0 )
|
|
{
|
|
buttons |= IN_MOVERIGHT;
|
|
}
|
|
}
|
|
DriveCrane( buttons, player->m_afButtonPressed );
|
|
}
|
|
|
|
// Run the crane's movement
|
|
RunCraneMovement( gpGlobals->frametime );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Crane rotates around with +left and +right, and extends/retracts
|
|
// the cable with +forward and +back.
|
|
//-----------------------------------------------------------------------------
|
|
void CPropCrane::DriveCrane( int iDriverButtons, int iButtonsPressed, float flNPCSteering )
|
|
{
|
|
bool bWasExtending = m_bExtending;
|
|
|
|
// Handle rotation of the crane
|
|
if ( iDriverButtons & IN_MOVELEFT )
|
|
{
|
|
// NPCs may cheat and set the steering
|
|
if ( flNPCSteering )
|
|
{
|
|
m_flTurn = flNPCSteering;
|
|
}
|
|
else
|
|
{
|
|
// Try adding some randomness to make it feel shaky?
|
|
float flTurnAdd = m_flTurnAccel;
|
|
// If we're turning back on ourselves, use decel speed
|
|
if ( m_flTurn < 0 )
|
|
{
|
|
flTurnAdd = MAX( flTurnAdd, m_flTurnDecel );
|
|
}
|
|
|
|
m_flTurn = UTIL_Approach( m_flMaxTurnSpeed, m_flTurn, flTurnAdd * gpGlobals->frametime );
|
|
}
|
|
m_iTurning = TURNING_LEFT;
|
|
}
|
|
else if ( iDriverButtons & IN_MOVERIGHT )
|
|
{
|
|
// NPCs may cheat and set the steering
|
|
if ( flNPCSteering )
|
|
{
|
|
m_flTurn = flNPCSteering;
|
|
}
|
|
else
|
|
{
|
|
// Try adding some randomness to make it feel shaky?
|
|
float flTurnAdd = m_flTurnAccel;
|
|
// If we're turning back on ourselves, increase the rate
|
|
if ( m_flTurn > 0 )
|
|
{
|
|
flTurnAdd = MAX( flTurnAdd, m_flTurnDecel );
|
|
}
|
|
m_flTurn = UTIL_Approach( -m_flMaxTurnSpeed, m_flTurn, flTurnAdd * gpGlobals->frametime );
|
|
}
|
|
m_iTurning = TURNING_RIGHT;
|
|
}
|
|
else
|
|
{
|
|
m_flTurn = UTIL_Approach( 0, m_flTurn, m_flTurnDecel * gpGlobals->frametime );
|
|
m_iTurning = TURNING_NOT;
|
|
}
|
|
|
|
if ( m_hPlayer )
|
|
{
|
|
float maxTurn = GetMaxTurnRate();
|
|
static float maxRumble = 0.35f;
|
|
static float minRumble = 0.1f;
|
|
float rumbleRange = maxRumble - minRumble;
|
|
float rumble;
|
|
|
|
float factor = fabs(m_flTurn) / maxTurn;
|
|
factor = MIN( factor, 1.0f );
|
|
rumble = minRumble + (rumbleRange * factor);
|
|
|
|
m_hPlayer->RumbleEffect( RUMBLE_FLAT_BOTH, (int)(rumble * 100), RUMBLE_FLAG_UPDATE_SCALE );
|
|
}
|
|
|
|
SetLocalAngularVelocity( QAngle(0,m_flTurn * 10,0) );
|
|
|
|
// Handle extension / retraction of the arm
|
|
if ( iDriverButtons & IN_FORWARD )
|
|
{
|
|
m_flExtensionRate = UTIL_Approach( m_flMaxExtensionSpeed, m_flExtensionRate, m_flExtensionAccel * gpGlobals->frametime );
|
|
m_bExtending = true;
|
|
}
|
|
else if ( iDriverButtons & IN_BACK )
|
|
{
|
|
m_flExtensionRate = UTIL_Approach( -m_flMaxExtensionSpeed, m_flExtensionRate, m_flExtensionAccel * gpGlobals->frametime );
|
|
m_bExtending = true;
|
|
}
|
|
else
|
|
{
|
|
m_flExtensionRate = UTIL_Approach( 0, m_flExtensionRate, m_flExtensionDecel * gpGlobals->frametime );
|
|
m_bExtending = false;
|
|
}
|
|
|
|
//Msg("Turn: %f\nExtensionRate: %f\n", m_flTurn, m_flExtensionRate );
|
|
|
|
//If we're holding down an attack button, update our state
|
|
if ( iButtonsPressed & (IN_ATTACK | IN_ATTACK2) )
|
|
{
|
|
// If we have something on the magnet, turn the magnet off
|
|
if ( m_hCraneMagnet->GetTotalMassAttachedObjects() )
|
|
{
|
|
TurnMagnetOff();
|
|
}
|
|
else if ( !m_bDropping && m_flNextDropAllowedTime < gpGlobals->curtime )
|
|
{
|
|
TurnMagnetOn();
|
|
|
|
// Drop the magnet till it hits something
|
|
m_bDropping = true;
|
|
m_hCraneMagnet->ResetHasHitSomething();
|
|
m_hCraneTip->m_pSpring->SetSpringConstant( CRANE_SPRING_CONSTANT_LOWERING );
|
|
|
|
m_ServerVehicle.PlaySound( VS_MISC1 );
|
|
}
|
|
}
|
|
|
|
float flSpeedPercentage = clamp( fabs(m_flTurn) / m_flMaxTurnSpeed, 0, 1 );
|
|
vbs_sound_update_t params;
|
|
params.Defaults();
|
|
params.bThrottleDown = (m_iTurning != TURNING_NOT);
|
|
params.flCurrentSpeedFraction = flSpeedPercentage;
|
|
params.flWorldSpaceSpeed = 0;
|
|
|
|
m_ServerVehicle.SoundUpdate( params );
|
|
|
|
// Play sounds for arm extension / retraction
|
|
if ( m_bExtending && !bWasExtending )
|
|
{
|
|
m_ServerVehicle.StopSound( VS_ENGINE2_STOP );
|
|
m_ServerVehicle.PlaySound( VS_ENGINE2_START );
|
|
}
|
|
else if ( !m_bExtending && bWasExtending )
|
|
{
|
|
m_ServerVehicle.StopSound( VS_ENGINE2_START );
|
|
m_ServerVehicle.PlaySound( VS_ENGINE2_STOP );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CPropCrane::RecalculateCraneTip( void )
|
|
{
|
|
Vector vecOrigin;
|
|
QAngle vecAngles;
|
|
GetCraneTipPosition( &vecOrigin, &vecAngles );
|
|
m_hCraneTip->SetAbsOrigin( vecOrigin );
|
|
|
|
// NOTE: We need to do this because we're not using Physics...
|
|
if ( m_hCraneTip->VPhysicsGetObject() )
|
|
{
|
|
m_hCraneTip->VPhysicsGetObject()->UpdateShadow( vecOrigin, vec3_angle, true, TICK_INTERVAL * 2.0f );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : *pPlayer -
|
|
// *pMoveData -
|
|
//-----------------------------------------------------------------------------
|
|
void CPropCrane::RunCraneMovement( float flTime )
|
|
{
|
|
if ( m_flExtensionRate )
|
|
{
|
|
// Extend / Retract the crane
|
|
m_flExtension = clamp( m_flExtension + (m_flExtensionRate * 10 * flTime), 0, 2 );
|
|
SetPoseParameter( "armextensionpose", m_flExtension );
|
|
StudioFrameAdvance();
|
|
}
|
|
|
|
// Drop the magnet until it hits the ground
|
|
if ( m_bDropping )
|
|
{
|
|
// Drop until the magnet hits something
|
|
if ( m_hCraneMagnet->HasHitSomething() )
|
|
{
|
|
// We hit the ground, stop dropping
|
|
m_hCraneTip->m_pSpring->SetSpringConstant( CRANE_SPRING_CONSTANT_INITIAL_RAISING );
|
|
m_bDropping = false;
|
|
m_flNextDropAllowedTime = gpGlobals->curtime + 3.0;
|
|
m_flSlowRaiseTime = gpGlobals->curtime;
|
|
|
|
m_ServerVehicle.PlaySound( VS_MISC2 );
|
|
}
|
|
}
|
|
else if ( (m_flSlowRaiseTime + CRANE_SLOWRAISE_TIME) > gpGlobals->curtime )
|
|
{
|
|
float flDelta = (gpGlobals->curtime - m_flSlowRaiseTime);
|
|
|
|
flDelta = clamp( flDelta, 0, CRANE_SLOWRAISE_TIME );
|
|
float flCurrentSpringConstant = RemapVal( flDelta, 0, CRANE_SLOWRAISE_TIME, CRANE_SPRING_CONSTANT_INITIAL_RAISING, CRANE_SPRING_CONSTANT_HANGING );
|
|
m_hCraneTip->m_pSpring->SetSpringConstant( flCurrentSpringConstant );
|
|
}
|
|
|
|
// If we've moved in any way, update the tip
|
|
if ( m_bDropping || m_flExtensionRate || GetLocalAngularVelocity() != vec3_angle )
|
|
{
|
|
RecalculateCraneTip();
|
|
}
|
|
|
|
// Make danger sounds underneath the magnet if we have something attached to it
|
|
/*
|
|
if ( (m_flNextDangerSoundTime < gpGlobals->curtime) && (m_hCraneMagnet->GetTotalMassAttachedObjects() > 0) )
|
|
{
|
|
// Trace down from the magnet and make a danger sound on the ground
|
|
trace_t tr;
|
|
Vector vecSource = m_hCraneMagnet->GetAbsOrigin();
|
|
UTIL_TraceLine( vecSource, vecSource - Vector(0,0,2048), MASK_SOLID_BRUSHONLY, m_hCraneMagnet, 0, &tr );
|
|
|
|
if ( tr.fraction < 1.0 )
|
|
{
|
|
// Make the volume proportional to the amount of mass on the magnet
|
|
float flVolume = clamp( (m_hCraneMagnet->GetTotalMassAttachedObjects() * 0.5), 100.f, 600.f );
|
|
CSoundEnt::InsertSound( SOUND_DANGER, tr.endpos, flVolume, 0.2, this );
|
|
|
|
//Msg("Total: %.2f Volume: %.2f\n", m_hCraneMagnet->GetTotalMassAttachedObjects(), flVolume );
|
|
//Vector vecVolume = Vector(flVolume,flVolume,flVolume) * 0.5;
|
|
//NDebugOverlay::Box( tr.endpos, -vecVolume, vecVolume, 255,0,0, false, 0.3 );
|
|
//NDebugOverlay::Cross3D( tr.endpos, -Vector(10,10,10), Vector(10,10,10), 255,0,0, false, 0.3 );
|
|
}
|
|
|
|
m_flNextDangerSoundTime = gpGlobals->curtime + 0.3;
|
|
}
|
|
*/
|
|
|
|
// Play creak sounds on the magnet if there's heavy weight on it
|
|
if ( (m_flNextCreakSound < gpGlobals->curtime) && (m_hCraneMagnet->GetTotalMassAttachedObjects() > 100) )
|
|
{
|
|
// Randomly play creaks from the magnet, and increase the chance based on the turning speed
|
|
float flSpeedPercentage = clamp( fabs(m_flTurn) / m_flMaxTurnSpeed, 0, 1 );
|
|
if ( RandomFloat(0,1) > (0.95 - (0.1 * flSpeedPercentage)) )
|
|
{
|
|
if ( m_ServerVehicle.m_vehicleSounds.iszSound[VS_MISC4] != NULL_STRING )
|
|
{
|
|
CPASAttenuationFilter filter( m_hCraneMagnet );
|
|
|
|
EmitSound_t ep;
|
|
ep.m_nChannel = CHAN_VOICE;
|
|
ep.m_pSoundName = STRING(m_ServerVehicle.m_vehicleSounds.iszSound[VS_MISC4]);
|
|
ep.m_flVolume = 1.0f;
|
|
ep.m_SoundLevel = SNDLVL_NORM;
|
|
|
|
CBaseEntity::EmitSound( filter, m_hCraneMagnet->entindex(), ep );
|
|
}
|
|
m_flNextCreakSound = gpGlobals->curtime + 5.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CPropCrane::TurnMagnetOn( void )
|
|
{
|
|
if ( !m_hCraneMagnet->IsOn() )
|
|
{
|
|
variant_t emptyVariant;
|
|
m_hCraneMagnet->AcceptInput( "Toggle", this, this, emptyVariant, USE_TOGGLE );
|
|
m_ServerVehicle.PlaySound( VS_MISC3 );
|
|
|
|
m_bMagnetOn = true;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CPropCrane::TurnMagnetOff( void )
|
|
{
|
|
if ( m_hCraneMagnet->IsOn() )
|
|
{
|
|
variant_t emptyVariant;
|
|
m_hCraneMagnet->AcceptInput( "Toggle", this, this, emptyVariant, USE_TOGGLE );
|
|
m_ServerVehicle.PlaySound( VS_MISC3 );
|
|
|
|
m_bMagnetOn = false;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
const Vector &CPropCrane::GetCraneTipPosition( void )
|
|
{
|
|
return m_hCraneTip->GetAbsOrigin();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Fills out the values with the desired position of the crane's tip
|
|
//-----------------------------------------------------------------------------
|
|
void CPropCrane::GetCraneTipPosition( Vector *vecOrigin, QAngle *vecAngles )
|
|
{
|
|
GetAttachment( "cable_tip", *vecOrigin, *vecAngles );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Vehicles are permanently oriented off angle for vphysics.
|
|
//-----------------------------------------------------------------------------
|
|
void CPropCrane::GetVectors(Vector* pForward, Vector* pRight, Vector* pUp) const
|
|
{
|
|
// This call is necessary to cause m_rgflCoordinateFrame to be recomputed
|
|
const matrix3x4_t &entityToWorld = EntityToWorldTransform();
|
|
|
|
if (pForward != NULL)
|
|
{
|
|
MatrixGetColumn( entityToWorld, 1, *pForward );
|
|
}
|
|
|
|
if (pRight != NULL)
|
|
{
|
|
MatrixGetColumn( entityToWorld, 0, *pRight );
|
|
}
|
|
|
|
if (pUp != NULL)
|
|
{
|
|
MatrixGetColumn( entityToWorld, 2, *pUp );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
CBaseEntity *CPropCrane::GetDriver( void )
|
|
{
|
|
if ( m_hNPCDriver )
|
|
return m_hNPCDriver;
|
|
|
|
return m_hPlayer;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Prevent the player from entering / exiting the vehicle
|
|
//-----------------------------------------------------------------------------
|
|
void CPropCrane::InputLock( inputdata_t &inputdata )
|
|
{
|
|
m_bLocked = true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Allow the player to enter / exit the vehicle
|
|
//-----------------------------------------------------------------------------
|
|
void CPropCrane::InputUnlock( inputdata_t &inputdata )
|
|
{
|
|
m_bLocked = false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : &inputdata -
|
|
//-----------------------------------------------------------------------------
|
|
void CPropCrane::InputForcePlayerIn( inputdata_t &inputdata )
|
|
{
|
|
CBasePlayer *pPlayer = UTIL_PlayerByIndex( 1 );
|
|
if ( pPlayer && !m_hPlayer )
|
|
{
|
|
GetServerVehicle()->HandlePassengerEntry( pPlayer, 0 );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CPropCrane::SetNPCDriver( CNPC_VehicleDriver *pDriver )
|
|
{
|
|
m_hNPCDriver = pDriver;
|
|
m_nNPCButtons = 0;
|
|
|
|
if ( pDriver )
|
|
{
|
|
m_flMaxExtensionSpeed = CRANE_EXTENSION_RATE_MAX * 1.5;
|
|
m_flMaxTurnSpeed = CRANE_TURN_RATE_MAX * 1.5;
|
|
m_flExtensionAccel = CRANE_EXTENSION_ACCEL * 2;
|
|
m_flExtensionDecel = CRANE_EXTENSION_DECEL * 20; // Npcs stop quickly to make them more accurate
|
|
m_flTurnAccel = CRANE_TURN_ACCEL * 2;
|
|
m_flTurnDecel = CRANE_DECEL * 10; // Npcs stop quickly to make them more accurate
|
|
|
|
// Set our owner entity to be the NPC, so it can path check without hitting us
|
|
SetOwnerEntity( pDriver );
|
|
}
|
|
else
|
|
{
|
|
// Restore player crane speeds
|
|
InitCraneSpeeds();
|
|
SetOwnerEntity( NULL );
|
|
|
|
// Shutdown the crane's sounds
|
|
m_ServerVehicle.SoundShutdown( 1.0 );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Allows us to turn off the rumble
|
|
//-----------------------------------------------------------------------------
|
|
void CPropCrane::PreExitVehicle( CBaseCombatCharacter *pPlayer, int nRole )
|
|
{
|
|
if ( pPlayer != m_hPlayer )
|
|
return;
|
|
|
|
if ( m_hPlayer != NULL )
|
|
{
|
|
// Stop rumbles
|
|
m_hPlayer->RumbleEffect( RUMBLE_FLAT_BOTH, 0, RUMBLE_FLAG_STOP );
|
|
}
|
|
}
|
|
|
|
//========================================================================================================================================
|
|
// CRANE VEHICLE SERVER VEHICLE
|
|
//========================================================================================================================================
|
|
CPropCrane *CCraneServerVehicle::GetCrane( void )
|
|
{
|
|
return (CPropCrane*)GetDrivableVehicle();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CCraneServerVehicle::GetVehicleViewPosition( int nRole, Vector *pAbsOrigin, QAngle *pAbsAngles, float *pFOV /*= NULL*/ )
|
|
{
|
|
// FIXME: This needs to be reconciled with the other versions of this function!
|
|
Assert( nRole == VEHICLE_ROLE_DRIVER );
|
|
CBasePlayer *pPlayer = ToBasePlayer( GetDrivableVehicle()->GetDriver() );
|
|
Assert( pPlayer );
|
|
|
|
*pAbsAngles = pPlayer->EyeAngles(); // yuck. this is an in/out parameter.
|
|
|
|
float flPitchFactor = 1.0;
|
|
matrix3x4_t vehicleEyePosToWorld;
|
|
Vector vehicleEyeOrigin;
|
|
QAngle vehicleEyeAngles;
|
|
GetCrane()->GetAttachment( "vehicle_driver_eyes", vehicleEyeOrigin, vehicleEyeAngles );
|
|
AngleMatrix( vehicleEyeAngles, vehicleEyePosToWorld );
|
|
|
|
// Compute the relative rotation between the unperterbed eye attachment + the eye angles
|
|
matrix3x4_t cameraToWorld;
|
|
AngleMatrix( *pAbsAngles, cameraToWorld );
|
|
|
|
matrix3x4_t worldToEyePos;
|
|
MatrixInvert( vehicleEyePosToWorld, worldToEyePos );
|
|
|
|
matrix3x4_t vehicleCameraToEyePos;
|
|
ConcatTransforms( worldToEyePos, cameraToWorld, vehicleCameraToEyePos );
|
|
|
|
// Now perterb the attachment point
|
|
vehicleEyeAngles.x = RemapAngleRange( PITCH_CURVE_ZERO * flPitchFactor, PITCH_CURVE_LINEAR, vehicleEyeAngles.x );
|
|
vehicleEyeAngles.z = RemapAngleRange( ROLL_CURVE_ZERO * flPitchFactor, ROLL_CURVE_LINEAR, vehicleEyeAngles.z );
|
|
AngleMatrix( vehicleEyeAngles, vehicleEyeOrigin, vehicleEyePosToWorld );
|
|
|
|
// Now treat the relative eye angles as being relative to this new, perterbed view position...
|
|
matrix3x4_t newCameraToWorld;
|
|
ConcatTransforms( vehicleEyePosToWorld, vehicleCameraToEyePos, newCameraToWorld );
|
|
|
|
// output new view abs angles
|
|
MatrixAngles( newCameraToWorld, *pAbsAngles );
|
|
|
|
// UNDONE: *pOrigin would already be correct in single player if the HandleView() on the server ran after vphysics
|
|
MatrixGetColumn( newCameraToWorld, 3, *pAbsOrigin );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CCraneServerVehicle::NPC_SetDriver( CNPC_VehicleDriver *pDriver )
|
|
{
|
|
GetCrane()->SetNPCDriver( pDriver );
|
|
|
|
if ( pDriver )
|
|
{
|
|
SetVehicleVolume( 1.0 ); // Vehicles driven by NPCs are louder
|
|
GetCrane()->SetSimulatedEveryTick( false );
|
|
}
|
|
else
|
|
{
|
|
SetVehicleVolume( 0.5 );
|
|
GetCrane()->SetSimulatedEveryTick( true );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CCraneServerVehicle::NPC_DriveVehicle( void )
|
|
{
|
|
if ( g_debug_vehicledriver.GetInt() )
|
|
{
|
|
if ( m_nNPCButtons )
|
|
{
|
|
Vector vecForward, vecRight;
|
|
GetCrane()->GetVectors( &vecForward, &vecRight, NULL );
|
|
if ( m_nNPCButtons & IN_FORWARD )
|
|
{
|
|
NDebugOverlay::Line( GetCrane()->GetAbsOrigin(), GetCrane()->GetAbsOrigin() + vecForward * 200, 0,255,0, true, 0.1 );
|
|
}
|
|
if ( m_nNPCButtons & IN_BACK )
|
|
{
|
|
NDebugOverlay::Line( GetCrane()->GetAbsOrigin(), GetCrane()->GetAbsOrigin() - vecForward * 200, 0,255,0, true, 0.1 );
|
|
}
|
|
if ( m_nNPCButtons & IN_MOVELEFT )
|
|
{
|
|
NDebugOverlay::Line( GetCrane()->GetAbsOrigin(), GetCrane()->GetAbsOrigin() - vecRight * 200, 0,255,0, true, 0.1 );
|
|
}
|
|
if ( m_nNPCButtons & IN_MOVERIGHT )
|
|
{
|
|
NDebugOverlay::Line( GetCrane()->GetAbsOrigin(), GetCrane()->GetAbsOrigin() + vecRight * 200, 0,255,0, true, 0.1 );
|
|
}
|
|
if ( m_nNPCButtons & IN_JUMP )
|
|
{
|
|
NDebugOverlay::Box( GetCrane()->GetAbsOrigin(), -Vector(20,20,20), Vector(20,20,20), 0,255,0, true, 0.1 );
|
|
}
|
|
}
|
|
}
|
|
|
|
GetCrane()->DriveCrane( m_nNPCButtons, m_nNPCButtons, m_flTurnDegrees );
|
|
|
|
// Clear out attack buttons each frame
|
|
m_nNPCButtons &= ~IN_ATTACK;
|
|
m_nNPCButtons &= ~IN_ATTACK2;
|
|
|
|
// Run the crane's movement
|
|
GetCrane()->RunCraneMovement( 0.1 );
|
|
}
|
|
|
|
//===============================================================================================================================
|
|
// CRANE CABLE TIP
|
|
//===============================================================================================================================
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: To by usable by the constraint system, this needs to have a phys model.
|
|
//-----------------------------------------------------------------------------
|
|
void CCraneTip::Spawn( void )
|
|
{
|
|
Precache();
|
|
SetModel( "models/props_junk/cardboard_box001a.mdl" );
|
|
AddEffects( EF_NODRAW );
|
|
|
|
// We don't want this to be solid, because we don't want it to collide with the hydra.
|
|
SetSolid( SOLID_VPHYSICS );
|
|
AddSolidFlags( FSOLID_NOT_SOLID );
|
|
VPhysicsInitShadow( false, false );
|
|
|
|
// Disable movement on this sucker, we're going to move him manually
|
|
SetMoveType( MOVETYPE_NONE );
|
|
|
|
BaseClass::Spawn();
|
|
|
|
m_pSpring = NULL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CCraneTip::Precache( void )
|
|
{
|
|
PrecacheModel( "models/props_junk/cardboard_box001a.mdl" );
|
|
BaseClass::Precache();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Activate/create the constraint
|
|
//-----------------------------------------------------------------------------
|
|
bool CCraneTip::CreateConstraint( CBaseAnimating *pCraneMagnet, IPhysicsConstraintGroup *pGroup )
|
|
{
|
|
IPhysicsObject *pPhysObject = VPhysicsGetObject();
|
|
IPhysicsObject *pCraneMagnetPhysObject = pCraneMagnet->VPhysicsGetObject();
|
|
if ( !pCraneMagnetPhysObject )
|
|
{
|
|
Msg(" Error: Tried to create a crane_tip with a crane magnet that has no physics model.\n" );
|
|
return false;
|
|
}
|
|
Assert( pPhysObject );
|
|
|
|
// Check to see if it's got an attachment point to connect to
|
|
Vector vecPoint = pCraneMagnet->GetAbsOrigin();
|
|
int iIndex = pCraneMagnet->LookupAttachment("magnetcable_a");
|
|
if ( iIndex >= 0 )
|
|
{
|
|
pCraneMagnet->GetAttachment( iIndex, vecPoint );
|
|
}
|
|
|
|
// Create our spring
|
|
/*
|
|
constraint_lengthparams_t length;
|
|
length.Defaults();
|
|
length.InitWorldspace( pPhysObject, pCraneMagnetPhysObject, GetAbsOrigin(), vecPoint );
|
|
length.constraint.Defaults();
|
|
m_pConstraint = physenv->CreateLengthConstraint( pPhysObject, pCraneMagnetPhysObject, pGroup, length );
|
|
*/
|
|
|
|
springparams_t spring;
|
|
spring.constant = CRANE_SPRING_CONSTANT_HANGING;
|
|
spring.damping = CRANE_SPRING_DAMPING;
|
|
spring.naturalLength = (GetAbsOrigin() - vecPoint).Length();
|
|
spring.relativeDamping = CRANE_SPRING_RELATIVE_DAMPING;
|
|
spring.startPosition = GetAbsOrigin();
|
|
spring.endPosition = vecPoint;
|
|
spring.useLocalPositions = false;
|
|
spring.onlyStretch = true;
|
|
m_pSpring = physenv->CreateSpring( pPhysObject, pCraneMagnetPhysObject, &spring );
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Create a Hydra Impale between the hydra and the entity passed in
|
|
//-----------------------------------------------------------------------------
|
|
CCraneTip *CCraneTip::Create( CBaseAnimating *pCraneMagnet, IPhysicsConstraintGroup *pGroup, const Vector &vecOrigin, const QAngle &vecAngles )
|
|
{
|
|
CCraneTip *pCraneTip = (CCraneTip *)CBaseEntity::Create( "crane_tip", vecOrigin, vecAngles );
|
|
if ( !pCraneTip )
|
|
return NULL;
|
|
|
|
if ( !pCraneTip->CreateConstraint( pCraneMagnet, pGroup ) )
|
|
return NULL;
|
|
|
|
return pCraneTip;
|
|
}
|
|
|