Team Fortress 2 Source Code as on 22/4/2020
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

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Spawn, think, and use functions for common brush entities.
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "doors.h"
  8. #include "mathlib/mathlib.h"
  9. #include "physics.h"
  10. #include "ndebugoverlay.h"
  11. #include "engine/IEngineSound.h"
  12. #include "globals.h"
  13. #include "filters.h"
  14. // memdbgon must be the last include file in a .cpp file!!!
  15. #include "tier0/memdbgon.h"
  16. #define SF_BRUSH_ACCDCC 16// brush should accelerate and decelerate when toggled
  17. #define SF_BRUSH_HURT 32// rotating brush that inflicts pain based on rotation speed
  18. #define SF_ROTATING_NOT_SOLID 64 // some special rotating objects are not solid.
  19. // =================== FUNC_WALL ==============================================
  20. class CFuncWall : public CBaseEntity
  21. {
  22. public:
  23. DECLARE_DATADESC();
  24. DECLARE_CLASS( CFuncWall, CBaseEntity );
  25. void Spawn( void );
  26. bool CreateVPhysics( void );
  27. void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
  28. int m_nState;
  29. };
  30. LINK_ENTITY_TO_CLASS( func_wall, CFuncWall );
  31. //---------------------------------------------------------
  32. // Save/Restore
  33. //---------------------------------------------------------
  34. BEGIN_DATADESC( CFuncWall )
  35. DEFINE_FIELD( m_nState, FIELD_INTEGER ),
  36. END_DATADESC()
  37. void CFuncWall::Spawn( void )
  38. {
  39. SetLocalAngles( vec3_angle );
  40. SetMoveType( MOVETYPE_PUSH ); // so it doesn't get pushed by anything
  41. SetModel( STRING( GetModelName() ) );
  42. // If it can't move/go away, it's really part of the world
  43. AddFlag( FL_WORLDBRUSH );
  44. // set manual mode
  45. CreateVPhysics();
  46. }
  47. bool CFuncWall::CreateVPhysics( void )
  48. {
  49. SetSolid( SOLID_BSP );
  50. IPhysicsObject *pPhys = VPhysicsInitStatic();
  51. if ( pPhys )
  52. {
  53. int contents = modelinfo->GetModelContents( GetModelIndex() );
  54. if ( ! (contents & (MASK_SOLID|MASK_PLAYERSOLID|MASK_NPCSOLID)) )
  55. {
  56. // leave the physics shadow there in case it has crap constrained to it
  57. // but disable collisions with it
  58. pPhys->EnableCollisions( false );
  59. }
  60. }
  61. return true;
  62. }
  63. void CFuncWall::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  64. {
  65. if ( ShouldToggle( useType, m_nState ) )
  66. {
  67. m_nState = 1 - m_nState;
  68. }
  69. }
  70. #define SF_WALL_START_OFF 0x0001
  71. class CFuncWallToggle : public CFuncWall
  72. {
  73. public:
  74. DECLARE_CLASS( CFuncWallToggle, CFuncWall );
  75. DECLARE_DATADESC();
  76. void Spawn( void );
  77. void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
  78. void InputToggle( inputdata_t &inputdata );
  79. void TurnOff( void );
  80. void TurnOn( void );
  81. bool IsOn( void );
  82. };
  83. BEGIN_DATADESC( CFuncWallToggle )
  84. DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),
  85. END_DATADESC()
  86. LINK_ENTITY_TO_CLASS( func_wall_toggle, CFuncWallToggle );
  87. void CFuncWallToggle::Spawn( void )
  88. {
  89. BaseClass::Spawn();
  90. if ( HasSpawnFlags( SF_WALL_START_OFF ) )
  91. TurnOff();
  92. SetMoveType( MOVETYPE_PUSH );
  93. }
  94. void CFuncWallToggle::TurnOff( void )
  95. {
  96. IPhysicsObject *pPhys = VPhysicsGetObject();
  97. if ( pPhys )
  98. {
  99. pPhys->EnableCollisions( false );
  100. }
  101. AddSolidFlags( FSOLID_NOT_SOLID );
  102. AddEffects( EF_NODRAW );
  103. }
  104. void CFuncWallToggle::TurnOn( void )
  105. {
  106. IPhysicsObject *pPhys = VPhysicsGetObject();
  107. if ( pPhys )
  108. {
  109. pPhys->EnableCollisions( true );
  110. }
  111. RemoveSolidFlags( FSOLID_NOT_SOLID );
  112. RemoveEffects( EF_NODRAW );
  113. }
  114. bool CFuncWallToggle::IsOn( void )
  115. {
  116. if ( IsSolidFlagSet( FSOLID_NOT_SOLID ) )
  117. return false;
  118. return true;
  119. }
  120. void CFuncWallToggle::InputToggle( inputdata_t &inputdata )
  121. {
  122. int status = IsOn();
  123. if ( ShouldToggle( USE_TOGGLE, status ) )
  124. {
  125. if ( status )
  126. TurnOff();
  127. else
  128. TurnOn();
  129. }
  130. }
  131. //Adrian - Is this function needed at all?
  132. void CFuncWallToggle::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  133. {
  134. int status = IsOn();
  135. if ( ShouldToggle( useType, status ) )
  136. {
  137. if ( status )
  138. TurnOff();
  139. else
  140. TurnOn();
  141. }
  142. }
  143. //============================== FUNC_VEHICLECLIP =====================================
  144. class CFuncVehicleClip : public CBaseEntity
  145. {
  146. public:
  147. DECLARE_CLASS( CFuncVehicleClip, CBaseEntity );
  148. DECLARE_DATADESC();
  149. void Spawn();
  150. bool CreateVPhysics( void );
  151. void InputEnable( inputdata_t &data );
  152. void InputDisable( inputdata_t &data );
  153. private:
  154. };
  155. BEGIN_DATADESC( CFuncVehicleClip )
  156. DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
  157. DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
  158. END_DATADESC()
  159. LINK_ENTITY_TO_CLASS( func_vehicleclip, CFuncVehicleClip );
  160. void CFuncVehicleClip::Spawn()
  161. {
  162. SetLocalAngles( vec3_angle );
  163. SetMoveType( MOVETYPE_PUSH ); // so it doesn't get pushed by anything
  164. SetModel( STRING( GetModelName() ) );
  165. // It's part of the world
  166. AddFlag( FL_WORLDBRUSH );
  167. CreateVPhysics();
  168. AddEffects( EF_NODRAW ); // make entity invisible
  169. SetCollisionGroup( COLLISION_GROUP_VEHICLE_CLIP );
  170. }
  171. bool CFuncVehicleClip::CreateVPhysics( void )
  172. {
  173. SetSolid( SOLID_BSP );
  174. VPhysicsInitStatic();
  175. return true;
  176. }
  177. void CFuncVehicleClip::InputEnable( inputdata_t &data )
  178. {
  179. IPhysicsObject *pPhys = VPhysicsGetObject();
  180. if ( pPhys )
  181. {
  182. pPhys->EnableCollisions( true );
  183. }
  184. RemoveSolidFlags( FSOLID_NOT_SOLID );
  185. }
  186. void CFuncVehicleClip::InputDisable( inputdata_t &data )
  187. {
  188. IPhysicsObject *pPhys = VPhysicsGetObject();
  189. if ( pPhys )
  190. {
  191. pPhys->EnableCollisions( false );
  192. }
  193. AddSolidFlags( FSOLID_NOT_SOLID );
  194. }
  195. //============================= FUNC_CONVEYOR =======================================
  196. #define SF_CONVEYOR_VISUAL 0x0001
  197. #define SF_CONVEYOR_NOTSOLID 0x0002
  198. class CFuncConveyor : public CFuncWall
  199. {
  200. public:
  201. DECLARE_CLASS( CFuncConveyor, CFuncWall );
  202. DECLARE_DATADESC();
  203. DECLARE_SERVERCLASS();
  204. CFuncConveyor();
  205. void Spawn( void );
  206. void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
  207. void UpdateSpeed( float flNewSpeed );
  208. void GetGroundVelocityToApply( Vector &vecGroundVel );
  209. // Input handlers.
  210. void InputToggleDirection( inputdata_t &inputdata );
  211. void InputSetSpeed( inputdata_t &inputdata );
  212. private:
  213. Vector m_vecMoveDir;
  214. CNetworkVar( float, m_flConveyorSpeed );
  215. };
  216. LINK_ENTITY_TO_CLASS( func_conveyor, CFuncConveyor );
  217. BEGIN_DATADESC( CFuncConveyor )
  218. DEFINE_INPUTFUNC( FIELD_VOID, "ToggleDirection", InputToggleDirection ),
  219. DEFINE_INPUTFUNC( FIELD_VOID, "SetSpeed", InputSetSpeed ),
  220. DEFINE_KEYFIELD( m_vecMoveDir, FIELD_VECTOR, "movedir" ),
  221. DEFINE_FIELD( m_flConveyorSpeed, FIELD_FLOAT ),
  222. END_DATADESC()
  223. IMPLEMENT_SERVERCLASS_ST(CFuncConveyor, DT_FuncConveyor)
  224. SendPropFloat( SENDINFO(m_flConveyorSpeed), 0, SPROP_NOSCALE ),
  225. END_SEND_TABLE()
  226. CFuncConveyor::CFuncConveyor()
  227. {
  228. m_flConveyorSpeed = 0.0;
  229. }
  230. void CFuncConveyor::Spawn( void )
  231. {
  232. // Convert movedir from angles to a vector
  233. QAngle angMoveDir = QAngle( m_vecMoveDir.x, m_vecMoveDir.y, m_vecMoveDir.z );
  234. AngleVectors( angMoveDir, &m_vecMoveDir );
  235. BaseClass::Spawn();
  236. if ( !HasSpawnFlags(SF_CONVEYOR_VISUAL) )
  237. AddFlag( FL_CONVEYOR );
  238. // HACKHACK - This is to allow for some special effects
  239. if ( HasSpawnFlags( SF_CONVEYOR_NOTSOLID ) )
  240. {
  241. AddSolidFlags( FSOLID_NOT_SOLID );
  242. }
  243. if ( m_flSpeed == 0 )
  244. m_flSpeed = 100;
  245. UpdateSpeed( m_flSpeed );
  246. }
  247. void CFuncConveyor::UpdateSpeed( float flNewSpeed )
  248. {
  249. m_flConveyorSpeed = flNewSpeed;
  250. }
  251. void CFuncConveyor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  252. {
  253. m_flSpeed = -m_flSpeed;
  254. UpdateSpeed( m_flSpeed );
  255. }
  256. void CFuncConveyor::InputToggleDirection( inputdata_t &inputdata )
  257. {
  258. Use( inputdata.pActivator, inputdata.pCaller, USE_TOGGLE, 0 );
  259. }
  260. void CFuncConveyor::InputSetSpeed( inputdata_t &inputdata )
  261. {
  262. m_flSpeed = inputdata.value.Float();
  263. UpdateSpeed( m_flSpeed );
  264. }
  265. //-----------------------------------------------------------------------------
  266. // Purpose: Returns the velocity imparted to players standing on us.
  267. //-----------------------------------------------------------------------------
  268. void CFuncConveyor::GetGroundVelocityToApply( Vector &vecGroundVel )
  269. {
  270. vecGroundVel = m_vecMoveDir * m_flSpeed;
  271. }
  272. // =================== FUNC_ILLUSIONARY ==============================================
  273. // A simple entity that looks solid but lets you walk through it.
  274. class CFuncIllusionary : public CBaseEntity
  275. {
  276. DECLARE_CLASS( CFuncIllusionary, CBaseEntity );
  277. public:
  278. void Spawn( void );
  279. };
  280. LINK_ENTITY_TO_CLASS( func_illusionary, CFuncIllusionary );
  281. void CFuncIllusionary::Spawn( void )
  282. {
  283. SetLocalAngles( vec3_angle );
  284. SetMoveType( MOVETYPE_NONE );
  285. SetSolid( SOLID_NONE );
  286. SetModel( STRING( GetModelName() ) );
  287. }
  288. //-----------------------------------------------------------------------------
  289. // Purpose: A rotating brush entity.
  290. //
  291. // You need to have an origin brush as part of this entity. The
  292. // center of that brush will be the point around which it is rotated.
  293. //
  294. // It will rotate around the Z axis by default. Spawnflags can be set
  295. // to make it rotate around the X or Y axes.
  296. //
  297. // The direction of rotation is also controlled by a spawnflag.
  298. //-----------------------------------------------------------------------------
  299. class CFuncRotating : public CBaseEntity
  300. {
  301. DECLARE_CLASS( CFuncRotating, CBaseEntity );
  302. public:
  303. // basic functions
  304. void Spawn( void );
  305. void Precache( void );
  306. bool CreateVPhysics( void );
  307. void SpinUpMove( void );
  308. void SpinDownMove( void );
  309. bool KeyValue( const char *szKeyName, const char *szValue );
  310. void HurtTouch ( CBaseEntity *pOther );
  311. void RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
  312. void RotateMove( void );
  313. void ReverseMove( void );
  314. void RampPitchVol( void );
  315. void Blocked( CBaseEntity *pOther );
  316. void SetTargetSpeed( float flSpeed );
  317. void UpdateSpeed( float flNewSpeed );
  318. int DrawDebugTextOverlays(void);
  319. DECLARE_DATADESC();
  320. DECLARE_SERVERCLASS();
  321. protected:
  322. bool SpinDown( float flTargetSpeed );
  323. float GetMoveSpeed( float flSpeed );
  324. float GetNextMoveInterval() const;
  325. // Input handlers
  326. void InputSetSpeed( inputdata_t &inputdata );
  327. void InputStart( inputdata_t &inputdata );
  328. void InputStop( inputdata_t &inputdata );
  329. void InputStartForward( inputdata_t &inputdata );
  330. void InputStartBackward( inputdata_t &inputdata );
  331. void InputToggle( inputdata_t &inputdata );
  332. void InputReverse( inputdata_t &inputdata );
  333. void InputStopAtStartPos( inputdata_t &inputdata );
  334. QAngle m_vecMoveAng;
  335. float m_flFanFriction;
  336. float m_flAttenuation;
  337. float m_flVolume;
  338. float m_flTargetSpeed; // Target value for m_flSpeed, used for spinning up and down.
  339. float m_flMaxSpeed; // Maximum value for m_flSpeed, used for ramping sound effects.
  340. float m_flBlockDamage; // Damage inflicted when blocked.
  341. string_t m_NoiseRunning;
  342. bool m_bReversed;
  343. QAngle m_angStart;
  344. bool m_bStopAtStartPos;
  345. bool m_bSolidBsp; // Brush is SOLID_BSP
  346. public:
  347. Vector m_vecClientOrigin;
  348. QAngle m_vecClientAngles;
  349. };
  350. LINK_ENTITY_TO_CLASS( func_rotating, CFuncRotating );
  351. BEGIN_DATADESC( CFuncRotating )
  352. DEFINE_FIELD( m_vecMoveAng, FIELD_VECTOR ),
  353. DEFINE_FIELD( m_flFanFriction, FIELD_FLOAT ),
  354. DEFINE_FIELD( m_flAttenuation, FIELD_FLOAT ),
  355. DEFINE_FIELD( m_flVolume, FIELD_FLOAT ),
  356. DEFINE_FIELD( m_flTargetSpeed, FIELD_FLOAT ),
  357. DEFINE_KEYFIELD( m_flMaxSpeed, FIELD_FLOAT, "maxspeed" ),
  358. DEFINE_KEYFIELD( m_flBlockDamage, FIELD_FLOAT, "dmg" ),
  359. DEFINE_KEYFIELD( m_NoiseRunning, FIELD_SOUNDNAME, "message" ),
  360. DEFINE_FIELD( m_bReversed, FIELD_BOOLEAN ),
  361. DEFINE_FIELD( m_angStart, FIELD_VECTOR ),
  362. DEFINE_FIELD( m_bStopAtStartPos, FIELD_BOOLEAN ),
  363. DEFINE_KEYFIELD( m_bSolidBsp, FIELD_BOOLEAN, "solidbsp" ),
  364. // Function Pointers
  365. DEFINE_FUNCTION( SpinUpMove ),
  366. DEFINE_FUNCTION( SpinDownMove ),
  367. DEFINE_FUNCTION( HurtTouch ),
  368. DEFINE_FUNCTION( RotatingUse ),
  369. DEFINE_FUNCTION( RotateMove ),
  370. DEFINE_FUNCTION( ReverseMove ),
  371. // Inputs
  372. DEFINE_INPUTFUNC( FIELD_FLOAT, "SetSpeed", InputSetSpeed ),
  373. DEFINE_INPUTFUNC( FIELD_VOID, "Start", InputStart ),
  374. DEFINE_INPUTFUNC( FIELD_VOID, "Stop", InputStop ),
  375. DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),
  376. DEFINE_INPUTFUNC( FIELD_VOID, "Reverse", InputReverse ),
  377. DEFINE_INPUTFUNC( FIELD_VOID, "StartForward", InputStartForward ),
  378. DEFINE_INPUTFUNC( FIELD_VOID, "StartBackward", InputStartBackward ),
  379. DEFINE_INPUTFUNC( FIELD_VOID, "StopAtStartPos", InputStopAtStartPos ),
  380. END_DATADESC()
  381. extern void SendProxy_Origin( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID );
  382. void SendProxy_FuncRotatingOrigin( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID )
  383. {
  384. #ifdef TF_DLL
  385. CFuncRotating *entity = (CFuncRotating*)pStruct;
  386. Assert( entity );
  387. if ( entity->HasSpawnFlags(SF_BRUSH_ROTATE_CLIENTSIDE) )
  388. {
  389. const Vector *v = &entity->m_vecClientOrigin;
  390. pOut->m_Vector[ 0 ] = v->x;
  391. pOut->m_Vector[ 1 ] = v->y;
  392. pOut->m_Vector[ 2 ] = v->z;
  393. return;
  394. }
  395. #endif
  396. SendProxy_Origin( pProp, pStruct, pData, pOut, iElement, objectID );
  397. }
  398. /*
  399. extern void SendProxy_Angles( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID );
  400. void SendProxy_FuncRotatingAngles( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID )
  401. {
  402. CFuncRotating *entity = (CFuncRotating*)pStruct;
  403. Assert( entity );
  404. if ( entity->HasSpawnFlags(SF_BRUSH_ROTATE_CLIENTSIDE) )
  405. {
  406. const QAngle *a = &entity->m_vecClientAngles;
  407. pOut->m_Vector[ 0 ] = anglemod( a->x );
  408. pOut->m_Vector[ 1 ] = anglemod( a->y );
  409. pOut->m_Vector[ 2 ] = anglemod( a->z );
  410. return;
  411. }
  412. SendProxy_Angles( pProp, pStruct, pData, pOut, iElement, objectID );
  413. }
  414. */
  415. void SendProxy_FuncRotatingAngle( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID)
  416. {
  417. CFuncRotating *entity = (CFuncRotating*)pStruct;
  418. Assert( entity );
  419. vec_t const *qa = (vec_t *)pData;
  420. vec_t const *ea = entity->GetLocalAngles().Base();
  421. NOTE_UNUSED(ea);
  422. // Assert its actually an index into m_angRotation if not this won't work
  423. Assert( (uintp)qa >= (uintp)ea && (uintp)qa < (uintp)ea + sizeof( QAngle ));
  424. #ifdef TF_DLL
  425. if ( entity->HasSpawnFlags(SF_BRUSH_ROTATE_CLIENTSIDE) )
  426. {
  427. const QAngle *a = &entity->m_vecClientAngles;
  428. pOut->m_Float = anglemod( (*a)[ qa - ea ] );
  429. return;
  430. }
  431. #endif
  432. pOut->m_Float = anglemod( *qa );
  433. Assert( IsFinite( pOut->m_Float ) );
  434. }
  435. extern void SendProxy_SimulationTime( const SendProp *pProp, const void *pStruct, const void *pVarData, DVariant *pOut, int iElement, int objectID );
  436. void SendProxy_FuncRotatingSimulationTime( const SendProp *pProp, const void *pStruct, const void *pVarData, DVariant *pOut, int iElement, int objectID )
  437. {
  438. #ifdef TF_DLL
  439. CFuncRotating *entity = (CFuncRotating*)pStruct;
  440. Assert( entity );
  441. if ( entity->HasSpawnFlags(SF_BRUSH_ROTATE_CLIENTSIDE) )
  442. {
  443. pOut->m_Int = 0;
  444. return;
  445. }
  446. #endif
  447. SendProxy_SimulationTime( pProp, pStruct, pVarData, pOut, iElement, objectID );
  448. }
  449. IMPLEMENT_SERVERCLASS_ST(CFuncRotating, DT_FuncRotating)
  450. SendPropExclude( "DT_BaseEntity", "m_angRotation" ),
  451. SendPropExclude( "DT_BaseEntity", "m_vecOrigin" ),
  452. SendPropExclude( "DT_BaseEntity", "m_flSimulationTime" ),
  453. SendPropVector(SENDINFO(m_vecOrigin), -1, SPROP_COORD|SPROP_CHANGES_OFTEN, 0.0f, HIGH_DEFAULT, SendProxy_FuncRotatingOrigin ),
  454. SendPropAngle( SENDINFO_VECTORELEM(m_angRotation, 0), 13, SPROP_CHANGES_OFTEN, SendProxy_FuncRotatingAngle ),
  455. SendPropAngle( SENDINFO_VECTORELEM(m_angRotation, 1), 13, SPROP_CHANGES_OFTEN, SendProxy_FuncRotatingAngle ),
  456. SendPropAngle( SENDINFO_VECTORELEM(m_angRotation, 2), 13, SPROP_CHANGES_OFTEN, SendProxy_FuncRotatingAngle ),
  457. SendPropInt(SENDINFO(m_flSimulationTime), SIMULATION_TIME_WINDOW_BITS, SPROP_UNSIGNED|SPROP_CHANGES_OFTEN|SPROP_ENCODED_AGAINST_TICKCOUNT, SendProxy_FuncRotatingSimulationTime),
  458. END_SEND_TABLE()
  459. //-----------------------------------------------------------------------------
  460. // Purpose: Handles keyvalues from the BSP. Called before spawning.
  461. //-----------------------------------------------------------------------------
  462. bool CFuncRotating::KeyValue( const char *szKeyName, const char *szValue )
  463. {
  464. if (FStrEq(szKeyName, "fanfriction"))
  465. {
  466. m_flFanFriction = atof(szValue)/100;
  467. }
  468. else if (FStrEq(szKeyName, "Volume"))
  469. {
  470. m_flVolume = atof(szValue) / 10.0;
  471. m_flVolume = clamp(m_flVolume, 0.0f, 1.0f);
  472. }
  473. else
  474. {
  475. return BaseClass::KeyValue( szKeyName, szValue );
  476. }
  477. return true;
  478. }
  479. //-----------------------------------------------------------------------------
  480. // Purpose: Called when spawning, after keyvalues have been set.
  481. //-----------------------------------------------------------------------------
  482. void CFuncRotating::Spawn( )
  483. {
  484. #ifdef TF_DLL
  485. AddSpawnFlags( SF_BRUSH_ROTATE_CLIENTSIDE );
  486. #endif
  487. //
  488. // Maintain compatibility with previous maps.
  489. //
  490. if (m_flVolume == 0.0)
  491. {
  492. m_flVolume = 1.0;
  493. }
  494. //
  495. // If the designer didn't set a sound attenuation, default to one.
  496. //
  497. if ( HasSpawnFlags(SF_BRUSH_ROTATE_SMALLRADIUS) )
  498. {
  499. m_flAttenuation = ATTN_IDLE;
  500. }
  501. else if ( HasSpawnFlags(SF_BRUSH_ROTATE_MEDIUMRADIUS) )
  502. {
  503. m_flAttenuation = ATTN_STATIC;
  504. }
  505. else if ( HasSpawnFlags(SF_BRUSH_ROTATE_LARGERADIUS) )
  506. {
  507. m_flAttenuation = ATTN_NORM;
  508. }
  509. else
  510. {
  511. m_flAttenuation = ATTN_NORM;
  512. }
  513. //
  514. // Prevent divide by zero if level designer forgets friction!
  515. //
  516. if ( m_flFanFriction == 0 )
  517. {
  518. m_flFanFriction = 1;
  519. }
  520. //
  521. // Build the axis of rotation based on spawnflags.
  522. //
  523. if ( HasSpawnFlags(SF_BRUSH_ROTATE_Z_AXIS) )
  524. {
  525. m_vecMoveAng = QAngle(0,0,1);
  526. }
  527. else if ( HasSpawnFlags(SF_BRUSH_ROTATE_X_AXIS) )
  528. {
  529. m_vecMoveAng = QAngle(1,0,0);
  530. }
  531. else
  532. {
  533. m_vecMoveAng = QAngle(0,1,0); // y-axis
  534. }
  535. //
  536. // Check for reverse rotation.
  537. //
  538. if ( HasSpawnFlags(SF_BRUSH_ROTATE_BACKWARDS) )
  539. {
  540. m_vecMoveAng = m_vecMoveAng * -1;
  541. }
  542. SetSolid( SOLID_VPHYSICS );
  543. //
  544. // Some rotating objects like fake volumetric lights will not be solid.
  545. //
  546. if ( HasSpawnFlags(SF_ROTATING_NOT_SOLID) )
  547. {
  548. AddSolidFlags( FSOLID_NOT_SOLID );
  549. SetMoveType( MOVETYPE_PUSH );
  550. }
  551. else
  552. {
  553. RemoveSolidFlags( FSOLID_NOT_SOLID );
  554. SetMoveType( MOVETYPE_PUSH );
  555. }
  556. SetModel( STRING( GetModelName() ) );
  557. SetUse( &CFuncRotating::RotatingUse );
  558. //
  559. // Did level designer forget to assign a maximum speed? Prevent a divide by
  560. // zero in RampPitchVol as well as allowing the rotator to work.
  561. //
  562. m_flMaxSpeed = fabs( m_flMaxSpeed );
  563. if (m_flMaxSpeed == 0)
  564. {
  565. m_flMaxSpeed = 100;
  566. }
  567. //
  568. // If the brush should be initially rotating, use it in a little while.
  569. //
  570. if ( HasSpawnFlags(SF_BRUSH_ROTATE_START_ON) )
  571. {
  572. SetThink( &CFuncRotating::SUB_CallUseToggle );
  573. SetNextThink( gpGlobals->curtime + .2 ); // leave a magic delay for client to start up
  574. }
  575. //
  576. // Can this brush inflict pain?
  577. //
  578. if ( HasSpawnFlags(SF_BRUSH_HURT) )
  579. {
  580. SetTouch( &CFuncRotating::HurtTouch );
  581. }
  582. //
  583. // Set speed to 0 in case there's an old "speed" key lying around.
  584. //
  585. m_flSpeed = 0;
  586. Precache( );
  587. CreateVPhysics();
  588. m_angStart = GetLocalAngles();
  589. // Slam the object back to solid - if we really want it to be solid.
  590. if ( m_bSolidBsp )
  591. {
  592. SetSolid( SOLID_BSP );
  593. }
  594. #ifdef TF_DLL
  595. if ( HasSpawnFlags(SF_BRUSH_ROTATE_CLIENTSIDE) )
  596. {
  597. m_vecClientOrigin = GetLocalOrigin();
  598. m_vecClientAngles = GetLocalAngles();
  599. }
  600. #endif
  601. }
  602. //-----------------------------------------------------------------------------
  603. // Purpose:
  604. //-----------------------------------------------------------------------------
  605. bool CFuncRotating::CreateVPhysics( void )
  606. {
  607. if ( !IsSolidFlagSet( FSOLID_NOT_SOLID ))
  608. {
  609. VPhysicsInitShadow( false, false );
  610. }
  611. return true;
  612. }
  613. //-----------------------------------------------------------------------------
  614. // Purpose:
  615. //-----------------------------------------------------------------------------
  616. void CFuncRotating::Precache( void )
  617. {
  618. //
  619. // Set up rotation sound.
  620. //
  621. char *szSoundFile = ( char * )STRING( m_NoiseRunning );
  622. if ( !m_NoiseRunning || strlen( szSoundFile ) == 0 )
  623. {
  624. // No sound set up, use the null sound.
  625. m_NoiseRunning = AllocPooledString("DoorSound.Null");
  626. }
  627. PrecacheScriptSound( STRING( m_NoiseRunning ) );
  628. if (GetLocalAngularVelocity() != vec3_angle )
  629. {
  630. //
  631. // If fan was spinning, and we went through transition or save/restore,
  632. // make sure we restart the sound. 1.5 sec delay is a magic number.
  633. //
  634. SetMoveDone( &CFuncRotating::SpinUpMove );
  635. SetMoveDoneTime( 1.5 );
  636. }
  637. }
  638. //-----------------------------------------------------------------------------
  639. // Purpose: Will hurt others based on how fast the brush is spinning.
  640. // Input : pOther -
  641. //-----------------------------------------------------------------------------
  642. void CFuncRotating::HurtTouch ( CBaseEntity *pOther )
  643. {
  644. // we can't hurt this thing, so we're not concerned with it
  645. if ( !pOther->m_takedamage )
  646. return;
  647. // calculate damage based on rotation speed
  648. m_flBlockDamage = GetLocalAngularVelocity().Length() / 10;
  649. #ifdef HL1_DLL
  650. if( m_flBlockDamage > 0 )
  651. #endif
  652. {
  653. pOther->TakeDamage( CTakeDamageInfo( this, this, m_flBlockDamage, DMG_CRUSH ) );
  654. Vector vecNewVelocity = pOther->GetAbsOrigin() - WorldSpaceCenter();
  655. VectorNormalize(vecNewVelocity);
  656. vecNewVelocity *= m_flBlockDamage;
  657. pOther->SetAbsVelocity( vecNewVelocity );
  658. }
  659. }
  660. #define FANPITCHMIN 30
  661. #define FANPITCHMAX 100
  662. //-----------------------------------------------------------------------------
  663. // Purpose: Ramp pitch and volume up to maximum values, based on the difference
  664. // between how fast we're going vs how fast we can go.
  665. //-----------------------------------------------------------------------------
  666. void CFuncRotating::RampPitchVol( void )
  667. {
  668. //
  669. // Calc volume and pitch as % of maximum vol and pitch.
  670. //
  671. float fpct = fabs(m_flSpeed) / m_flMaxSpeed;
  672. float fvol = clamp(m_flVolume * fpct, 0.f, 1.f); // slowdown volume ramps down to 0
  673. float fpitch = FANPITCHMIN + (FANPITCHMAX - FANPITCHMIN) * fpct;
  674. int pitch = clamp(FastFloatToSmallInt(fpitch), 0, 255);
  675. if (pitch == PITCH_NORM)
  676. {
  677. pitch = PITCH_NORM - 1;
  678. }
  679. //
  680. // Update the fan's volume and pitch.
  681. //
  682. CPASAttenuationFilter filter( GetAbsOrigin(), m_flAttenuation );
  683. filter.MakeReliable();
  684. EmitSound_t ep;
  685. ep.m_nChannel = CHAN_STATIC;
  686. ep.m_pSoundName = STRING(m_NoiseRunning);
  687. ep.m_flVolume = fvol;
  688. ep.m_SoundLevel = ATTN_TO_SNDLVL( m_flAttenuation );
  689. ep.m_nFlags = SND_CHANGE_PITCH | SND_CHANGE_VOL;
  690. ep.m_nPitch = pitch;
  691. EmitSound( filter, entindex(), ep );
  692. }
  693. //-----------------------------------------------------------------------------
  694. // Purpose:
  695. // Output : float
  696. //-----------------------------------------------------------------------------
  697. float CFuncRotating::GetNextMoveInterval() const
  698. {
  699. if ( m_bStopAtStartPos )
  700. {
  701. return TICK_INTERVAL;
  702. }
  703. return 0.1f;
  704. }
  705. //-----------------------------------------------------------------------------
  706. // Purpose: Sets the current speed to the given value and manages the sound effects.
  707. // Input : flNewSpeed - New speed in degrees per second.
  708. //-----------------------------------------------------------------------------
  709. void CFuncRotating::UpdateSpeed( float flNewSpeed )
  710. {
  711. float flOldSpeed = m_flSpeed;
  712. m_flSpeed = clamp( flNewSpeed, -m_flMaxSpeed, m_flMaxSpeed );
  713. if ( m_bStopAtStartPos )
  714. {
  715. int checkAxis = 2;
  716. // See if we got close to the starting orientation
  717. if ( m_vecMoveAng[0] != 0 )
  718. {
  719. checkAxis = 0;
  720. }
  721. else if ( m_vecMoveAng[1] != 0 )
  722. {
  723. checkAxis = 1;
  724. }
  725. float angDelta = anglemod( GetLocalAngles()[ checkAxis ] - m_angStart[ checkAxis ] );
  726. if ( angDelta > 180.0f )
  727. {
  728. angDelta -= 360.0f;
  729. }
  730. if ( flNewSpeed < 100 )
  731. {
  732. if ( flNewSpeed <= 25 && fabs( angDelta ) < 1.0f )
  733. {
  734. m_flTargetSpeed = 0;
  735. m_bStopAtStartPos = false;
  736. m_flSpeed = 0.0f;
  737. SetLocalAngles( m_angStart );
  738. }
  739. else if ( fabs( angDelta ) > 90.0f )
  740. {
  741. // Keep rotating at same speed for now
  742. m_flSpeed = flOldSpeed;
  743. }
  744. else
  745. {
  746. float minSpeed = fabs( angDelta );
  747. if ( minSpeed < 20 )
  748. minSpeed = 20;
  749. m_flSpeed = flOldSpeed > 0.0f ? minSpeed : -minSpeed;
  750. }
  751. }
  752. }
  753. if ( ( flOldSpeed == 0 ) && ( m_flSpeed != 0 ) )
  754. {
  755. // Starting to move - emit the sound.
  756. CPASAttenuationFilter filter( GetAbsOrigin(), m_flAttenuation );
  757. filter.MakeReliable();
  758. EmitSound_t ep;
  759. ep.m_nChannel = CHAN_STATIC;
  760. ep.m_pSoundName = STRING(m_NoiseRunning);
  761. ep.m_flVolume = 0.01;
  762. ep.m_SoundLevel = ATTN_TO_SNDLVL( m_flAttenuation );
  763. ep.m_nPitch = FANPITCHMIN;
  764. EmitSound( filter, entindex(), ep );
  765. RampPitchVol();
  766. }
  767. else if ( ( flOldSpeed != 0 ) && ( m_flSpeed == 0 ) )
  768. {
  769. // Stopping - stop the sound.
  770. StopSound( entindex(), CHAN_STATIC, STRING(m_NoiseRunning) );
  771. }
  772. else
  773. {
  774. // Changing speed - adjust the pitch and volume.
  775. RampPitchVol();
  776. }
  777. SetLocalAngularVelocity( m_vecMoveAng * m_flSpeed );
  778. }
  779. //-----------------------------------------------------------------------------
  780. // Purpose: Think function. Accelerates a func_rotating to a higher angular velocity.
  781. //-----------------------------------------------------------------------------
  782. void CFuncRotating::SpinUpMove( void )
  783. {
  784. //
  785. // Calculate our new speed.
  786. //
  787. bool bSpinUpDone = false;
  788. float flNewSpeed = fabs( m_flSpeed ) + 0.2 * m_flMaxSpeed * m_flFanFriction;
  789. if ( fabs( flNewSpeed ) >= fabs( m_flTargetSpeed ) )
  790. {
  791. // Reached our target speed.
  792. flNewSpeed = m_flTargetSpeed;
  793. bSpinUpDone = !m_bStopAtStartPos;
  794. }
  795. else if ( m_flTargetSpeed < 0 )
  796. {
  797. // Spinning up in reverse - negate the speed.
  798. flNewSpeed *= -1;
  799. }
  800. //
  801. // Apply the new speed, adjust sound pitch and volume.
  802. //
  803. UpdateSpeed( flNewSpeed );
  804. //
  805. // If we've met or exceeded target speed, stop spinning up.
  806. //
  807. if ( bSpinUpDone )
  808. {
  809. SetMoveDone( &CFuncRotating::RotateMove );
  810. RotateMove();
  811. }
  812. SetMoveDoneTime( GetNextMoveInterval() );
  813. }
  814. //-----------------------------------------------------------------------------
  815. // Purpose: Decelerates the rotator from a higher speed to a lower one.
  816. // Input : flTargetSpeed - Speed to spin down to.
  817. // Output : Returns true if we reached the target speed, false otherwise.
  818. //-----------------------------------------------------------------------------
  819. bool CFuncRotating::SpinDown( float flTargetSpeed )
  820. {
  821. //
  822. // Bleed off a little speed due to friction.
  823. //
  824. bool bSpinDownDone = false;
  825. float flNewSpeed = fabs( m_flSpeed ) - 0.1 * m_flMaxSpeed * m_flFanFriction;
  826. if ( flNewSpeed < 0 )
  827. {
  828. flNewSpeed = 0;
  829. }
  830. if ( fabs( flNewSpeed ) <= fabs( flTargetSpeed ) )
  831. {
  832. // Reached our target speed.
  833. flNewSpeed = flTargetSpeed;
  834. bSpinDownDone = !m_bStopAtStartPos;
  835. }
  836. else if ( m_flSpeed < 0 )
  837. {
  838. // Spinning down in reverse - negate the speed.
  839. flNewSpeed *= -1;
  840. }
  841. //
  842. // Apply the new speed, adjust sound pitch and volume.
  843. //
  844. UpdateSpeed( flNewSpeed );
  845. //
  846. // If we've met or exceeded target speed, stop spinning down.
  847. //
  848. return bSpinDownDone;
  849. }
  850. //-----------------------------------------------------------------------------
  851. // Purpose: Think function. Decelerates a func_rotating to a lower angular velocity.
  852. //-----------------------------------------------------------------------------
  853. void CFuncRotating::SpinDownMove( void )
  854. {
  855. //
  856. // If we've met or exceeded target speed, stop spinning down.
  857. //
  858. if ( SpinDown( m_flTargetSpeed ) )
  859. {
  860. SetMoveDone( &CFuncRotating::RotateMove );
  861. RotateMove();
  862. }
  863. else
  864. {
  865. SetMoveDoneTime( GetNextMoveInterval() );
  866. }
  867. }
  868. //-----------------------------------------------------------------------------
  869. // Purpose: Think function for reversing directions. Spins down to zero, then
  870. // starts spinning up to the target speed.
  871. //-----------------------------------------------------------------------------
  872. void CFuncRotating::ReverseMove( void )
  873. {
  874. if ( SpinDown( 0 ) )
  875. {
  876. // We've reached zero - spin back up to the target speed.
  877. SetTargetSpeed( m_flTargetSpeed );
  878. }
  879. else
  880. {
  881. SetMoveDoneTime( GetNextMoveInterval() );
  882. }
  883. }
  884. //-----------------------------------------------------------------------------
  885. // Purpose: Think function. Called while rotating at a constant angular velocity.
  886. //-----------------------------------------------------------------------------
  887. void CFuncRotating::RotateMove( void )
  888. {
  889. SetMoveDoneTime( 10 );
  890. if ( m_bStopAtStartPos )
  891. {
  892. SetMoveDoneTime( GetNextMoveInterval() );
  893. int checkAxis = 2;
  894. // See if we got close to the starting orientation
  895. if ( m_vecMoveAng[0] != 0 )
  896. {
  897. checkAxis = 0;
  898. }
  899. else if ( m_vecMoveAng[1] != 0 )
  900. {
  901. checkAxis = 1;
  902. }
  903. float angDelta = anglemod( GetLocalAngles()[ checkAxis ] - m_angStart[ checkAxis ] );
  904. if ( angDelta > 180.0f )
  905. angDelta -= 360.0f;
  906. QAngle avel = GetLocalAngularVelocity();
  907. // Delta per tick
  908. QAngle avelpertick = avel * TICK_INTERVAL;
  909. if ( fabs( angDelta ) < fabs( avelpertick[ checkAxis ] ) )
  910. {
  911. SetTargetSpeed( 0 );
  912. SetLocalAngles( m_angStart );
  913. m_bStopAtStartPos = false;
  914. }
  915. }
  916. }
  917. //-----------------------------------------------------------------------------
  918. // Purpose: Used for debug output. Returns the given speed considering our current
  919. // direction of rotation, so that positive values are forward and negative
  920. // values are backward.
  921. // Input : flSpeed - Angular speed in degrees per second.
  922. //-----------------------------------------------------------------------------
  923. float CFuncRotating::GetMoveSpeed( float flSpeed )
  924. {
  925. if ( m_vecMoveAng[0] != 0 )
  926. {
  927. return flSpeed * m_vecMoveAng[0];
  928. }
  929. if ( m_vecMoveAng[1] != 0 )
  930. {
  931. return flSpeed * m_vecMoveAng[1];
  932. }
  933. return flSpeed * m_vecMoveAng[2];
  934. }
  935. //-----------------------------------------------------------------------------
  936. // Purpose: Sets a new angular velocity to achieve.
  937. // Input : flSpeed - Target angular velocity in degrees per second.
  938. //-----------------------------------------------------------------------------
  939. void CFuncRotating::SetTargetSpeed( float flSpeed )
  940. {
  941. //
  942. // Make sure the sign is correct - positive for forward rotation,
  943. // negative for reverse rotation.
  944. //
  945. flSpeed = fabs( flSpeed );
  946. if ( m_bReversed )
  947. {
  948. flSpeed *= -1;
  949. }
  950. m_flTargetSpeed = flSpeed;
  951. //
  952. // If we don't accelerate, change to the new speed instantly.
  953. //
  954. if ( !HasSpawnFlags(SF_BRUSH_ACCDCC ) )
  955. {
  956. UpdateSpeed( m_flTargetSpeed );
  957. SetMoveDone( &CFuncRotating::RotateMove );
  958. }
  959. //
  960. // Otherwise deal with acceleration/deceleration:
  961. //
  962. else
  963. {
  964. //
  965. // Check for reversing directions.
  966. //
  967. if ((( m_flSpeed > 0 ) && ( m_flTargetSpeed < 0 )) ||
  968. (( m_flSpeed < 0 ) && ( m_flTargetSpeed > 0 )))
  969. {
  970. SetMoveDone( &CFuncRotating::ReverseMove );
  971. }
  972. //
  973. // If we are below the new target speed, spin up to the target speed.
  974. //
  975. else if ( fabs( m_flSpeed ) < fabs( m_flTargetSpeed ) )
  976. {
  977. SetMoveDone( &CFuncRotating::SpinUpMove );
  978. }
  979. //
  980. // If we are above the new target speed, spin down to the target speed.
  981. //
  982. else if ( fabs( m_flSpeed ) > fabs( m_flTargetSpeed ) )
  983. {
  984. SetMoveDone( &CFuncRotating::SpinDownMove );
  985. }
  986. //
  987. // We are already at the new target speed. Just keep rotating.
  988. //
  989. else
  990. {
  991. SetMoveDone( &CFuncRotating::RotateMove );
  992. }
  993. }
  994. SetMoveDoneTime( GetNextMoveInterval() );
  995. }
  996. //-----------------------------------------------------------------------------
  997. // Purpose: Called when a rotating brush is used by the player.
  998. // Input : pActivator -
  999. // pCaller -
  1000. // useType -
  1001. // value -
  1002. //-----------------------------------------------------------------------------
  1003. void CFuncRotating::RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  1004. {
  1005. //
  1006. // If the rotator is spinning, stop it.
  1007. //
  1008. if ( m_flSpeed != 0 )
  1009. {
  1010. SetTargetSpeed( 0 );
  1011. }
  1012. //
  1013. // Rotator is not moving, so start it.
  1014. //
  1015. else
  1016. {
  1017. SetTargetSpeed( m_flMaxSpeed );
  1018. }
  1019. }
  1020. //-----------------------------------------------------------------------------
  1021. // Purpose: Input handler that reverses the direction of rotation.
  1022. //-----------------------------------------------------------------------------
  1023. void CFuncRotating::InputReverse( inputdata_t &inputdata )
  1024. {
  1025. m_bStopAtStartPos = false;
  1026. m_bReversed = !m_bReversed;
  1027. SetTargetSpeed( m_flSpeed );
  1028. }
  1029. //-----------------------------------------------------------------------------
  1030. // Purpose: Input handler for setting the speed of the rotator.
  1031. // Input : Float target angular velocity as a ratio of maximum speed [0, 1].
  1032. //-----------------------------------------------------------------------------
  1033. void CFuncRotating::InputSetSpeed( inputdata_t &inputdata )
  1034. {
  1035. m_bStopAtStartPos = false;
  1036. float flSpeed = inputdata.value.Float();
  1037. m_bReversed = flSpeed < 0 ? true : false;
  1038. flSpeed = fabs(flSpeed);
  1039. SetTargetSpeed( clamp( flSpeed, 0.f, 1.f ) * m_flMaxSpeed );
  1040. }
  1041. //-----------------------------------------------------------------------------
  1042. // Purpose: Input handler to start the rotator spinning.
  1043. //-----------------------------------------------------------------------------
  1044. void CFuncRotating::InputStart( inputdata_t &inputdata )
  1045. {
  1046. m_bStopAtStartPos = false;
  1047. SetTargetSpeed( m_flMaxSpeed );
  1048. }
  1049. //-----------------------------------------------------------------------------
  1050. // Purpose: Input handler to start the rotator spinning.
  1051. //-----------------------------------------------------------------------------
  1052. void CFuncRotating::InputStartForward( inputdata_t &inputdata )
  1053. {
  1054. m_bReversed = false;
  1055. SetTargetSpeed( m_flMaxSpeed );
  1056. }
  1057. //-----------------------------------------------------------------------------
  1058. // Purpose: Input handler to start the rotator spinning.
  1059. //-----------------------------------------------------------------------------
  1060. void CFuncRotating::InputStartBackward( inputdata_t &inputdata )
  1061. {
  1062. m_bStopAtStartPos = false;
  1063. m_bReversed = true;
  1064. SetTargetSpeed( m_flMaxSpeed );
  1065. }
  1066. //-----------------------------------------------------------------------------
  1067. // Purpose: Input handler to stop the rotator from spinning.
  1068. //-----------------------------------------------------------------------------
  1069. void CFuncRotating::InputStop( inputdata_t &inputdata )
  1070. {
  1071. m_bStopAtStartPos = false;
  1072. SetTargetSpeed( 0 );
  1073. }
  1074. //-----------------------------------------------------------------------------
  1075. // Purpose:
  1076. // Input : &inputdata -
  1077. //-----------------------------------------------------------------------------
  1078. void CFuncRotating::InputStopAtStartPos( inputdata_t &inputdata )
  1079. {
  1080. m_bStopAtStartPos = true;
  1081. SetTargetSpeed( 0 );
  1082. SetMoveDoneTime( GetNextMoveInterval() );
  1083. }
  1084. //-----------------------------------------------------------------------------
  1085. // Purpose: Starts the rotator if it is still, stops it if it is spinning.
  1086. //-----------------------------------------------------------------------------
  1087. void CFuncRotating::InputToggle( inputdata_t &inputdata )
  1088. {
  1089. if (m_flSpeed > 0)
  1090. {
  1091. SetTargetSpeed( 0 );
  1092. }
  1093. else
  1094. {
  1095. SetTargetSpeed( m_flMaxSpeed );
  1096. }
  1097. }
  1098. //-----------------------------------------------------------------------------
  1099. // Purpose: An entity has blocked the brush.
  1100. // Input : pOther -
  1101. //-----------------------------------------------------------------------------
  1102. void CFuncRotating::Blocked( CBaseEntity *pOther )
  1103. {
  1104. #ifdef HL1_DLL
  1105. if( m_flBlockDamage > 0 )
  1106. #endif
  1107. pOther->TakeDamage( CTakeDamageInfo( this, this, m_flBlockDamage, DMG_CRUSH ) );
  1108. }
  1109. //-----------------------------------------------------------------------------
  1110. // Purpose: Draw any debug text overlays
  1111. // Input :
  1112. // Output : Current text offset from the top
  1113. //-----------------------------------------------------------------------------
  1114. int CFuncRotating::DrawDebugTextOverlays(void)
  1115. {
  1116. int text_offset = BaseClass::DrawDebugTextOverlays();
  1117. if (m_debugOverlays & OVERLAY_TEXT_BIT)
  1118. {
  1119. char tempstr[512];
  1120. Q_snprintf( tempstr, sizeof( tempstr ),"Speed cur (target): %3.2f (%3.2f)", GetMoveSpeed( m_flSpeed ), GetMoveSpeed( m_flTargetSpeed ) );
  1121. EntityText(text_offset,tempstr,0);
  1122. text_offset++;
  1123. }
  1124. return text_offset;
  1125. }
  1126. class CFuncVPhysicsClip : public CBaseEntity
  1127. {
  1128. DECLARE_DATADESC();
  1129. DECLARE_CLASS( CFuncVPhysicsClip, CBaseEntity );
  1130. public:
  1131. void Spawn();
  1132. void Activate();
  1133. bool CreateVPhysics( void );
  1134. bool EntityPassesFilter( CBaseEntity *pOther );
  1135. bool ForceVPhysicsCollide( CBaseEntity *pEntity );
  1136. void InputEnable( inputdata_t &inputdata );
  1137. void InputDisable( inputdata_t &inputdata );
  1138. private:
  1139. string_t m_iFilterName;
  1140. CHandle<CBaseFilter> m_hFilter;
  1141. bool m_bDisabled;
  1142. };
  1143. // Global Savedata for base trigger
  1144. BEGIN_DATADESC( CFuncVPhysicsClip )
  1145. // Keyfields
  1146. DEFINE_KEYFIELD( m_iFilterName, FIELD_STRING, "filtername" ),
  1147. DEFINE_FIELD( m_hFilter, FIELD_EHANDLE ),
  1148. DEFINE_FIELD( m_bDisabled, FIELD_BOOLEAN ),
  1149. DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
  1150. DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
  1151. END_DATADESC()
  1152. LINK_ENTITY_TO_CLASS( func_clip_vphysics, CFuncVPhysicsClip );
  1153. void CFuncVPhysicsClip::Spawn( void )
  1154. {
  1155. SetMoveType( MOVETYPE_PUSH ); // so it doesn't get pushed by anything
  1156. SetSolid( SOLID_VPHYSICS );
  1157. AddSolidFlags( FSOLID_NOT_SOLID );
  1158. SetModel( STRING( GetModelName() ) );
  1159. AddEffects( EF_NODRAW );
  1160. CreateVPhysics();
  1161. VPhysicsGetObject()->EnableCollisions( !m_bDisabled );
  1162. }
  1163. bool CFuncVPhysicsClip::CreateVPhysics( void )
  1164. {
  1165. VPhysicsInitStatic();
  1166. return true;
  1167. }
  1168. void CFuncVPhysicsClip::Activate( void )
  1169. {
  1170. // Get a handle to my filter entity if there is one
  1171. if (m_iFilterName != NULL_STRING)
  1172. {
  1173. m_hFilter = dynamic_cast<CBaseFilter *>(gEntList.FindEntityByName( NULL, m_iFilterName ));
  1174. }
  1175. BaseClass::Activate();
  1176. }
  1177. bool CFuncVPhysicsClip::EntityPassesFilter( CBaseEntity *pOther )
  1178. {
  1179. CBaseFilter* pFilter = (CBaseFilter*)(m_hFilter.Get());
  1180. if ( pFilter )
  1181. return pFilter->PassesFilter( this, pOther );
  1182. if ( pOther->GetMoveType() == MOVETYPE_VPHYSICS && pOther->VPhysicsGetObject()->IsMoveable() )
  1183. return true;
  1184. return false;
  1185. }
  1186. bool CFuncVPhysicsClip::ForceVPhysicsCollide( CBaseEntity *pEntity )
  1187. {
  1188. return EntityPassesFilter(pEntity);
  1189. }
  1190. void CFuncVPhysicsClip::InputEnable( inputdata_t &inputdata )
  1191. {
  1192. VPhysicsGetObject()->EnableCollisions(true);
  1193. m_bDisabled = false;
  1194. }
  1195. void CFuncVPhysicsClip::InputDisable( inputdata_t &inputdata )
  1196. {
  1197. VPhysicsGetObject()->EnableCollisions(false);
  1198. m_bDisabled = true;
  1199. }