You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1465 lines
38 KiB
1465 lines
38 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: Spawn, think, and use functions for common brush entities. |
|
// |
|
//=============================================================================// |
|
|
|
#include "cbase.h" |
|
#include "doors.h" |
|
#include "mathlib/mathlib.h" |
|
#include "physics.h" |
|
#include "ndebugoverlay.h" |
|
#include "engine/IEngineSound.h" |
|
#include "globals.h" |
|
#include "filters.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
#define SF_BRUSH_ACCDCC 16// brush should accelerate and decelerate when toggled |
|
#define SF_BRUSH_HURT 32// rotating brush that inflicts pain based on rotation speed |
|
#define SF_ROTATING_NOT_SOLID 64 // some special rotating objects are not solid. |
|
|
|
// =================== FUNC_WALL ============================================== |
|
class CFuncWall : public CBaseEntity |
|
{ |
|
public: |
|
DECLARE_DATADESC(); |
|
DECLARE_CLASS( CFuncWall, CBaseEntity ); |
|
void Spawn( void ); |
|
bool CreateVPhysics( void ); |
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); |
|
|
|
int m_nState; |
|
}; |
|
|
|
LINK_ENTITY_TO_CLASS( func_wall, CFuncWall ); |
|
|
|
//--------------------------------------------------------- |
|
// Save/Restore |
|
//--------------------------------------------------------- |
|
BEGIN_DATADESC( CFuncWall ) |
|
|
|
DEFINE_FIELD( m_nState, FIELD_INTEGER ), |
|
|
|
END_DATADESC() |
|
|
|
void CFuncWall::Spawn( void ) |
|
{ |
|
SetLocalAngles( vec3_angle ); |
|
SetMoveType( MOVETYPE_PUSH ); // so it doesn't get pushed by anything |
|
SetModel( STRING( GetModelName() ) ); |
|
|
|
// If it can't move/go away, it's really part of the world |
|
AddFlag( FL_WORLDBRUSH ); |
|
|
|
// set manual mode |
|
CreateVPhysics(); |
|
} |
|
|
|
|
|
bool CFuncWall::CreateVPhysics( void ) |
|
{ |
|
SetSolid( SOLID_BSP ); |
|
IPhysicsObject *pPhys = VPhysicsInitStatic(); |
|
if ( pPhys ) |
|
{ |
|
int contents = modelinfo->GetModelContents( GetModelIndex() ); |
|
if ( ! (contents & (MASK_SOLID|MASK_PLAYERSOLID|MASK_NPCSOLID)) ) |
|
{ |
|
// leave the physics shadow there in case it has crap constrained to it |
|
// but disable collisions with it |
|
pPhys->EnableCollisions( false ); |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
|
|
void CFuncWall::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) |
|
{ |
|
if ( ShouldToggle( useType, m_nState ) ) |
|
{ |
|
m_nState = 1 - m_nState; |
|
} |
|
} |
|
|
|
|
|
#define SF_WALL_START_OFF 0x0001 |
|
|
|
class CFuncWallToggle : public CFuncWall |
|
{ |
|
public: |
|
DECLARE_CLASS( CFuncWallToggle, CFuncWall ); |
|
|
|
DECLARE_DATADESC(); |
|
|
|
void Spawn( void ); |
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); |
|
|
|
void InputToggle( inputdata_t &inputdata ); |
|
|
|
void TurnOff( void ); |
|
void TurnOn( void ); |
|
bool IsOn( void ); |
|
}; |
|
|
|
BEGIN_DATADESC( CFuncWallToggle ) |
|
|
|
DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ), |
|
|
|
END_DATADESC() |
|
|
|
|
|
LINK_ENTITY_TO_CLASS( func_wall_toggle, CFuncWallToggle ); |
|
|
|
void CFuncWallToggle::Spawn( void ) |
|
{ |
|
BaseClass::Spawn(); |
|
if ( HasSpawnFlags( SF_WALL_START_OFF ) ) |
|
TurnOff(); |
|
|
|
SetMoveType( MOVETYPE_PUSH ); |
|
} |
|
|
|
|
|
void CFuncWallToggle::TurnOff( void ) |
|
{ |
|
IPhysicsObject *pPhys = VPhysicsGetObject(); |
|
if ( pPhys ) |
|
{ |
|
pPhys->EnableCollisions( false ); |
|
} |
|
AddSolidFlags( FSOLID_NOT_SOLID ); |
|
AddEffects( EF_NODRAW ); |
|
} |
|
|
|
|
|
void CFuncWallToggle::TurnOn( void ) |
|
{ |
|
IPhysicsObject *pPhys = VPhysicsGetObject(); |
|
if ( pPhys ) |
|
{ |
|
pPhys->EnableCollisions( true ); |
|
} |
|
RemoveSolidFlags( FSOLID_NOT_SOLID ); |
|
RemoveEffects( EF_NODRAW ); |
|
} |
|
|
|
|
|
bool CFuncWallToggle::IsOn( void ) |
|
{ |
|
if ( IsSolidFlagSet( FSOLID_NOT_SOLID ) ) |
|
return false; |
|
return true; |
|
} |
|
|
|
void CFuncWallToggle::InputToggle( inputdata_t &inputdata ) |
|
{ |
|
int status = IsOn(); |
|
|
|
if ( ShouldToggle( USE_TOGGLE, status ) ) |
|
{ |
|
if ( status ) |
|
TurnOff(); |
|
else |
|
TurnOn(); |
|
} |
|
} |
|
|
|
//Adrian - Is this function needed at all? |
|
void CFuncWallToggle::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) |
|
{ |
|
int status = IsOn(); |
|
|
|
if ( ShouldToggle( useType, status ) ) |
|
{ |
|
if ( status ) |
|
TurnOff(); |
|
else |
|
TurnOn(); |
|
} |
|
} |
|
|
|
//============================== FUNC_VEHICLECLIP ===================================== |
|
class CFuncVehicleClip : public CBaseEntity |
|
{ |
|
public: |
|
DECLARE_CLASS( CFuncVehicleClip, CBaseEntity ); |
|
DECLARE_DATADESC(); |
|
|
|
void Spawn(); |
|
bool CreateVPhysics( void ); |
|
|
|
void InputEnable( inputdata_t &data ); |
|
void InputDisable( inputdata_t &data ); |
|
|
|
private: |
|
}; |
|
|
|
BEGIN_DATADESC( CFuncVehicleClip ) |
|
|
|
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ), |
|
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ), |
|
|
|
END_DATADESC() |
|
|
|
LINK_ENTITY_TO_CLASS( func_vehicleclip, CFuncVehicleClip ); |
|
|
|
void CFuncVehicleClip::Spawn() |
|
{ |
|
|
|
SetLocalAngles( vec3_angle ); |
|
SetMoveType( MOVETYPE_PUSH ); // so it doesn't get pushed by anything |
|
SetModel( STRING( GetModelName() ) ); |
|
|
|
// It's part of the world |
|
AddFlag( FL_WORLDBRUSH ); |
|
|
|
CreateVPhysics(); |
|
|
|
AddEffects( EF_NODRAW ); // make entity invisible |
|
|
|
SetCollisionGroup( COLLISION_GROUP_VEHICLE_CLIP ); |
|
} |
|
|
|
bool CFuncVehicleClip::CreateVPhysics( void ) |
|
{ |
|
SetSolid( SOLID_BSP ); |
|
VPhysicsInitStatic(); |
|
|
|
return true; |
|
} |
|
|
|
void CFuncVehicleClip::InputEnable( inputdata_t &data ) |
|
{ |
|
IPhysicsObject *pPhys = VPhysicsGetObject(); |
|
if ( pPhys ) |
|
{ |
|
pPhys->EnableCollisions( true ); |
|
} |
|
RemoveSolidFlags( FSOLID_NOT_SOLID ); |
|
} |
|
|
|
void CFuncVehicleClip::InputDisable( inputdata_t &data ) |
|
{ |
|
IPhysicsObject *pPhys = VPhysicsGetObject(); |
|
if ( pPhys ) |
|
{ |
|
pPhys->EnableCollisions( false ); |
|
} |
|
AddSolidFlags( FSOLID_NOT_SOLID ); |
|
} |
|
|
|
//============================= FUNC_CONVEYOR ======================================= |
|
|
|
#define SF_CONVEYOR_VISUAL 0x0001 |
|
#define SF_CONVEYOR_NOTSOLID 0x0002 |
|
|
|
class CFuncConveyor : public CFuncWall |
|
{ |
|
public: |
|
DECLARE_CLASS( CFuncConveyor, CFuncWall ); |
|
DECLARE_DATADESC(); |
|
DECLARE_SERVERCLASS(); |
|
|
|
CFuncConveyor(); |
|
|
|
void Spawn( void ); |
|
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); |
|
void UpdateSpeed( float flNewSpeed ); |
|
|
|
void GetGroundVelocityToApply( Vector &vecGroundVel ); |
|
|
|
// Input handlers. |
|
void InputToggleDirection( inputdata_t &inputdata ); |
|
void InputSetSpeed( inputdata_t &inputdata ); |
|
|
|
private: |
|
|
|
Vector m_vecMoveDir; |
|
CNetworkVar( float, m_flConveyorSpeed ); |
|
}; |
|
|
|
LINK_ENTITY_TO_CLASS( func_conveyor, CFuncConveyor ); |
|
|
|
BEGIN_DATADESC( CFuncConveyor ) |
|
|
|
DEFINE_INPUTFUNC( FIELD_VOID, "ToggleDirection", InputToggleDirection ), |
|
DEFINE_INPUTFUNC( FIELD_VOID, "SetSpeed", InputSetSpeed ), |
|
|
|
DEFINE_KEYFIELD( m_vecMoveDir, FIELD_VECTOR, "movedir" ), |
|
DEFINE_FIELD( m_flConveyorSpeed, FIELD_FLOAT ), |
|
|
|
END_DATADESC() |
|
|
|
|
|
IMPLEMENT_SERVERCLASS_ST(CFuncConveyor, DT_FuncConveyor) |
|
SendPropFloat( SENDINFO(m_flConveyorSpeed), 0, SPROP_NOSCALE ), |
|
END_SEND_TABLE() |
|
|
|
|
|
CFuncConveyor::CFuncConveyor() |
|
{ |
|
m_flConveyorSpeed = 0.0; |
|
} |
|
|
|
void CFuncConveyor::Spawn( void ) |
|
{ |
|
// Convert movedir from angles to a vector |
|
QAngle angMoveDir = QAngle( m_vecMoveDir.x, m_vecMoveDir.y, m_vecMoveDir.z ); |
|
AngleVectors( angMoveDir, &m_vecMoveDir ); |
|
|
|
BaseClass::Spawn(); |
|
|
|
if ( !HasSpawnFlags(SF_CONVEYOR_VISUAL) ) |
|
AddFlag( FL_CONVEYOR ); |
|
|
|
// HACKHACK - This is to allow for some special effects |
|
if ( HasSpawnFlags( SF_CONVEYOR_NOTSOLID ) ) |
|
{ |
|
AddSolidFlags( FSOLID_NOT_SOLID ); |
|
} |
|
|
|
if ( m_flSpeed == 0 ) |
|
m_flSpeed = 100; |
|
|
|
UpdateSpeed( m_flSpeed ); |
|
} |
|
|
|
|
|
void CFuncConveyor::UpdateSpeed( float flNewSpeed ) |
|
{ |
|
m_flConveyorSpeed = flNewSpeed; |
|
} |
|
|
|
|
|
void CFuncConveyor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) |
|
{ |
|
m_flSpeed = -m_flSpeed; |
|
UpdateSpeed( m_flSpeed ); |
|
} |
|
|
|
|
|
void CFuncConveyor::InputToggleDirection( inputdata_t &inputdata ) |
|
{ |
|
Use( inputdata.pActivator, inputdata.pCaller, USE_TOGGLE, 0 ); |
|
} |
|
|
|
|
|
void CFuncConveyor::InputSetSpeed( inputdata_t &inputdata ) |
|
{ |
|
m_flSpeed = inputdata.value.Float(); |
|
UpdateSpeed( m_flSpeed ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Returns the velocity imparted to players standing on us. |
|
//----------------------------------------------------------------------------- |
|
void CFuncConveyor::GetGroundVelocityToApply( Vector &vecGroundVel ) |
|
{ |
|
vecGroundVel = m_vecMoveDir * m_flSpeed; |
|
} |
|
|
|
|
|
// =================== FUNC_ILLUSIONARY ============================================== |
|
// A simple entity that looks solid but lets you walk through it. |
|
class CFuncIllusionary : public CBaseEntity |
|
{ |
|
DECLARE_CLASS( CFuncIllusionary, CBaseEntity ); |
|
public: |
|
void Spawn( void ); |
|
}; |
|
|
|
LINK_ENTITY_TO_CLASS( func_illusionary, CFuncIllusionary ); |
|
|
|
void CFuncIllusionary::Spawn( void ) |
|
{ |
|
SetLocalAngles( vec3_angle ); |
|
SetMoveType( MOVETYPE_NONE ); |
|
SetSolid( SOLID_NONE ); |
|
SetModel( STRING( GetModelName() ) ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: A rotating brush entity. |
|
// |
|
// You need to have an origin brush as part of this entity. The |
|
// center of that brush will be the point around which it is rotated. |
|
// |
|
// It will rotate around the Z axis by default. Spawnflags can be set |
|
// to make it rotate around the X or Y axes. |
|
// |
|
// The direction of rotation is also controlled by a spawnflag. |
|
//----------------------------------------------------------------------------- |
|
class CFuncRotating : public CBaseEntity |
|
{ |
|
DECLARE_CLASS( CFuncRotating, CBaseEntity ); |
|
public: |
|
// basic functions |
|
void Spawn( void ); |
|
void Precache( void ); |
|
bool CreateVPhysics( void ); |
|
void SpinUpMove( void ); |
|
void SpinDownMove( void ); |
|
bool KeyValue( const char *szKeyName, const char *szValue ); |
|
void HurtTouch ( CBaseEntity *pOther ); |
|
void RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); |
|
void RotateMove( void ); |
|
void ReverseMove( void ); |
|
void RampPitchVol( void ); |
|
void Blocked( CBaseEntity *pOther ); |
|
void SetTargetSpeed( float flSpeed ); |
|
void UpdateSpeed( float flNewSpeed ); |
|
|
|
int DrawDebugTextOverlays(void); |
|
|
|
DECLARE_DATADESC(); |
|
DECLARE_SERVERCLASS(); |
|
|
|
protected: |
|
bool SpinDown( float flTargetSpeed ); |
|
float GetMoveSpeed( float flSpeed ); |
|
|
|
float GetNextMoveInterval() const; |
|
|
|
// Input handlers |
|
void InputSetSpeed( inputdata_t &inputdata ); |
|
void InputStart( inputdata_t &inputdata ); |
|
void InputStop( inputdata_t &inputdata ); |
|
void InputStartForward( inputdata_t &inputdata ); |
|
void InputStartBackward( inputdata_t &inputdata ); |
|
void InputToggle( inputdata_t &inputdata ); |
|
void InputReverse( inputdata_t &inputdata ); |
|
void InputStopAtStartPos( inputdata_t &inputdata ); |
|
|
|
QAngle m_vecMoveAng; |
|
|
|
float m_flFanFriction; |
|
float m_flAttenuation; |
|
float m_flVolume; |
|
float m_flTargetSpeed; // Target value for m_flSpeed, used for spinning up and down. |
|
float m_flMaxSpeed; // Maximum value for m_flSpeed, used for ramping sound effects. |
|
float m_flBlockDamage; // Damage inflicted when blocked. |
|
string_t m_NoiseRunning; |
|
bool m_bReversed; |
|
|
|
QAngle m_angStart; |
|
bool m_bStopAtStartPos; |
|
|
|
bool m_bSolidBsp; // Brush is SOLID_BSP |
|
|
|
public: |
|
Vector m_vecClientOrigin; |
|
QAngle m_vecClientAngles; |
|
}; |
|
|
|
LINK_ENTITY_TO_CLASS( func_rotating, CFuncRotating ); |
|
|
|
|
|
BEGIN_DATADESC( CFuncRotating ) |
|
|
|
DEFINE_FIELD( m_vecMoveAng, FIELD_VECTOR ), |
|
DEFINE_FIELD( m_flFanFriction, FIELD_FLOAT ), |
|
DEFINE_FIELD( m_flAttenuation, FIELD_FLOAT ), |
|
DEFINE_FIELD( m_flVolume, FIELD_FLOAT ), |
|
DEFINE_FIELD( m_flTargetSpeed, FIELD_FLOAT ), |
|
DEFINE_KEYFIELD( m_flMaxSpeed, FIELD_FLOAT, "maxspeed" ), |
|
DEFINE_KEYFIELD( m_flBlockDamage, FIELD_FLOAT, "dmg" ), |
|
DEFINE_KEYFIELD( m_NoiseRunning, FIELD_SOUNDNAME, "message" ), |
|
DEFINE_FIELD( m_bReversed, FIELD_BOOLEAN ), |
|
DEFINE_FIELD( m_angStart, FIELD_VECTOR ), |
|
DEFINE_FIELD( m_bStopAtStartPos, FIELD_BOOLEAN ), |
|
DEFINE_KEYFIELD( m_bSolidBsp, FIELD_BOOLEAN, "solidbsp" ), |
|
|
|
// Function Pointers |
|
DEFINE_FUNCTION( SpinUpMove ), |
|
DEFINE_FUNCTION( SpinDownMove ), |
|
DEFINE_FUNCTION( HurtTouch ), |
|
DEFINE_FUNCTION( RotatingUse ), |
|
DEFINE_FUNCTION( RotateMove ), |
|
DEFINE_FUNCTION( ReverseMove ), |
|
|
|
// Inputs |
|
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetSpeed", InputSetSpeed ), |
|
DEFINE_INPUTFUNC( FIELD_VOID, "Start", InputStart ), |
|
DEFINE_INPUTFUNC( FIELD_VOID, "Stop", InputStop ), |
|
DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ), |
|
DEFINE_INPUTFUNC( FIELD_VOID, "Reverse", InputReverse ), |
|
DEFINE_INPUTFUNC( FIELD_VOID, "StartForward", InputStartForward ), |
|
DEFINE_INPUTFUNC( FIELD_VOID, "StartBackward", InputStartBackward ), |
|
DEFINE_INPUTFUNC( FIELD_VOID, "StopAtStartPos", InputStopAtStartPos ), |
|
|
|
END_DATADESC() |
|
|
|
extern void SendProxy_Origin( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ); |
|
void SendProxy_FuncRotatingOrigin( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ) |
|
{ |
|
#ifdef TF_DLL |
|
CFuncRotating *entity = (CFuncRotating*)pStruct; |
|
Assert( entity ); |
|
|
|
if ( entity->HasSpawnFlags(SF_BRUSH_ROTATE_CLIENTSIDE) ) |
|
{ |
|
const Vector *v = &entity->m_vecClientOrigin; |
|
pOut->m_Vector[ 0 ] = v->x; |
|
pOut->m_Vector[ 1 ] = v->y; |
|
pOut->m_Vector[ 2 ] = v->z; |
|
return; |
|
} |
|
#endif |
|
|
|
SendProxy_Origin( pProp, pStruct, pData, pOut, iElement, objectID ); |
|
} |
|
|
|
/* |
|
extern void SendProxy_Angles( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ); |
|
void SendProxy_FuncRotatingAngles( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID ) |
|
{ |
|
CFuncRotating *entity = (CFuncRotating*)pStruct; |
|
Assert( entity ); |
|
if ( entity->HasSpawnFlags(SF_BRUSH_ROTATE_CLIENTSIDE) ) |
|
{ |
|
const QAngle *a = &entity->m_vecClientAngles; |
|
pOut->m_Vector[ 0 ] = anglemod( a->x ); |
|
pOut->m_Vector[ 1 ] = anglemod( a->y ); |
|
pOut->m_Vector[ 2 ] = anglemod( a->z ); |
|
return; |
|
} |
|
|
|
SendProxy_Angles( pProp, pStruct, pData, pOut, iElement, objectID ); |
|
} |
|
*/ |
|
void SendProxy_FuncRotatingAngle( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID) |
|
{ |
|
CFuncRotating *entity = (CFuncRotating*)pStruct; |
|
Assert( entity ); |
|
|
|
vec_t const *qa = (vec_t *)pData; |
|
vec_t const *ea = entity->GetLocalAngles().Base(); |
|
NOTE_UNUSED(ea); |
|
// Assert its actually an index into m_angRotation if not this won't work |
|
|
|
Assert( (uintp)qa >= (uintp)ea && (uintp)qa < (uintp)ea + sizeof( QAngle )); |
|
|
|
#ifdef TF_DLL |
|
if ( entity->HasSpawnFlags(SF_BRUSH_ROTATE_CLIENTSIDE) ) |
|
{ |
|
const QAngle *a = &entity->m_vecClientAngles; |
|
|
|
pOut->m_Float = anglemod( (*a)[ qa - ea ] ); |
|
return; |
|
} |
|
#endif |
|
|
|
pOut->m_Float = anglemod( *qa ); |
|
|
|
Assert( IsFinite( pOut->m_Float ) ); |
|
} |
|
|
|
|
|
extern void SendProxy_SimulationTime( const SendProp *pProp, const void *pStruct, const void *pVarData, DVariant *pOut, int iElement, int objectID ); |
|
void SendProxy_FuncRotatingSimulationTime( const SendProp *pProp, const void *pStruct, const void *pVarData, DVariant *pOut, int iElement, int objectID ) |
|
{ |
|
#ifdef TF_DLL |
|
CFuncRotating *entity = (CFuncRotating*)pStruct; |
|
Assert( entity ); |
|
|
|
if ( entity->HasSpawnFlags(SF_BRUSH_ROTATE_CLIENTSIDE) ) |
|
{ |
|
pOut->m_Int = 0; |
|
return; |
|
} |
|
#endif |
|
|
|
SendProxy_SimulationTime( pProp, pStruct, pVarData, pOut, iElement, objectID ); |
|
} |
|
|
|
IMPLEMENT_SERVERCLASS_ST(CFuncRotating, DT_FuncRotating) |
|
SendPropExclude( "DT_BaseEntity", "m_angRotation" ), |
|
SendPropExclude( "DT_BaseEntity", "m_vecOrigin" ), |
|
SendPropExclude( "DT_BaseEntity", "m_flSimulationTime" ), |
|
|
|
SendPropVector(SENDINFO(m_vecOrigin), -1, SPROP_COORD|SPROP_CHANGES_OFTEN, 0.0f, HIGH_DEFAULT, SendProxy_FuncRotatingOrigin ), |
|
SendPropAngle( SENDINFO_VECTORELEM(m_angRotation, 0), 13, SPROP_CHANGES_OFTEN, SendProxy_FuncRotatingAngle ), |
|
SendPropAngle( SENDINFO_VECTORELEM(m_angRotation, 1), 13, SPROP_CHANGES_OFTEN, SendProxy_FuncRotatingAngle ), |
|
SendPropAngle( SENDINFO_VECTORELEM(m_angRotation, 2), 13, SPROP_CHANGES_OFTEN, SendProxy_FuncRotatingAngle ), |
|
|
|
SendPropInt(SENDINFO(m_flSimulationTime), SIMULATION_TIME_WINDOW_BITS, SPROP_UNSIGNED|SPROP_CHANGES_OFTEN|SPROP_ENCODED_AGAINST_TICKCOUNT, SendProxy_FuncRotatingSimulationTime), |
|
END_SEND_TABLE() |
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Handles keyvalues from the BSP. Called before spawning. |
|
//----------------------------------------------------------------------------- |
|
bool CFuncRotating::KeyValue( const char *szKeyName, const char *szValue ) |
|
{ |
|
if (FStrEq(szKeyName, "fanfriction")) |
|
{ |
|
m_flFanFriction = atof(szValue)/100; |
|
} |
|
else if (FStrEq(szKeyName, "Volume")) |
|
{ |
|
m_flVolume = atof(szValue) / 10.0; |
|
m_flVolume = clamp(m_flVolume, 0.0f, 1.0f); |
|
} |
|
else |
|
{ |
|
return BaseClass::KeyValue( szKeyName, szValue ); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Called when spawning, after keyvalues have been set. |
|
//----------------------------------------------------------------------------- |
|
void CFuncRotating::Spawn( ) |
|
{ |
|
#ifdef TF_DLL |
|
AddSpawnFlags( SF_BRUSH_ROTATE_CLIENTSIDE ); |
|
#endif |
|
|
|
// |
|
// Maintain compatibility with previous maps. |
|
// |
|
if (m_flVolume == 0.0) |
|
{ |
|
m_flVolume = 1.0; |
|
} |
|
|
|
// |
|
// If the designer didn't set a sound attenuation, default to one. |
|
// |
|
if ( HasSpawnFlags(SF_BRUSH_ROTATE_SMALLRADIUS) ) |
|
{ |
|
m_flAttenuation = ATTN_IDLE; |
|
} |
|
else if ( HasSpawnFlags(SF_BRUSH_ROTATE_MEDIUMRADIUS) ) |
|
{ |
|
m_flAttenuation = ATTN_STATIC; |
|
} |
|
else if ( HasSpawnFlags(SF_BRUSH_ROTATE_LARGERADIUS) ) |
|
{ |
|
m_flAttenuation = ATTN_NORM; |
|
} |
|
else |
|
{ |
|
m_flAttenuation = ATTN_NORM; |
|
} |
|
|
|
// |
|
// Prevent divide by zero if level designer forgets friction! |
|
// |
|
if ( m_flFanFriction == 0 ) |
|
{ |
|
m_flFanFriction = 1; |
|
} |
|
|
|
// |
|
// Build the axis of rotation based on spawnflags. |
|
// |
|
if ( HasSpawnFlags(SF_BRUSH_ROTATE_Z_AXIS) ) |
|
{ |
|
m_vecMoveAng = QAngle(0,0,1); |
|
} |
|
else if ( HasSpawnFlags(SF_BRUSH_ROTATE_X_AXIS) ) |
|
{ |
|
m_vecMoveAng = QAngle(1,0,0); |
|
} |
|
else |
|
{ |
|
m_vecMoveAng = QAngle(0,1,0); // y-axis |
|
} |
|
|
|
// |
|
// Check for reverse rotation. |
|
// |
|
if ( HasSpawnFlags(SF_BRUSH_ROTATE_BACKWARDS) ) |
|
{ |
|
m_vecMoveAng = m_vecMoveAng * -1; |
|
} |
|
|
|
SetSolid( SOLID_VPHYSICS ); |
|
|
|
// |
|
// Some rotating objects like fake volumetric lights will not be solid. |
|
// |
|
if ( HasSpawnFlags(SF_ROTATING_NOT_SOLID) ) |
|
{ |
|
AddSolidFlags( FSOLID_NOT_SOLID ); |
|
SetMoveType( MOVETYPE_PUSH ); |
|
} |
|
else |
|
{ |
|
RemoveSolidFlags( FSOLID_NOT_SOLID ); |
|
SetMoveType( MOVETYPE_PUSH ); |
|
} |
|
|
|
SetModel( STRING( GetModelName() ) ); |
|
|
|
SetUse( &CFuncRotating::RotatingUse ); |
|
|
|
// |
|
// Did level designer forget to assign a maximum speed? Prevent a divide by |
|
// zero in RampPitchVol as well as allowing the rotator to work. |
|
// |
|
m_flMaxSpeed = fabs( m_flMaxSpeed ); |
|
if (m_flMaxSpeed == 0) |
|
{ |
|
m_flMaxSpeed = 100; |
|
} |
|
|
|
// |
|
// If the brush should be initially rotating, use it in a little while. |
|
// |
|
if ( HasSpawnFlags(SF_BRUSH_ROTATE_START_ON) ) |
|
{ |
|
SetThink( &CFuncRotating::SUB_CallUseToggle ); |
|
SetNextThink( gpGlobals->curtime + .2 ); // leave a magic delay for client to start up |
|
} |
|
|
|
// |
|
// Can this brush inflict pain? |
|
// |
|
if ( HasSpawnFlags(SF_BRUSH_HURT) ) |
|
{ |
|
SetTouch( &CFuncRotating::HurtTouch ); |
|
} |
|
|
|
// |
|
// Set speed to 0 in case there's an old "speed" key lying around. |
|
// |
|
m_flSpeed = 0; |
|
|
|
Precache( ); |
|
CreateVPhysics(); |
|
|
|
m_angStart = GetLocalAngles(); |
|
|
|
// Slam the object back to solid - if we really want it to be solid. |
|
if ( m_bSolidBsp ) |
|
{ |
|
SetSolid( SOLID_BSP ); |
|
} |
|
|
|
#ifdef TF_DLL |
|
if ( HasSpawnFlags(SF_BRUSH_ROTATE_CLIENTSIDE) ) |
|
{ |
|
m_vecClientOrigin = GetLocalOrigin(); |
|
m_vecClientAngles = GetLocalAngles(); |
|
} |
|
#endif |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CFuncRotating::CreateVPhysics( void ) |
|
{ |
|
if ( !IsSolidFlagSet( FSOLID_NOT_SOLID )) |
|
{ |
|
VPhysicsInitShadow( false, false ); |
|
} |
|
return true; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CFuncRotating::Precache( void ) |
|
{ |
|
// |
|
// Set up rotation sound. |
|
// |
|
char *szSoundFile = ( char * )STRING( m_NoiseRunning ); |
|
if ( !m_NoiseRunning || strlen( szSoundFile ) == 0 ) |
|
{ |
|
// No sound set up, use the null sound. |
|
m_NoiseRunning = AllocPooledString("DoorSound.Null"); |
|
} |
|
PrecacheScriptSound( STRING( m_NoiseRunning ) ); |
|
|
|
if (GetLocalAngularVelocity() != vec3_angle ) |
|
{ |
|
// |
|
// If fan was spinning, and we went through transition or save/restore, |
|
// make sure we restart the sound. 1.5 sec delay is a magic number. |
|
// |
|
SetMoveDone( &CFuncRotating::SpinUpMove ); |
|
SetMoveDoneTime( 1.5 ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Will hurt others based on how fast the brush is spinning. |
|
// Input : pOther - |
|
//----------------------------------------------------------------------------- |
|
void CFuncRotating::HurtTouch ( CBaseEntity *pOther ) |
|
{ |
|
// we can't hurt this thing, so we're not concerned with it |
|
if ( !pOther->m_takedamage ) |
|
return; |
|
|
|
// calculate damage based on rotation speed |
|
m_flBlockDamage = GetLocalAngularVelocity().Length() / 10; |
|
|
|
#ifdef HL1_DLL |
|
if( m_flBlockDamage > 0 ) |
|
#endif |
|
{ |
|
pOther->TakeDamage( CTakeDamageInfo( this, this, m_flBlockDamage, DMG_CRUSH ) ); |
|
|
|
Vector vecNewVelocity = pOther->GetAbsOrigin() - WorldSpaceCenter(); |
|
VectorNormalize(vecNewVelocity); |
|
vecNewVelocity *= m_flBlockDamage; |
|
pOther->SetAbsVelocity( vecNewVelocity ); |
|
} |
|
} |
|
|
|
|
|
#define FANPITCHMIN 30 |
|
#define FANPITCHMAX 100 |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Ramp pitch and volume up to maximum values, based on the difference |
|
// between how fast we're going vs how fast we can go. |
|
//----------------------------------------------------------------------------- |
|
void CFuncRotating::RampPitchVol( void ) |
|
{ |
|
// |
|
// Calc volume and pitch as % of maximum vol and pitch. |
|
// |
|
float fpct = fabs(m_flSpeed) / m_flMaxSpeed; |
|
float fvol = clamp(m_flVolume * fpct, 0.f, 1.f); // slowdown volume ramps down to 0 |
|
|
|
float fpitch = FANPITCHMIN + (FANPITCHMAX - FANPITCHMIN) * fpct; |
|
|
|
int pitch = clamp(FastFloatToSmallInt(fpitch), 0, 255); |
|
if (pitch == PITCH_NORM) |
|
{ |
|
pitch = PITCH_NORM - 1; |
|
} |
|
|
|
// |
|
// Update the fan's volume and pitch. |
|
// |
|
CPASAttenuationFilter filter( GetAbsOrigin(), m_flAttenuation ); |
|
filter.MakeReliable(); |
|
|
|
EmitSound_t ep; |
|
ep.m_nChannel = CHAN_STATIC; |
|
ep.m_pSoundName = STRING(m_NoiseRunning); |
|
ep.m_flVolume = fvol; |
|
ep.m_SoundLevel = ATTN_TO_SNDLVL( m_flAttenuation ); |
|
ep.m_nFlags = SND_CHANGE_PITCH | SND_CHANGE_VOL; |
|
ep.m_nPitch = pitch; |
|
|
|
EmitSound( filter, entindex(), ep ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Output : float |
|
//----------------------------------------------------------------------------- |
|
float CFuncRotating::GetNextMoveInterval() const |
|
{ |
|
if ( m_bStopAtStartPos ) |
|
{ |
|
return TICK_INTERVAL; |
|
} |
|
return 0.1f; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Sets the current speed to the given value and manages the sound effects. |
|
// Input : flNewSpeed - New speed in degrees per second. |
|
//----------------------------------------------------------------------------- |
|
void CFuncRotating::UpdateSpeed( float flNewSpeed ) |
|
{ |
|
float flOldSpeed = m_flSpeed; |
|
m_flSpeed = clamp( flNewSpeed, -m_flMaxSpeed, m_flMaxSpeed ); |
|
|
|
if ( m_bStopAtStartPos ) |
|
{ |
|
int checkAxis = 2; |
|
// See if we got close to the starting orientation |
|
if ( m_vecMoveAng[0] != 0 ) |
|
{ |
|
checkAxis = 0; |
|
} |
|
else if ( m_vecMoveAng[1] != 0 ) |
|
{ |
|
checkAxis = 1; |
|
} |
|
|
|
float angDelta = anglemod( GetLocalAngles()[ checkAxis ] - m_angStart[ checkAxis ] ); |
|
if ( angDelta > 180.0f ) |
|
{ |
|
angDelta -= 360.0f; |
|
} |
|
|
|
if ( flNewSpeed < 100 ) |
|
{ |
|
if ( flNewSpeed <= 25 && fabs( angDelta ) < 1.0f ) |
|
{ |
|
m_flTargetSpeed = 0; |
|
m_bStopAtStartPos = false; |
|
m_flSpeed = 0.0f; |
|
|
|
SetLocalAngles( m_angStart ); |
|
} |
|
else if ( fabs( angDelta ) > 90.0f ) |
|
{ |
|
// Keep rotating at same speed for now |
|
m_flSpeed = flOldSpeed; |
|
} |
|
else |
|
{ |
|
float minSpeed = fabs( angDelta ); |
|
if ( minSpeed < 20 ) |
|
minSpeed = 20; |
|
|
|
m_flSpeed = flOldSpeed > 0.0f ? minSpeed : -minSpeed; |
|
} |
|
} |
|
} |
|
|
|
|
|
if ( ( flOldSpeed == 0 ) && ( m_flSpeed != 0 ) ) |
|
{ |
|
// Starting to move - emit the sound. |
|
CPASAttenuationFilter filter( GetAbsOrigin(), m_flAttenuation ); |
|
filter.MakeReliable(); |
|
|
|
EmitSound_t ep; |
|
ep.m_nChannel = CHAN_STATIC; |
|
ep.m_pSoundName = STRING(m_NoiseRunning); |
|
ep.m_flVolume = 0.01; |
|
ep.m_SoundLevel = ATTN_TO_SNDLVL( m_flAttenuation ); |
|
ep.m_nPitch = FANPITCHMIN; |
|
|
|
EmitSound( filter, entindex(), ep ); |
|
RampPitchVol(); |
|
} |
|
else if ( ( flOldSpeed != 0 ) && ( m_flSpeed == 0 ) ) |
|
{ |
|
// Stopping - stop the sound. |
|
StopSound( entindex(), CHAN_STATIC, STRING(m_NoiseRunning) ); |
|
|
|
} |
|
else |
|
{ |
|
// Changing speed - adjust the pitch and volume. |
|
RampPitchVol(); |
|
} |
|
|
|
SetLocalAngularVelocity( m_vecMoveAng * m_flSpeed ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Think function. Accelerates a func_rotating to a higher angular velocity. |
|
//----------------------------------------------------------------------------- |
|
void CFuncRotating::SpinUpMove( void ) |
|
{ |
|
// |
|
// Calculate our new speed. |
|
// |
|
bool bSpinUpDone = false; |
|
float flNewSpeed = fabs( m_flSpeed ) + 0.2 * m_flMaxSpeed * m_flFanFriction; |
|
if ( fabs( flNewSpeed ) >= fabs( m_flTargetSpeed ) ) |
|
{ |
|
// Reached our target speed. |
|
flNewSpeed = m_flTargetSpeed; |
|
bSpinUpDone = !m_bStopAtStartPos; |
|
} |
|
else if ( m_flTargetSpeed < 0 ) |
|
{ |
|
// Spinning up in reverse - negate the speed. |
|
flNewSpeed *= -1; |
|
} |
|
|
|
// |
|
// Apply the new speed, adjust sound pitch and volume. |
|
// |
|
UpdateSpeed( flNewSpeed ); |
|
|
|
// |
|
// If we've met or exceeded target speed, stop spinning up. |
|
// |
|
if ( bSpinUpDone ) |
|
{ |
|
SetMoveDone( &CFuncRotating::RotateMove ); |
|
RotateMove(); |
|
} |
|
|
|
SetMoveDoneTime( GetNextMoveInterval() ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Decelerates the rotator from a higher speed to a lower one. |
|
// Input : flTargetSpeed - Speed to spin down to. |
|
// Output : Returns true if we reached the target speed, false otherwise. |
|
//----------------------------------------------------------------------------- |
|
bool CFuncRotating::SpinDown( float flTargetSpeed ) |
|
{ |
|
// |
|
// Bleed off a little speed due to friction. |
|
// |
|
bool bSpinDownDone = false; |
|
float flNewSpeed = fabs( m_flSpeed ) - 0.1 * m_flMaxSpeed * m_flFanFriction; |
|
if ( flNewSpeed < 0 ) |
|
{ |
|
flNewSpeed = 0; |
|
} |
|
|
|
if ( fabs( flNewSpeed ) <= fabs( flTargetSpeed ) ) |
|
{ |
|
// Reached our target speed. |
|
flNewSpeed = flTargetSpeed; |
|
bSpinDownDone = !m_bStopAtStartPos; |
|
} |
|
else if ( m_flSpeed < 0 ) |
|
{ |
|
// Spinning down in reverse - negate the speed. |
|
flNewSpeed *= -1; |
|
} |
|
|
|
// |
|
// Apply the new speed, adjust sound pitch and volume. |
|
// |
|
UpdateSpeed( flNewSpeed ); |
|
|
|
// |
|
// If we've met or exceeded target speed, stop spinning down. |
|
// |
|
return bSpinDownDone; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Think function. Decelerates a func_rotating to a lower angular velocity. |
|
//----------------------------------------------------------------------------- |
|
void CFuncRotating::SpinDownMove( void ) |
|
{ |
|
// |
|
// If we've met or exceeded target speed, stop spinning down. |
|
// |
|
if ( SpinDown( m_flTargetSpeed ) ) |
|
{ |
|
SetMoveDone( &CFuncRotating::RotateMove ); |
|
RotateMove(); |
|
} |
|
else |
|
{ |
|
SetMoveDoneTime( GetNextMoveInterval() ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Think function for reversing directions. Spins down to zero, then |
|
// starts spinning up to the target speed. |
|
//----------------------------------------------------------------------------- |
|
void CFuncRotating::ReverseMove( void ) |
|
{ |
|
if ( SpinDown( 0 ) ) |
|
{ |
|
// We've reached zero - spin back up to the target speed. |
|
SetTargetSpeed( m_flTargetSpeed ); |
|
} |
|
else |
|
{ |
|
SetMoveDoneTime( GetNextMoveInterval() ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Think function. Called while rotating at a constant angular velocity. |
|
//----------------------------------------------------------------------------- |
|
void CFuncRotating::RotateMove( void ) |
|
{ |
|
SetMoveDoneTime( 10 ); |
|
|
|
if ( m_bStopAtStartPos ) |
|
{ |
|
SetMoveDoneTime( GetNextMoveInterval() ); |
|
int checkAxis = 2; |
|
|
|
// See if we got close to the starting orientation |
|
if ( m_vecMoveAng[0] != 0 ) |
|
{ |
|
checkAxis = 0; |
|
} |
|
else if ( m_vecMoveAng[1] != 0 ) |
|
{ |
|
checkAxis = 1; |
|
} |
|
|
|
float angDelta = anglemod( GetLocalAngles()[ checkAxis ] - m_angStart[ checkAxis ] ); |
|
if ( angDelta > 180.0f ) |
|
angDelta -= 360.0f; |
|
|
|
QAngle avel = GetLocalAngularVelocity(); |
|
// Delta per tick |
|
QAngle avelpertick = avel * TICK_INTERVAL; |
|
|
|
if ( fabs( angDelta ) < fabs( avelpertick[ checkAxis ] ) ) |
|
{ |
|
SetTargetSpeed( 0 ); |
|
SetLocalAngles( m_angStart ); |
|
m_bStopAtStartPos = false; |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Used for debug output. Returns the given speed considering our current |
|
// direction of rotation, so that positive values are forward and negative |
|
// values are backward. |
|
// Input : flSpeed - Angular speed in degrees per second. |
|
//----------------------------------------------------------------------------- |
|
float CFuncRotating::GetMoveSpeed( float flSpeed ) |
|
{ |
|
if ( m_vecMoveAng[0] != 0 ) |
|
{ |
|
return flSpeed * m_vecMoveAng[0]; |
|
} |
|
|
|
if ( m_vecMoveAng[1] != 0 ) |
|
{ |
|
return flSpeed * m_vecMoveAng[1]; |
|
} |
|
|
|
return flSpeed * m_vecMoveAng[2]; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Sets a new angular velocity to achieve. |
|
// Input : flSpeed - Target angular velocity in degrees per second. |
|
//----------------------------------------------------------------------------- |
|
void CFuncRotating::SetTargetSpeed( float flSpeed ) |
|
{ |
|
// |
|
// Make sure the sign is correct - positive for forward rotation, |
|
// negative for reverse rotation. |
|
// |
|
flSpeed = fabs( flSpeed ); |
|
if ( m_bReversed ) |
|
{ |
|
flSpeed *= -1; |
|
} |
|
|
|
m_flTargetSpeed = flSpeed; |
|
|
|
// |
|
// If we don't accelerate, change to the new speed instantly. |
|
// |
|
if ( !HasSpawnFlags(SF_BRUSH_ACCDCC ) ) |
|
{ |
|
UpdateSpeed( m_flTargetSpeed ); |
|
SetMoveDone( &CFuncRotating::RotateMove ); |
|
} |
|
// |
|
// Otherwise deal with acceleration/deceleration: |
|
// |
|
else |
|
{ |
|
// |
|
// Check for reversing directions. |
|
// |
|
if ((( m_flSpeed > 0 ) && ( m_flTargetSpeed < 0 )) || |
|
(( m_flSpeed < 0 ) && ( m_flTargetSpeed > 0 ))) |
|
{ |
|
SetMoveDone( &CFuncRotating::ReverseMove ); |
|
} |
|
// |
|
// If we are below the new target speed, spin up to the target speed. |
|
// |
|
else if ( fabs( m_flSpeed ) < fabs( m_flTargetSpeed ) ) |
|
{ |
|
SetMoveDone( &CFuncRotating::SpinUpMove ); |
|
} |
|
// |
|
// If we are above the new target speed, spin down to the target speed. |
|
// |
|
else if ( fabs( m_flSpeed ) > fabs( m_flTargetSpeed ) ) |
|
{ |
|
SetMoveDone( &CFuncRotating::SpinDownMove ); |
|
} |
|
// |
|
// We are already at the new target speed. Just keep rotating. |
|
// |
|
else |
|
{ |
|
SetMoveDone( &CFuncRotating::RotateMove ); |
|
} |
|
} |
|
|
|
SetMoveDoneTime( GetNextMoveInterval() ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Called when a rotating brush is used by the player. |
|
// Input : pActivator - |
|
// pCaller - |
|
// useType - |
|
// value - |
|
//----------------------------------------------------------------------------- |
|
void CFuncRotating::RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) |
|
{ |
|
// |
|
// If the rotator is spinning, stop it. |
|
// |
|
if ( m_flSpeed != 0 ) |
|
{ |
|
SetTargetSpeed( 0 ); |
|
} |
|
// |
|
// Rotator is not moving, so start it. |
|
// |
|
else |
|
{ |
|
SetTargetSpeed( m_flMaxSpeed ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Input handler that reverses the direction of rotation. |
|
//----------------------------------------------------------------------------- |
|
void CFuncRotating::InputReverse( inputdata_t &inputdata ) |
|
{ |
|
m_bStopAtStartPos = false; |
|
m_bReversed = !m_bReversed; |
|
SetTargetSpeed( m_flSpeed ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Input handler for setting the speed of the rotator. |
|
// Input : Float target angular velocity as a ratio of maximum speed [0, 1]. |
|
//----------------------------------------------------------------------------- |
|
void CFuncRotating::InputSetSpeed( inputdata_t &inputdata ) |
|
{ |
|
m_bStopAtStartPos = false; |
|
float flSpeed = inputdata.value.Float(); |
|
m_bReversed = flSpeed < 0 ? true : false; |
|
flSpeed = fabs(flSpeed); |
|
SetTargetSpeed( clamp( flSpeed, 0.f, 1.f ) * m_flMaxSpeed ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Input handler to start the rotator spinning. |
|
//----------------------------------------------------------------------------- |
|
void CFuncRotating::InputStart( inputdata_t &inputdata ) |
|
{ |
|
m_bStopAtStartPos = false; |
|
SetTargetSpeed( m_flMaxSpeed ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Input handler to start the rotator spinning. |
|
//----------------------------------------------------------------------------- |
|
void CFuncRotating::InputStartForward( inputdata_t &inputdata ) |
|
{ |
|
m_bReversed = false; |
|
SetTargetSpeed( m_flMaxSpeed ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Input handler to start the rotator spinning. |
|
//----------------------------------------------------------------------------- |
|
void CFuncRotating::InputStartBackward( inputdata_t &inputdata ) |
|
{ |
|
m_bStopAtStartPos = false; |
|
m_bReversed = true; |
|
SetTargetSpeed( m_flMaxSpeed ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Input handler to stop the rotator from spinning. |
|
//----------------------------------------------------------------------------- |
|
void CFuncRotating::InputStop( inputdata_t &inputdata ) |
|
{ |
|
m_bStopAtStartPos = false; |
|
SetTargetSpeed( 0 ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : &inputdata - |
|
//----------------------------------------------------------------------------- |
|
void CFuncRotating::InputStopAtStartPos( inputdata_t &inputdata ) |
|
{ |
|
m_bStopAtStartPos = true; |
|
SetTargetSpeed( 0 ); |
|
SetMoveDoneTime( GetNextMoveInterval() ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Starts the rotator if it is still, stops it if it is spinning. |
|
//----------------------------------------------------------------------------- |
|
void CFuncRotating::InputToggle( inputdata_t &inputdata ) |
|
{ |
|
if (m_flSpeed > 0) |
|
{ |
|
SetTargetSpeed( 0 ); |
|
} |
|
else |
|
{ |
|
SetTargetSpeed( m_flMaxSpeed ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: An entity has blocked the brush. |
|
// Input : pOther - |
|
//----------------------------------------------------------------------------- |
|
void CFuncRotating::Blocked( CBaseEntity *pOther ) |
|
{ |
|
#ifdef HL1_DLL |
|
if( m_flBlockDamage > 0 ) |
|
#endif |
|
pOther->TakeDamage( CTakeDamageInfo( this, this, m_flBlockDamage, DMG_CRUSH ) ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Draw any debug text overlays |
|
// Input : |
|
// Output : Current text offset from the top |
|
//----------------------------------------------------------------------------- |
|
int CFuncRotating::DrawDebugTextOverlays(void) |
|
{ |
|
int text_offset = BaseClass::DrawDebugTextOverlays(); |
|
|
|
if (m_debugOverlays & OVERLAY_TEXT_BIT) |
|
{ |
|
char tempstr[512]; |
|
Q_snprintf( tempstr, sizeof( tempstr ),"Speed cur (target): %3.2f (%3.2f)", GetMoveSpeed( m_flSpeed ), GetMoveSpeed( m_flTargetSpeed ) ); |
|
EntityText(text_offset,tempstr,0); |
|
text_offset++; |
|
} |
|
return text_offset; |
|
|
|
} |
|
|
|
|
|
class CFuncVPhysicsClip : public CBaseEntity |
|
{ |
|
DECLARE_DATADESC(); |
|
DECLARE_CLASS( CFuncVPhysicsClip, CBaseEntity ); |
|
|
|
public: |
|
void Spawn(); |
|
void Activate(); |
|
bool CreateVPhysics( void ); |
|
|
|
bool EntityPassesFilter( CBaseEntity *pOther ); |
|
bool ForceVPhysicsCollide( CBaseEntity *pEntity ); |
|
|
|
void InputEnable( inputdata_t &inputdata ); |
|
void InputDisable( inputdata_t &inputdata ); |
|
|
|
private: |
|
|
|
string_t m_iFilterName; |
|
CHandle<CBaseFilter> m_hFilter; |
|
bool m_bDisabled; |
|
}; |
|
|
|
// Global Savedata for base trigger |
|
BEGIN_DATADESC( CFuncVPhysicsClip ) |
|
|
|
// Keyfields |
|
DEFINE_KEYFIELD( m_iFilterName, FIELD_STRING, "filtername" ), |
|
DEFINE_FIELD( m_hFilter, FIELD_EHANDLE ), |
|
DEFINE_FIELD( m_bDisabled, FIELD_BOOLEAN ), |
|
|
|
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ), |
|
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ), |
|
|
|
END_DATADESC() |
|
|
|
|
|
LINK_ENTITY_TO_CLASS( func_clip_vphysics, CFuncVPhysicsClip ); |
|
|
|
void CFuncVPhysicsClip::Spawn( void ) |
|
{ |
|
SetMoveType( MOVETYPE_PUSH ); // so it doesn't get pushed by anything |
|
SetSolid( SOLID_VPHYSICS ); |
|
AddSolidFlags( FSOLID_NOT_SOLID ); |
|
SetModel( STRING( GetModelName() ) ); |
|
AddEffects( EF_NODRAW ); |
|
CreateVPhysics(); |
|
VPhysicsGetObject()->EnableCollisions( !m_bDisabled ); |
|
} |
|
|
|
|
|
bool CFuncVPhysicsClip::CreateVPhysics( void ) |
|
{ |
|
VPhysicsInitStatic(); |
|
return true; |
|
} |
|
|
|
|
|
void CFuncVPhysicsClip::Activate( void ) |
|
{ |
|
// Get a handle to my filter entity if there is one |
|
if (m_iFilterName != NULL_STRING) |
|
{ |
|
m_hFilter = dynamic_cast<CBaseFilter *>(gEntList.FindEntityByName( NULL, m_iFilterName )); |
|
} |
|
BaseClass::Activate(); |
|
} |
|
|
|
bool CFuncVPhysicsClip::EntityPassesFilter( CBaseEntity *pOther ) |
|
{ |
|
CBaseFilter* pFilter = (CBaseFilter*)(m_hFilter.Get()); |
|
|
|
if ( pFilter ) |
|
return pFilter->PassesFilter( this, pOther ); |
|
|
|
if ( pOther->GetMoveType() == MOVETYPE_VPHYSICS && pOther->VPhysicsGetObject()->IsMoveable() ) |
|
return true; |
|
|
|
return false; |
|
} |
|
|
|
|
|
bool CFuncVPhysicsClip::ForceVPhysicsCollide( CBaseEntity *pEntity ) |
|
{ |
|
return EntityPassesFilter(pEntity); |
|
} |
|
|
|
void CFuncVPhysicsClip::InputEnable( inputdata_t &inputdata ) |
|
{ |
|
VPhysicsGetObject()->EnableCollisions(true); |
|
m_bDisabled = false; |
|
} |
|
|
|
void CFuncVPhysicsClip::InputDisable( inputdata_t &inputdata ) |
|
{ |
|
VPhysicsGetObject()->EnableCollisions(false); |
|
m_bDisabled = true; |
|
}
|
|
|