//----------------------------------------------------------------------------- // Copyright(c), HL Rally: Source, 2004, All rights reserved. // The contents of this file may only be used / distributed in accordance // with the conditions listed in the supplied license, or with written // permission of the respective authors listed. // // Based off fourwheelvehiclephysics.cpp from sourcesdk // // Shared vehicle physics // No longer just used as a battering ram ;) //----------------------------------------------------------------------------- #include "cbase.h" #include "VehiclePhysics.h" #include "engine/IEngineSound.h" #include "soundenvelope.h" #include "vcollide_parse.h" #include "in_buttons.h" #include "IEffects.h" #include "physics_saverestore.h" #include "isaverestore.h" #include "movevars_shared.h" #include "studio.h" #include "debugoverlay_shared.h" #include "effect_dispatch_data.h" #ifdef CLIENT_DLL # include "HLRally2/c_EntityPropVehicle.h" #else # include "EntityPropVehicle.h" #endif // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" #define REAR_AXLE 1 // indexes of axlex #define FRONT_AXLE 0 #define MAX_GUAGE_SPEED 100.0 // 100 mph is max speed shown on guage #define BRAKE_MAX_VALUE 1.0f #define BRAKE_BACK_FORWARD_SCALAR 2.0f #define FRAMETIME_RELATIVE gpGlobals->frametime * 66.666666666667 #define ACCEL_RATE_RELATIVE 10.0f * gpGlobals->frametime #define STEER_RATE_RELATIVE 10.0f * gpGlobals->frametime #ifdef CLIENT_DLL ConVar r_vehicleDrawDebug( "rally_vehicle_debug_client", "0", FCVAR_CHEAT ); #else ConVar r_vehicleDrawDebug( "rally_vehicle_debug_server", "0", FCVAR_CHEAT ); #endif ConVar r_vehicleBrakeRate( "r_vehicleBrakeRate", "1.5", FCVAR_CHEAT ); //----------------------------------------------------------------------------- // Writes a DevMsg() stating which DLL it came from //----------------------------------------------------------------------------- void DevMsgShared(const char *szMessage, ...) { #ifdef CLIENT_DLL DevMsg("Client: "); #else DevMsg("Server: "); #endif va_list marker; char msg[256]; va_start(marker, szMessage); Q_vsnprintf(msg, sizeof(msg), szMessage, marker); va_end(marker); DevMsg(msg); } // remaps an angular variable to a 3 band function: // 0 <= t < start : f(t) = 0 // start <= t <= end : f(t) = end * spline(( t-start) / (end-start) ) // s curve between clamped and linear // end < t : f(t) = t float RemapAngleRange( float startInterval, float endInterval, float value ) { // Fixup the roll value = AngleNormalize( value ); float absAngle = fabs(value); // beneath cutoff? if ( absAngle < startInterval ) { value = 0; } // in spline range? else if ( absAngle <= endInterval ) { float newAngle = SimpleSpline( (absAngle - startInterval) / (endInterval-startInterval) ) * endInterval; // grab the sign from the initial value if ( value < 0 ) { newAngle *= -1; } value = newAngle; } // else leave it alone, in linear range return value; } enum vehicle_pose_params { VEH_FL_WHEEL_HEIGHT=0, VEH_FR_WHEEL_HEIGHT, VEH_RL_WHEEL_HEIGHT, VEH_RR_WHEEL_HEIGHT, VEH_FL_WHEEL_SPIN, VEH_FR_WHEEL_SPIN, VEH_RL_WHEEL_SPIN, VEH_RR_WHEEL_SPIN, VEH_STEER, VEH_ACTION, VEH_SPEEDO, }; //----------------------------------------------------------------------------- // Constructor //----------------------------------------------------------------------------- CVehiclePhysics::CVehiclePhysics( CBaseAnimating *pOuter ) { m_flVehicleVolume = 0.5; m_pOuter = NULL; m_flMaxSpeed = 30; m_flThrottleReduction = 0; } //----------------------------------------------------------------------------- // Destructor //----------------------------------------------------------------------------- CVehiclePhysics::~CVehiclePhysics () { physenv->DestroyVehicleController( m_pVehicle ); } //----------------------------------------------------------------------------- // A couple wrapper methods to perform common operations //----------------------------------------------------------------------------- inline int CVehiclePhysics::LookupPoseParameter( const char *szName ) { return m_pOuter->LookupPoseParameter( szName ); } inline float CVehiclePhysics::GetPoseParameter( int iParameter ) { Assert(!"No longer used"); } inline float CVehiclePhysics::SetPoseParameter( int iParameter, float flValue ) { //#ifdef CLIENT_DLL return m_pOuter->SetPoseParameter( iParameter, flValue ); //#else //if(flValue == 0 || flValue == 1) // return m_pOuter->SetPoseParameter( iParameter, flValue ); return 0; //#endif } inline bool CVehiclePhysics::GetAttachment( const char *szName, Vector &origin, QAngle &angles ) { #ifdef CLIENT_DLL return m_pOuter->GetAttachment(m_pOuter->LookupAttachment(szName), origin, angles); #else return m_pOuter->GetAttachment(szName, origin, angles); #endif } inline void CVehiclePhysics::InvalidateBoneCache() { // #ifdef CLIENT_DLL m_pOuter->InvalidateBoneCache(); // #endif } //----------------------------------------------------------------------------- // Methods related to spawn //----------------------------------------------------------------------------- void CVehiclePhysics::InitializePoseParameters() { m_poseParameters[VEH_FL_WHEEL_HEIGHT] = LookupPoseParameter( "vehicle_wheel_fl_height" ); m_poseParameters[VEH_FR_WHEEL_HEIGHT] = LookupPoseParameter( "vehicle_wheel_fr_height" ); m_poseParameters[VEH_RL_WHEEL_HEIGHT] = LookupPoseParameter( "vehicle_wheel_rl_height" ); m_poseParameters[VEH_RR_WHEEL_HEIGHT] = LookupPoseParameter( "vehicle_wheel_rr_height" ); m_poseParameters[VEH_FL_WHEEL_SPIN] = LookupPoseParameter( "vehicle_wheel_fl_spin" ); m_poseParameters[VEH_FR_WHEEL_SPIN] = LookupPoseParameter( "vehicle_wheel_fr_spin" ); m_poseParameters[VEH_RL_WHEEL_SPIN] = LookupPoseParameter( "vehicle_wheel_rl_spin" ); m_poseParameters[VEH_RR_WHEEL_SPIN] = LookupPoseParameter( "vehicle_wheel_rr_spin" ); m_poseParameters[VEH_STEER] = LookupPoseParameter( "vehicle_steer" ); m_poseParameters[VEH_ACTION] = LookupPoseParameter( "vehicle_action" ); m_poseParameters[VEH_SPEEDO] = LookupPoseParameter( "vehicle_guage" ); // move the wheels to a neutral position SetPoseParameter( m_poseParameters[VEH_SPEEDO], 0 ); SetPoseParameter( m_poseParameters[VEH_STEER], 0 ); SetPoseParameter( m_poseParameters[VEH_FL_WHEEL_HEIGHT], 0 ); SetPoseParameter( m_poseParameters[VEH_FR_WHEEL_HEIGHT], 0 ); SetPoseParameter( m_poseParameters[VEH_RL_WHEEL_HEIGHT], 0 ); SetPoseParameter( m_poseParameters[VEH_RR_WHEEL_HEIGHT], 0 ); InvalidateBoneCache(); } //----------------------------------------------------------------------------- // Purpose: Parses the vehicle's script //----------------------------------------------------------------------------- bool CVehiclePhysics::ParseVehicleScript( const char *pScriptName, solid_t &solid, vehicleparams_t &vehicle) { DevMsgShared("****************************************************************************\n"); DevMsgShared(pScriptName); DevMsgShared("\n****************************************************************************\n"); byte *pFile = UTIL_LoadFileForMe( "models/buggy/buggy.txt", NULL ); // @todo : remake this pScriptName - but only when they are equal cl-sv if ( !pFile ) { assert(!"Could not load vehicle file."); return false; } IVPhysicsKeyParser *pParse = physcollision->VPhysicsKeyParserCreate( (char *)pFile ); while ( !pParse->Finished() ) { const char *pBlock = pParse->GetCurrentBlockName(); if ( !strcmpi( pBlock, "vehicle" ) ) { pParse->ParseVehicle( &vehicle, NULL ); } else { pParse->SkipBlock(); } } physcollision->VPhysicsKeyParserDestroy( pParse ); UTIL_FreeFile( pFile ); m_debugRadius = vehicle.axles[0].wheels.radius; CalcWheelData( vehicle ); PhysModelParseSolid( solid, m_pOuter, m_pOuter->GetModelIndex() ); // Allow the script to shift the center of mass if ( vehicle.body.massCenterOverride != vec3_origin ) { solid.massCenterOverride = vehicle.body.massCenterOverride; solid.params.massCenterOverride = &solid.massCenterOverride; } // allow script to change the mass of the vehicle body if ( vehicle.body.massOverride > 0 ) { solid.params.mass = vehicle.body.massOverride; } return true; } void CVehiclePhysics::CalcWheelData( vehicleparams_t &vehicle ) { Vector left, right; QAngle dummy; SetPoseParameter( m_poseParameters[VEH_FL_WHEEL_HEIGHT], 0 ); SetPoseParameter( m_poseParameters[VEH_FR_WHEEL_HEIGHT], 0 ); SetPoseParameter( m_poseParameters[VEH_RL_WHEEL_HEIGHT], 0 ); SetPoseParameter( m_poseParameters[VEH_RR_WHEEL_HEIGHT], 0 ); InvalidateBoneCache(); if ( GetAttachment( "wheel_fl", left, dummy ) && GetAttachment( "wheel_fr", right, dummy ) ) { VectorITransform( left, m_pOuter->EntityToWorldTransform(), left ); VectorITransform( right, m_pOuter->EntityToWorldTransform(), right ); Vector center = (left + right) * 0.5; vehicle.axles[0].offset = center; vehicle.axles[0].wheelOffset = right - center; // Cache the base height of the wheels in body space m_wheelBaseHeight[0] = left.z; m_wheelBaseHeight[1] = right.z; } if ( GetAttachment( "wheel_rl", left, dummy ) && GetAttachment( "wheel_rr", right, dummy ) ) { VectorITransform( left, m_pOuter->EntityToWorldTransform(), left ); VectorITransform( right, m_pOuter->EntityToWorldTransform(), right ); Vector center = (left + right) * 0.5; vehicle.axles[1].offset = center; vehicle.axles[1].wheelOffset = right - center; // Cache the base height of the wheels in body space m_wheelBaseHeight[2] = left.z; m_wheelBaseHeight[3] = right.z; } SetPoseParameter( m_poseParameters[VEH_FL_WHEEL_HEIGHT], 1 ); SetPoseParameter( m_poseParameters[VEH_FR_WHEEL_HEIGHT], 1 ); SetPoseParameter( m_poseParameters[VEH_RL_WHEEL_HEIGHT], 1 ); SetPoseParameter( m_poseParameters[VEH_RR_WHEEL_HEIGHT], 1 ); InvalidateBoneCache(); if ( GetAttachment( "wheel_fl", left, dummy ) && GetAttachment( "wheel_fr", right, dummy ) ) { VectorITransform( left, m_pOuter->EntityToWorldTransform(), left ); VectorITransform( right, m_pOuter->EntityToWorldTransform(), right ); // Cache the height range of the wheels in body space m_wheelTotalHeight[0] = m_wheelBaseHeight[0] - left.z; m_wheelTotalHeight[1] = m_wheelBaseHeight[1] - right.z; vehicle.axles[0].wheels.springAdditionalLength = m_wheelTotalHeight[0]; } if ( GetAttachment( "wheel_rl", left, dummy ) && GetAttachment( "wheel_rr", right, dummy ) ) { VectorITransform( left, m_pOuter->EntityToWorldTransform(), left ); VectorITransform( right, m_pOuter->EntityToWorldTransform(), right ); // Cache the height range of the wheels in body space m_wheelTotalHeight[2] = m_wheelBaseHeight[0] - left.z; m_wheelTotalHeight[3] = m_wheelBaseHeight[1] - right.z; vehicle.axles[1].wheels.springAdditionalLength = m_wheelTotalHeight[2]; } DevMsgShared("Wheel height: %.3f\n", m_wheelTotalHeight[3]); SetPoseParameter( m_poseParameters[VEH_FL_WHEEL_HEIGHT], 0 ); SetPoseParameter( m_poseParameters[VEH_FR_WHEEL_HEIGHT], 0 ); SetPoseParameter( m_poseParameters[VEH_RL_WHEEL_HEIGHT], 0 ); SetPoseParameter( m_poseParameters[VEH_RR_WHEEL_HEIGHT], 0 ); InvalidateBoneCache(); // Get raytrace offsets if they exist. if ( GetAttachment( "raytrace_fl", left, dummy ) && GetAttachment( "raytrace_fr", right, dummy ) ) { VectorITransform( left, m_pOuter->EntityToWorldTransform(), left ); VectorITransform( right, m_pOuter->EntityToWorldTransform(), right ); Vector center = ( left + right ) * 0.5; vehicle.axles[0].raytraceCenterOffset = center; vehicle.axles[0].raytraceOffset = right - center; } if ( GetAttachment( "raytrace_rl", left, dummy ) && GetAttachment( "raytrace_rr", right, dummy ) ) { VectorITransform( left, m_pOuter->EntityToWorldTransform(), left ); VectorITransform( right, m_pOuter->EntityToWorldTransform(), right ); Vector center = ( left + right ) * 0.5; vehicle.axles[1].raytraceCenterOffset = center; vehicle.axles[1].raytraceOffset = right - center; } } //----------------------------------------------------------------------------- // Spawns the vehicle //----------------------------------------------------------------------------- void CVehiclePhysics::Spawn( ) { Assert( m_pOuter ); m_actionValue = 0; m_actionSpeed = 0; m_bIsOn = false; m_controls.handbrake = false; m_controls.handbrakeLeft = false; m_controls.handbrakeRight = false; m_controls.bHasBrakePedal = true; SetMaxThrottle( 1.0 ); SetMaxReverseThrottle( -1.0f ); InitializePoseParameters(); } //----------------------------------------------------------------------------- // Purpose: Initializes the vehicle physics // Called by our outer vehicle in it's Spawn() //----------------------------------------------------------------------------- bool CVehiclePhysics::Initialize( const char *pVehicleScript, unsigned int nVehicleType ) { // Ok, turn on the simulation now // FIXME: Disabling collisions here is necessary because we seem to be // getting a one-frame collision between the old + new collision models if ( m_pOuter->VPhysicsGetObject() ) { m_pOuter->VPhysicsGetObject()->EnableCollisions(false); } m_pOuter->VPhysicsDestroyObject(); // Create the vphysics model + teleport it into position solid_t solid; vehicleparams_t vehicle; if (!ParseVehicleScript( pVehicleScript, solid, vehicle )) { #ifdef CLIENT_DLL // TODO #else UTIL_Remove(m_pOuter); #endif return false; } // NOTE: this needs to be greater than your max framerate (so zero is still instant) m_throttleRate = 10000.0; if ( vehicle.engine.throttleTime > 0 ) { m_throttleRate = 1.0 / vehicle.engine.throttleTime; } m_flMaxSpeed = vehicle.engine.maxSpeed; IPhysicsObject *pBody = m_pOuter->VPhysicsInitNormal( SOLID_VPHYSICS, 0, false, &solid ); if(!pBody) { Error("The vehicle does not have a physics box\n"); return false; } PhysSetGameFlags( pBody, FVPHYSICS_NO_SELF_COLLISIONS | FVPHYSICS_MULTIOBJECT_ENTITY ); m_pVehicle = physenv->CreateVehicleController( pBody, vehicle, nVehicleType, physgametrace ); m_wheelCount = m_pVehicle->GetWheelCount(); for ( int i = 0; i < m_wheelCount; i++ ) { m_pWheels[i] = m_pVehicle->GetWheel( i ); m_pWheels[i]->SetCallbackFlags(CALLBACK_GLOBAL_COLLISION|CALLBACK_GLOBAL_FRICTION|CALLBACK_FLUID_TOUCH|CALLBACK_GLOBAL_TOUCH|CALLBACK_GLOBAL_COLLIDE_STATIC|CALLBACK_DO_FLUID_SIMULATION); } return true; } //----------------------------------------------------------------------------- // Purpose: Called only by EntityPropVehicle::InputThrottle and used only by // hammer input functions. // SYNC OK //----------------------------------------------------------------------------- void CVehiclePhysics::SetThrottle( float flThrottle ) { m_controls.throttle = flThrottle; } //----------------------------------------------------------------------------- // Purpose: Called only by the constructor (shared - so ok). // SYNC OK //----------------------------------------------------------------------------- void CVehiclePhysics::SetMaxThrottle( float flMaxThrottle ) { m_maxThrottle = flMaxThrottle; } //----------------------------------------------------------------------------- // Purpose: Called only by the constructor (shared - so ok). // SYNC OK //----------------------------------------------------------------------------- void CVehiclePhysics::SetMaxReverseThrottle( float flMaxThrottle ) { m_flMaxRevThrottle = flMaxThrottle; } //----------------------------------------------------------------------------- // Purpose: // Called by: CFourWheelServerVehicle::NPC_DriveVehicle //----------------------------------------------------------------------------- void CVehiclePhysics::SetSteering( float flSteering, float flSteeringRate ) { if ( !flSteeringRate ) { m_controls.steering = flSteering; } else { // TODO: controls m_controls.steering = Approach( flSteering, m_controls.steering, flSteeringRate * gpGlobals->frametime ); m_controls.steering = flSteering; } } //----------------------------------------------------------------------------- // Purpose: // SYNC OK //----------------------------------------------------------------------------- void CVehiclePhysics::SetSteeringDegrees( float flDegrees ) { vehicleparams_t &vehicleParams = m_pVehicle->GetVehicleParamsForChange(); vehicleParams.steering.degrees = flDegrees; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CVehiclePhysics::SetAction( float flAction ) { m_actionSpeed = flAction; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CVehiclePhysics::TurnOn( ) { if ( IsEngineDisabled() ) return; if ( !m_bIsOn ) { // m_pOuterServerVehicle->SoundStart(); TODO m_bIsOn = true; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CVehiclePhysics::TurnOff( ) { ResetControls(); if ( m_bIsOn ) { // m_pOuterServerVehicle->SoundShutdown(); m_bIsOn = false; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CVehiclePhysics::SetBoost( float flBoost ) { if ( !IsEngineDisabled() ) { m_controls.boost = flBoost; } } //------------------------------------------------------ // UpdateBooster - Calls UpdateBooster() in the vphysics // code to allow the timer to be updated // // Returns: false if timer has expired (can use again and // can stop think // true if timer still running //------------------------------------------------------ bool CVehiclePhysics::UpdateBooster( void ) { float retval = m_pVehicle->UpdateBooster(gpGlobals->frametime ); return ( retval > 0 ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CVehiclePhysics::SetHasBrakePedal( bool bHasBrakePedal ) { m_controls.bHasBrakePedal = bHasBrakePedal; } //----------------------------------------------------------------------------- // Teleport //----------------------------------------------------------------------------- void CVehiclePhysics::Teleport( matrix3x4_t& relativeTransform ) { // We basically just have to make sure the wheels are in the right place // after teleportation occurs for ( int i = 0; i < m_wheelCount; i++ ) { matrix3x4_t matrix, newMatrix; m_pWheels[i]->GetPositionMatrix( &matrix ); ConcatTransforms( relativeTransform, matrix, newMatrix ); m_pWheels[i]->SetPositionMatrix( newMatrix, true ); } } #if 1 // For the #if 0 debug code below! #define HL2IVP_FACTOR METERS_PER_INCH #define IVP2HL(x) (float)(x * (1.0f/HL2IVP_FACTOR)) #define HL2IVP(x) (double)(x * HL2IVP_FACTOR) #endif //----------------------------------------------------------------------------- // Processes input and movement of the vehicle //----------------------------------------------------------------------------- void CVehiclePhysics::ProcessMovement(CMoveData *pMove) { // Sanity check if (!m_pVehicle) { return; } // Forward movement m_controls.throttle = Approach(pMove->m_flForwardMove / 400, m_controls.throttle, ACCEL_RATE_RELATIVE); // Steering m_controls.steering = Approach(pMove->m_flSideMove / 400, m_controls.steering, STEER_RATE_RELATIVE); // Hand brake if((pMove->m_nButtons & IN_JUMP) && m_controls.bHasBrakePedal) { m_controls.handbrake = true; m_controls.handbrakeLeft = (pMove->m_flSideMove < 0); m_controls.handbrakeRight = (pMove->m_flSideMove > 0); m_controls.throttle = 0; } else { m_controls.handbrake = false; m_controls.handbrakeLeft = false; m_controls.handbrakeRight = false; } // Update sound + physics state const vehicle_operatingparams_t &carState = m_pVehicle->GetOperatingParams(); const vehicleparams_t &vehicleData = m_pVehicle->GetVehicleParams(); // Set save data. float carSpeed = fabs( INS2MPH( carState.speed ) ); m_nLastSpeed = m_nSpeed; m_nSpeed = ( int )carSpeed; m_fOldRPM = carState.engineRPM; m_nRPM = (int)m_fOldRPM; #ifdef CLIENT_DLL // if( m_nGear != carState.gear) // DevMsg("Changing gears! Gear: %i\n", carState.gear); #endif /* // If the gears are jewed if( m_nGear == (vehicleData.engine.gearCount - 1) && carState.gear == 0 && !m_controls.handbrake) { float flAvgRotSpeed = 0; AngularImpulse temp; // Recalculate RPM with old gear for( int iWheel = 0; iWheel < m_wheelCount; ++iWheel ) { m_pWheels[iWheel]->GetVelocity(NULL, &temp); flAvgRotSpeed += temp.Length(); } flAvgRotSpeed /= m_wheelCount; float flEstEngineRPM = flAvgRotSpeed * vehicleData.engine.axleRatio * vehicleData.engine.gearRatio[m_nGear] * 60; m_nRPM = (int)flEstEngineRPM; } else {*/ m_nGear = carState.gear;/* }*/ m_nHasBoost = vehicleData.engine.boostDelay; // if we have any boost delay, vehicle has boost ability m_pVehicle->Update( gpGlobals->frametime, m_controls); // boost sounds if( IsBoosting() && !m_bLastBoost ) { m_bLastBoost = true; m_turboTimer = gpGlobals->curtime + 2.75f; // min duration for turbo sound } else if( !IsBoosting() && m_bLastBoost ) { if ( gpGlobals->curtime >= m_turboTimer ) { m_bLastBoost = false; } } m_fLastBoost = carState.boostDelay; m_nBoostTimeLeft = carState.boostTimeLeft; // UNDONE: Use skid info from the physics system? // Only check wheels if we're not being carried by a dropship if ( m_pOuter->VPhysicsGetObject() && !m_pOuter->VPhysicsGetObject()->GetShadowController() ) { // check for skidding, if we're skidding, need to play the sound if ( carState.skidding && m_bIsOn ) { if ( !m_bLastSkid ) // only play sound once { m_bLastSkid = true; CPASAttenuationFilter filter( m_pOuter ); // m_pOuterServerVehicle->PlaySound( VS_SKID_FRICTION_NORMAL ); TODO } // kick up dust from the wheels while skidding for ( int i = 0; i < 4; i++ ) { PlaceWheelDust( i, true ); } } else if ( m_bLastSkid == true ) { m_bLastSkid = false; // m_pOuterServerVehicle->StopSound( VS_SKID_FRICTION_NORMAL ); TODO } // toss dust up from the wheels of the vehicle if we're moving fast enough if (vehicleData.steering.dustCloud && m_bIsOn) { for ( int i = 0; i < 4; i++ ) { PlaceWheelDust( i ); } } } // Make the steering wheel match the input, with a little dampening. #define STEER_DAMPING 0.8 //float flSteer = GetPoseParameter( m_poseParameters[VEH_STEER] ); //SetPoseParameter( m_poseParameters[VEH_STEER], (STEER_DAMPING * flSteer) + ((1 - STEER_DAMPING) * m_controls.steering) ); SetPoseParameter( m_poseParameters[VEH_STEER], m_controls.steering ); m_actionValue += m_actionSpeed * m_actionScale * gpGlobals->frametime; SetPoseParameter( m_poseParameters[VEH_ACTION], m_actionValue ); // setup speedometer if ( m_bIsOn == true ) { float displaySpeed = m_nSpeed / MAX_GUAGE_SPEED; SetPoseParameter( m_poseParameters[VEH_SPEEDO], displaySpeed ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CVehiclePhysics::VPhysicsUpdate( IPhysicsObject *pPhysics ) { if ( r_vehicleDrawDebug.GetInt() ) { DrawDebugGeometryOverlays(); } // must be a wheel if ( pPhysics == m_pOuter->VPhysicsGetObject() ) return true; // This is here so we can make the pose parameters of the wheels // reflect their current physics state for ( int i = 0; i < m_wheelCount; i++ ) { if ( pPhysics == m_pWheels[i] ) { Vector tmp; pPhysics->GetPosition( &m_wheelPosition[i], &m_wheelRotation[i] ); // transform the wheel into body space VectorITransform( m_wheelPosition[i], m_pOuter->EntityToWorldTransform(), tmp ); SetPoseParameter( m_poseParameters[VEH_FL_WHEEL_HEIGHT + i], (m_wheelBaseHeight[i] - tmp.z) / m_wheelTotalHeight[i] ); SetPoseParameter( m_poseParameters[VEH_FL_WHEEL_SPIN + i], -m_wheelRotation[i].z ); return false; } } return false; } //----------------------------------------------------------------------------- // Shared code to compute the vehicle view position //----------------------------------------------------------------------------- void CVehiclePhysics::GetVehicleViewPosition( const char *pViewAttachment, float flPitchFactor, Vector *pAbsOrigin, QAngle *pAbsAngles ) { matrix3x4_t vehicleEyePosToWorld; Vector vehicleEyeOrigin; QAngle vehicleEyeAngles; GetAttachment( pViewAttachment, vehicleEyeOrigin, vehicleEyeAngles ); AngleMatrix( vehicleEyeAngles, vehicleEyePosToWorld ); #ifdef HL2_DLL // View dampening. if ( r_VehicleViewDampen.GetInt() ) { // m_pOuterServerVehicle->GetFourWheelVehicle()->DampenEyePosition( vehicleEyeOrigin, vehicleEyeAngles ); } #endif // 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 ); } //----------------------------------------------------------------------------- // Control initialization //----------------------------------------------------------------------------- void CVehiclePhysics::ResetControls() { m_controls.handbrake = true; m_controls.handbrakeLeft = false; m_controls.handbrakeRight = false; m_controls.boost = 0; m_controls.brake = 0.0f; m_controls.throttle = 0; m_controls.steering = 0; } void CVehiclePhysics::ReleaseHandbrake() { m_controls.handbrake = false; } void CVehiclePhysics::SetHandbrake( bool bBrake ) { m_controls.handbrake = bBrake; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CVehiclePhysics::EnableMotion( void ) { for( int iWheel = 0; iWheel < m_wheelCount; ++iWheel ) { m_pWheels[iWheel]->EnableMotion( true ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CVehiclePhysics::DisableMotion( void ) { Vector vecZero( 0.0f, 0.0f, 0.0f ); AngularImpulse angNone( 0.0f, 0.0f, 0.0f ); for( int iWheel = 0; iWheel < m_wheelCount; ++iWheel ) { m_pWheels[iWheel]->SetVelocity( &vecZero, &angNone ); m_pWheels[iWheel]->EnableMotion( false ); } } float CVehiclePhysics::GetHLSpeed() const { const vehicle_operatingparams_t &carState = m_pVehicle->GetOperatingParams(); return carState.speed; } float CVehiclePhysics::GetSteering() const { return m_controls.steering; } float CVehiclePhysics::GetSteeringDegrees() const { const vehicleparams_t vehicleParams = m_pVehicle->GetVehicleParams(); return vehicleParams.steering.degrees; } #define STEERING_BASE_RATE 3.0f #define STEERING_REST_DECAY 2.0f #define STEERING_REST_EPS 0.001f //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CVehiclePhysics::SteeringRest( float carSpeed, const vehicleparams_t &vehicleData ) { // TODO controls: m_controls.steering = Approach(0, m_controls.steering, ( STEERING_REST_DECAY * vehicleData.steering.steeringRestFactor * gpGlobals->frametime )); m_controls.steering = 0; m_nTurnLeftCount = 2; m_nTurnRightCount = 2; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CVehiclePhysics::SteeringTurn( float carSpeed, const vehicleparams_t &vehicleData, bool bTurnLeft ) { float flSteeringRate = STEERING_BASE_RATE * 4; if ( bTurnLeft ) { // TODO: change the log function to an approx. m_nTurnLeftCount = clamp( m_nTurnLeftCount, 2, 30 ); flSteeringRate *= log( (float) m_nTurnLeftCount ); SetSteering( -1, flSteeringRate ); // m_nTurnLeftCount++; m_nTurnLeftCount += gpGlobals->frametime; m_nTurnRightCount = 2; } else { // TODO: change the log function to an approx. m_nTurnRightCount = clamp( m_nTurnRightCount, 2, 30 ); flSteeringRate *= log( (float) m_nTurnRightCount ); SetSteering( 1, flSteeringRate ); m_nTurnLeftCount = 2; // m_nTurnRightCount++; m_nTurnRightCount += gpGlobals->frametime; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CVehiclePhysics::SteeringTurnAnalog( float carSpeed, const vehicleparams_t &vehicleData, float sidemove ) { float flSteeringRate = STEERING_BASE_RATE; float factor = clamp( fabs( sidemove ) / 400.0f, 0.0f, 1.0f ); factor *= 30; flSteeringRate *= log( factor ); SetSteering( sidemove < 0.0f ? 1 : -1, flSteeringRate ); // Neutralize m_nTurnLeftCount = 2; m_nTurnRightCount = 2; } /* //----------------------------------------------------------------------------- // Methods related to actually driving the vehicle //----------------------------------------------------------------------------- void CVehiclePhysics::UpdateDriverControls( CUserCmd *cmd, float flFrameTime ) { if(!m_pVehicle) { return; } int nButtons = cmd->buttons; // Get vehicle data. const vehicle_operatingparams_t &carState = m_pVehicle->GetOperatingParams(); const vehicleparams_t &vehicleData = m_pVehicle->GetVehicleParams(); // Get current speed in miles/hour. float flCarSign = carState.speed >= 0.0f ? 1.0f : -1.0f; float carSpeed = fabs(INS2MPH(carState.speed)); // If changing direction, use default "return to zero" speed to more quickly transition. if ( ( nButtons & IN_MOVELEFT ) || ( nButtons & IN_MOVERIGHT ) ) { SteeringTurn( carSpeed, vehicleData, ( ( nButtons & IN_MOVELEFT ) != 0 ) ); } else if ( cmd->sidemove != 0.0f ) { SteeringTurnAnalog( carSpeed, vehicleData, cmd->sidemove ); } else { SteeringRest( carSpeed, vehicleData ); } // Set vehicle control inputs. m_controls.boost = 0; m_controls.handbrake = false; m_controls.handbrakeLeft = false; m_controls.handbrakeRight = false; m_controls.brakepedal = false; bool bThrottle; if ( nButtons & IN_FORWARD ) { bThrottle = true; if ( m_controls.throttle < 0 ) { m_controls.throttle = 0; } float flMaxThrottle = max( 0.1, m_maxThrottle - ( m_maxThrottle * m_flThrottleReduction ) ); // TODO m_controls.throttle = Approach( flMaxThrottle, m_controls.throttle, flFrameTime * m_throttleRate ); m_controls.throttle = flMaxThrottle; // Apply the brake. if ( ( flCarSign < 0.0f ) && m_controls.bHasBrakePedal ) { // TODO m_controls.brake = Approach( BRAKE_MAX_VALUE, m_controls.brake, flFrameTime * r_vehicleBrakeRate.GetFloat() * BRAKE_BACK_FORWARD_SCALAR ); m_controls.brake = BRAKE_MAX_VALUE; m_controls.brakepedal = true; m_controls.throttle = 0.0f; bThrottle = false; } else { m_controls.brake = 0.0f; } } else if ( nButtons & IN_BACK ) { bThrottle = true; if ( m_controls.throttle > 0 ) { m_controls.throttle = 0; } float flMaxThrottle = min( -0.1, m_flMaxRevThrottle - ( m_flMaxRevThrottle * m_flThrottleReduction ) ); // TODO: controls m_controls.throttle = Approach( flMaxThrottle, m_controls.throttle, flFrameTime * m_throttleRate ); m_controls.throttle = flMaxThrottle; // Apply the brake. if ( ( flCarSign > 0.0f ) && m_controls.bHasBrakePedal ) { /// TODO controls m_controls.brake = Approach( BRAKE_MAX_VALUE, m_controls.brake, flFrameTime * r_vehicleBrakeRate.GetFloat() ); m_controls.brake = 1; m_controls.brakepedal = true; m_controls.throttle = 0.0f; bThrottle = false; } else { m_controls.brake = 0.0f; } } else { bThrottle = false; m_controls.throttle = 0; m_controls.brake = 0.0f; } if ( ( nButtons & IN_SPEED ) && !IsEngineDisabled() ) { m_controls.boost = 1.0f; } // Using has brakepedal for handbrake as well. if ( ( nButtons & IN_JUMP ) && m_controls.bHasBrakePedal ) { m_controls.handbrake = true; if ( nButtons & IN_MOVELEFT ) { m_controls.handbrakeLeft = true; } else if ( nButtons & IN_MOVERIGHT ) { m_controls.handbrakeRight = true; } // Prevent playing of the engine revup when we're braking bThrottle = false; } if ( IsEngineDisabled() ) { m_controls.throttle = 0.0f; m_controls.handbrake = true; bThrottle = false; } // throttle sounds // If we dropped a bunch of speed, restart the throttle if ( bThrottle && (m_nLastSpeed > m_nSpeed && (m_nLastSpeed - m_nSpeed > 10)) ) { m_bLastThrottle = false; } // throttle down now but not before??? (or we're braking) if ( !m_controls.handbrake && !m_controls.brakepedal && bThrottle && !m_bLastThrottle ) { m_throttleStartTime = gpGlobals->curtime; // need to track how long throttle is down m_bLastThrottle = true; } // throttle up now but not before?? else if ( !bThrottle && m_bLastThrottle && IsEngineDisabled() == false ) { m_throttleActiveTime = gpGlobals->curtime - m_throttleStartTime; m_bLastThrottle = false; } // float flSpeedPercentage = clamp( m_nSpeed / m_flMaxSpeed, 0, 1 ); // vbs_sound_update_t params; // params.Defaults(); // params.bReverse = (m_controls.throttle < 0); // params.bThrottleDown = bThrottle; // params.bTurbo = IsBoosting(); // params.bVehicleInWater = m_pOuterServerVehicle->IsVehicleBodyInWater(); // params.flCurrentSpeedFraction = flSpeedPercentage; // params.flFrameTime = flFrameTime; // params.flWorldSpaceSpeed = carState.speed; TODO // m_pOuterServerVehicle->SoundUpdate( params ); }*/ //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CVehiclePhysics::AddThrottleReduction( float flPercentage ) { // We allow the speed reduction to go over 1, but extras have no effect. m_flThrottleReduction = m_flThrottleReduction + flPercentage; //Msg("Added speed reduction. Now %.2f\n", m_flThrottleReduction ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CVehiclePhysics::RemoveThrottleReduction( float flPercentage ) { m_flThrottleReduction = max( 0, m_flThrottleReduction - flPercentage ); //Msg("Removed speed reduction. Now %.2f\n", m_flThrottleReduction ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CVehiclePhysics::IsBoosting( void ) { const vehicleparams_t *pVehicleParams = &m_pVehicle->GetVehicleParams(); const vehicle_operatingparams_t *pVehicleOperating = &m_pVehicle->GetOperatingParams(); if ( pVehicleParams && pVehicleOperating ) { if ( ( pVehicleOperating->boostDelay - pVehicleParams->engine.boostDelay ) > 0.0f ) return true; } return false; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CVehiclePhysics::SetDisableEngine( bool bDisable ) { // Set the engine state. m_pVehicle->SetEngineDisabled( bDisable ); } //----------------------------------------------------------------------------- // Debugging methods //----------------------------------------------------------------------------- void CVehiclePhysics::DrawDebugGeometryOverlays() { #ifdef CLIENT_DLL int iColour = 256; #else int iColour = 128; #endif DrawDebugTextOverlays(0); Vector vecRad(m_debugRadius,m_debugRadius,m_debugRadius); for ( int i = 0; i < m_wheelCount; i++ ) { NDebugOverlay::BoxAngles(m_wheelPosition[i], -vecRad, vecRad, m_wheelRotation[i], 0, iColour, 45, 0 ,0); } for ( int iWheel = 0; iWheel < m_wheelCount; iWheel++ ) { IPhysicsObject *pWheel = m_pVehicle->GetWheel( iWheel ); Vector vecPos; QAngle vecRot; pWheel->GetPosition( &vecPos, &vecRot ); NDebugOverlay::BoxAngles( vecPos, -vecRad, vecRad, vecRot, 0, iColour, 45, 0 ,0 ); } #if 1 // Render vehicle data. IPhysicsObject *pBody = m_pOuter->VPhysicsGetObject(); if ( pBody ) { const vehicleparams_t vehicleParams = m_pVehicle->GetVehicleParams(); // Draw a red cube as the "center" of the vehicle. Vector vecBodyPosition; QAngle angBodyDirection; pBody->GetPosition( &vecBodyPosition, &angBodyDirection ); NDebugOverlay::BoxAngles( vecBodyPosition, Vector( -5, -5, -5 ), Vector( 5, 5, 5 ), angBodyDirection, iColour, 0, 0, 0 ,0 ); matrix3x4_t matrix; AngleMatrix( angBodyDirection, vecBodyPosition, matrix ); // Draw green cubes at axle centers. Vector vecAxlePositions[2], vecAxlePositionsHL[2]; vecAxlePositions[0] = vehicleParams.axles[0].offset; vecAxlePositions[1] = vehicleParams.axles[1].offset; VectorTransform( vecAxlePositions[0], matrix, vecAxlePositionsHL[0] ); VectorTransform( vecAxlePositions[1], matrix, vecAxlePositionsHL[1] ); NDebugOverlay::BoxAngles( vecAxlePositionsHL[0], Vector( -3, -3, -3 ), Vector( 3, 3, 3 ), angBodyDirection, 0, iColour, 0, 0 ,0 ); NDebugOverlay::BoxAngles( vecAxlePositionsHL[1], Vector( -3, -3, -3 ), Vector( 3, 3, 3 ), angBodyDirection, 0, iColour, 0, 0 ,0 ); // Draw blue cubes at wheel centers. Vector vecWheelPositions[4], vecWheelPositionsHL[4]; vecWheelPositions[0] = vehicleParams.axles[0].offset; vecWheelPositions[0] -= vehicleParams.axles[0].wheelOffset; vecWheelPositions[1] = vehicleParams.axles[0].offset; vecWheelPositions[1] += vehicleParams.axles[0].wheelOffset; vecWheelPositions[2] = vehicleParams.axles[1].offset; vecWheelPositions[2] -= vehicleParams.axles[1].wheelOffset; vecWheelPositions[3] = vehicleParams.axles[1].offset; vecWheelPositions[3] += vehicleParams.axles[1].wheelOffset; VectorTransform( vecWheelPositions[0], matrix, vecWheelPositionsHL[0] ); VectorTransform( vecWheelPositions[1], matrix, vecWheelPositionsHL[1] ); VectorTransform( vecWheelPositions[2], matrix, vecWheelPositionsHL[2] ); VectorTransform( vecWheelPositions[3], matrix, vecWheelPositionsHL[3] ); float flWheelRadius = vehicleParams.axles[0].wheels.radius; flWheelRadius = IVP2HL( flWheelRadius ); Vector vecWheelRadius( flWheelRadius, flWheelRadius, flWheelRadius ); NDebugOverlay::BoxAngles( vecWheelPositionsHL[0], -vecWheelRadius, vecWheelRadius, angBodyDirection, 0, 0, iColour, 0 ,0 ); NDebugOverlay::BoxAngles( vecWheelPositionsHL[1], -vecWheelRadius, vecWheelRadius, angBodyDirection, 0, 0, iColour, 0 ,0 ); NDebugOverlay::BoxAngles( vecWheelPositionsHL[2], -vecWheelRadius, vecWheelRadius, angBodyDirection, 0, 0, iColour, 0 ,0 ); NDebugOverlay::BoxAngles( vecWheelPositionsHL[3], -vecWheelRadius, vecWheelRadius, angBodyDirection, 0, 0, iColour, 0 ,0 ); // Draw wheel raycasts in yellow vehicle_debugcarsystem_t debugCarSystem; m_pVehicle->GetCarSystemDebugData( debugCarSystem ); for ( int iWheel = 0; iWheel < 4; ++iWheel ) { // Scott McNaught: Are the client side raycasts off? Vector vecStart, vecEnd, vecImpact; // Hack for now. float tmpY = IVP2HL( debugCarSystem.vecWheelRaycasts[iWheel][0].z ); vecStart.z = -IVP2HL( debugCarSystem.vecWheelRaycasts[iWheel][0].y ); vecStart.y = tmpY; vecStart.x = IVP2HL( debugCarSystem.vecWheelRaycasts[iWheel][0].x ); tmpY = IVP2HL( debugCarSystem.vecWheelRaycasts[iWheel][1].z ); vecEnd.z = -IVP2HL( debugCarSystem.vecWheelRaycasts[iWheel][1].y ); vecEnd.y = tmpY; vecEnd.x = IVP2HL( debugCarSystem.vecWheelRaycasts[iWheel][1].x ); tmpY = IVP2HL( debugCarSystem.vecWheelRaycastImpacts[iWheel].z ); vecImpact.z = -IVP2HL( debugCarSystem.vecWheelRaycastImpacts[iWheel].y ); vecImpact.y = tmpY; vecImpact.x = IVP2HL( debugCarSystem.vecWheelRaycastImpacts[iWheel].x ); NDebugOverlay::BoxAngles( vecStart, Vector( -1 , -1, -1 ), Vector( 1, 1, 1 ), angBodyDirection, 0, iColour, 0, 0, 0 ); NDebugOverlay::Line( vecStart, vecEnd, 255, 255, 0, true, 0 ); NDebugOverlay::BoxAngles( vecEnd, Vector( -1, -1, -1 ), Vector( 1, 1, 1 ), angBodyDirection, iColour, 0, 0, 0, 0 ); NDebugOverlay::BoxAngles( vecImpact, Vector( -0.5f , -0.5f, -0.5f ), Vector( 0.5f, 0.5f, 0.5f ), angBodyDirection, 0, 0, iColour, 0, 0 ); } } #endif } int CVehiclePhysics::DrawDebugTextOverlays( int nOffset ) { #ifndef CLIENT_DLL char str[] = "SV: T/S/B (%.2f %.2f %.2f)\n"; #else char str[] = "CL: T/S/B (%.2f %.2f %.2f)\n"; nOffset++; #endif // const vehicle_operatingparams_t ¶ms = m_pVehicle->GetOperatingParams(); char tempstr[512]; Q_snprintf( tempstr,sizeof(tempstr), str, m_controls.throttle, m_controls.steering, m_controls.brake ); //NDebugOverlay::EntityText( m_pOuter->entindex(), nOffset, tempstr, 0 ); nOffset++; Msg( "%s", tempstr ); /*Q_snprintf( tempstr,sizeof(tempstr), "Gear: %d, RPM %4d", params.gear, (int)params.engineRPM ); NDebugOverlay::EntityText( m_pOuter->entindex(), nOffset, tempstr, 0 ); nOffset++; Msg( " %s\n", tempstr );*/ return nOffset; } //---------------------------------------------------- // Place dust at vector passed in //---------------------------------------------------- #define DUST_SPEED 5 // Velocity #define DUST_VELOCITY_RAND_MIN -1.0f #define DUST_VELOCITY_RAND_MAX 1.0f #define DUST_VELOCITY_Z_MIN .3f #define DUST_Z_SPEED_RAND_MIN 5.0f #define DUST_Z_SPEED_RAND_MAX 15.0f // Color #define DUST_COLOR_R 20 #define DUST_COLOR_G 11 #define DUST_COLOR_B 2.2 #define DUST_COLOR_RAND_MIN 100 #define DUST_COLOR_RAND_MAX 150 // Alpha #define DUST_ALPHA_RAND_MIN 64.0f #define DUST_ALPHA_RAND_MAX 128.0f // Life #define DUST_LIFE_RAND_MIN 1.0f #define DUST_LIFE_RAND_MAX 2.5f // Size #define DUST_SIZE_START_RAND_MIN 16 #define DUST_SIZE_START_RAND_MAX 20 #define DUST_SIZE_END_RAND_MIN 18 #define DUST_SIZE_END_RAND_MAX 22 void CVehiclePhysics::PlaceWheelDust( int wheelIndex, bool ignoreSpeed ) { #ifdef CLIENT_DLL /* UNDONE - for some reason this is causing *serious* lag Vector vecPos, vecVel; m_pVehicle->GetWheelContactPoint(wheelIndex, vecPos); // Velocity vector vecVel.Random(DUST_VELOCITY_RAND_MIN, DUST_VELOCITY_RAND_MAX); vecVel.z = random->RandomFloat(DUST_VELOCITY_Z_MIN, DUST_VELOCITY_RAND_MAX); VectorNormalize(vecVel); // Higher speeds make larger dust clouds float flSize; if ( ignoreSpeed ) { flSize = 1.0f; } else { flSize = RemapValClamped( m_nSpeed, DUST_SPEED, m_flMaxSpeed, 0.0f, 1.0f ); } if (flSize) { CSmartPtr pEmitter = CSimpleEmitter::Create("dust"); pEmitter->SetSortOrigin(vecPos); pEmitter->SetNearClip(32, 64); SimpleParticle *pParticle; Vector offset; offset = vecPos + (vecVel * flSize); // Find area ambient light color and use it to tint smoke Vector worldLight = WorldGetLightForPoint(offset, true); PMaterialHandle hMaterial = pEmitter->GetPMaterial("particle/particle_smokegrenade"); // Throw puffs offset.Random(-(flSize*16.0f), flSize*16.0f); offset.z = 0.4f; offset += vecPos + (vecVel * flSize); pParticle = (SimpleParticle *)pEmitter->AddParticle(sizeof(SimpleParticle), hMaterial, offset); // No particle created, return if (!pParticle) { return; } pParticle->m_flLifetime = 0.0f; pParticle->m_flDieTime = random->RandomFloat(DUST_LIFE_RAND_MIN, DUST_LIFE_RAND_MAX); pParticle->m_vecVelocity = RandomVector(DUST_VELOCITY_RAND_MIN, DUST_VELOCITY_RAND_MAX); VectorNormalize(pParticle->m_vecVelocity); pParticle->m_vecVelocity[2] += random->RandomFloat(DUST_Z_SPEED_RAND_MIN, DUST_Z_SPEED_RAND_MAX) * (flSize*2.0f); int color = random->RandomInt(DUST_COLOR_RAND_MIN, DUST_COLOR_RAND_MAX); // Color pParticle->m_uchColor[0] = DUST_COLOR_R + (worldLight[0] * (float) color); pParticle->m_uchColor[1] = DUST_COLOR_G + (worldLight[1] * (float) color); pParticle->m_uchColor[2] = DUST_COLOR_B + (worldLight[2] * (float) color); // Alpha pParticle->m_uchStartAlpha = random->RandomInt(DUST_ALPHA_RAND_MIN * flSize, DUST_ALPHA_RAND_MAX * flSize ); pParticle->m_uchEndAlpha = 0; // Size pParticle->m_uchStartSize = random->RandomInt(DUST_SIZE_START_RAND_MIN, DUST_SIZE_START_RAND_MAX) * flSize; pParticle->m_uchEndSize = random->RandomInt(DUST_SIZE_END_RAND_MIN, DUST_SIZE_END_RAND_MAX) * flSize; pParticle->m_flRoll = random->RandomInt(0, 360); pParticle->m_flRollDelta = random->RandomFloat(-2.0f, 2.0f); }*/ #endif } static int AddPhysToList( IPhysicsObject **pList, int listMax, int count, IPhysicsObject *pPhys ) { if ( pPhys ) { if ( count < listMax ) { pList[count] = pPhys; count++; } } return count; } int CVehiclePhysics::VPhysicsGetObjectList( IPhysicsObject **pList, int listMax ) { int count = 0; // add the body count = AddPhysToList( pList, listMax, count, m_pOuter->VPhysicsGetObject() ); for ( int i = 0; i < 4; i++ ) { count = AddPhysToList( pList, listMax, count, m_pWheels[i] ); } return count; }