Counter Strike : Global Offensive Source Code
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.

1502 lines
39 KiB

  1. //========= Copyright � 1996-2005, 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. // If our euler angle is starting to get too big, normalize it
  326. void NormalizeAngleIfNeeded();
  327. // Input handlers
  328. void InputSetSpeed( inputdata_t &inputdata );
  329. void InputGetSpeed( inputdata_t &inputdata );
  330. void InputStart( inputdata_t &inputdata );
  331. void InputStop( inputdata_t &inputdata );
  332. void InputStartForward( inputdata_t &inputdata );
  333. void InputStartBackward( inputdata_t &inputdata );
  334. void InputToggle( inputdata_t &inputdata );
  335. void InputReverse( inputdata_t &inputdata );
  336. void InputStopAtStartPos( inputdata_t &inputdata );
  337. QAngle m_vecMoveAng;
  338. float m_flFanFriction;
  339. float m_flAttenuation;
  340. float m_flVolume;
  341. float m_flTargetSpeed; // Target value for m_flSpeed, used for spinning up and down.
  342. float m_flMaxSpeed; // Maximum value for m_flSpeed, used for ramping sound effects.
  343. float m_flBlockDamage; // Damage inflicted when blocked.
  344. string_t m_NoiseRunning;
  345. bool m_bReversed;
  346. QAngle m_angStart;
  347. bool m_bStopAtStartPos;
  348. bool m_bSolidBsp; // Brush is SOLID_BSP
  349. //outputs
  350. COutputFloat m_OnGetSpeed; // Used for polling the speed value.
  351. public:
  352. Vector m_vecClientOrigin;
  353. QAngle m_vecClientAngles;
  354. };
  355. LINK_ENTITY_TO_CLASS( func_rotating, CFuncRotating );
  356. BEGIN_DATADESC( CFuncRotating )
  357. DEFINE_FIELD( m_vecMoveAng, FIELD_VECTOR ),
  358. DEFINE_FIELD( m_flFanFriction, FIELD_FLOAT ),
  359. DEFINE_FIELD( m_flAttenuation, FIELD_FLOAT ),
  360. DEFINE_FIELD( m_flVolume, FIELD_FLOAT ),
  361. DEFINE_FIELD( m_flTargetSpeed, FIELD_FLOAT ),
  362. DEFINE_KEYFIELD( m_flMaxSpeed, FIELD_FLOAT, "maxspeed" ),
  363. DEFINE_KEYFIELD( m_flBlockDamage, FIELD_FLOAT, "dmg" ),
  364. DEFINE_KEYFIELD( m_NoiseRunning, FIELD_SOUNDNAME, "message" ),
  365. DEFINE_FIELD( m_bReversed, FIELD_BOOLEAN ),
  366. DEFINE_FIELD( m_angStart, FIELD_VECTOR ),
  367. DEFINE_FIELD( m_bStopAtStartPos, FIELD_BOOLEAN ),
  368. DEFINE_KEYFIELD( m_bSolidBsp, FIELD_BOOLEAN, "solidbsp" ),
  369. // Function Pointers
  370. DEFINE_FUNCTION( SpinUpMove ),
  371. DEFINE_FUNCTION( SpinDownMove ),
  372. DEFINE_FUNCTION( HurtTouch ),
  373. DEFINE_FUNCTION( RotatingUse ),
  374. DEFINE_FUNCTION( RotateMove ),
  375. DEFINE_FUNCTION( ReverseMove ),
  376. // Inputs
  377. DEFINE_INPUTFUNC( FIELD_FLOAT, "SetSpeed", InputSetSpeed ),
  378. DEFINE_INPUTFUNC( FIELD_VOID, "GetSpeed", InputGetSpeed ),
  379. DEFINE_INPUTFUNC( FIELD_VOID, "Start", InputStart ),
  380. DEFINE_INPUTFUNC( FIELD_VOID, "Stop", InputStop ),
  381. DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),
  382. DEFINE_INPUTFUNC( FIELD_VOID, "Reverse", InputReverse ),
  383. DEFINE_INPUTFUNC( FIELD_VOID, "StartForward", InputStartForward ),
  384. DEFINE_INPUTFUNC( FIELD_VOID, "StartBackward", InputStartBackward ),
  385. DEFINE_INPUTFUNC( FIELD_VOID, "StopAtStartPos", InputStopAtStartPos ),
  386. // Outputs
  387. DEFINE_OUTPUT(m_OnGetSpeed, "OnGetSpeed"),
  388. END_DATADESC()
  389. extern void SendProxy_Origin( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID );
  390. void SendProxy_FuncRotatingOrigin( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID )
  391. {
  392. CFuncRotating *entity = (CFuncRotating*)pStruct;
  393. Assert( entity );
  394. if ( entity->HasSpawnFlags(SF_BRUSH_ROTATE_CLIENTSIDE) )
  395. {
  396. const Vector *v = &entity->m_vecClientOrigin;
  397. pOut->m_Vector[ 0 ] = v->x;
  398. pOut->m_Vector[ 1 ] = v->y;
  399. pOut->m_Vector[ 2 ] = v->z;
  400. return;
  401. }
  402. SendProxy_Origin( pProp, pStruct, pData, pOut, iElement, objectID );
  403. }
  404. void SendProxy_FuncRotatingAngle( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID)
  405. {
  406. vec_t const *qa = (vec_t *)pData;
  407. #ifdef TF_DLL
  408. CFuncRotating *entity = (CFuncRotating*)pStruct;
  409. Assert( entity );
  410. vec_t const *ea = entity->GetLocalAngles().Base();
  411. // Assert its actually an index into m_angRotation if not this won't work
  412. Assert( (uintp)qa >= (uintp)ea && (uintp)qa < (uintp)ea + sizeof( QAngle ));
  413. if ( entity->HasSpawnFlags(SF_BRUSH_ROTATE_CLIENTSIDE) )
  414. {
  415. const QAngle *a = &entity->m_vecClientAngles;
  416. pOut->m_Float = anglemod( (*a)[ qa - ea ] );
  417. return;
  418. }
  419. #endif
  420. pOut->m_Float = anglemod( *qa );
  421. Assert( IsFinite( pOut->m_Float ) );
  422. }
  423. extern void SendProxy_SimulationTime( const SendProp *pProp, const void *pStruct, const void *pVarData, DVariant *pOut, int iElement, int objectID );
  424. void SendProxy_FuncRotatingSimulationTime( const SendProp *pProp, const void *pStruct, const void *pVarData, DVariant *pOut, int iElement, int objectID )
  425. {
  426. #ifdef TF_DLL
  427. CFuncRotating *entity = (CFuncRotating*)pStruct;
  428. Assert( entity );
  429. if ( entity->HasSpawnFlags(SF_BRUSH_ROTATE_CLIENTSIDE) )
  430. {
  431. pOut->m_Int = 0;
  432. return;
  433. }
  434. #endif
  435. SendProxy_SimulationTime( pProp, pStruct, pVarData, pOut, iElement, objectID );
  436. }
  437. IMPLEMENT_SERVERCLASS_ST(CFuncRotating, DT_FuncRotating)
  438. SendPropExclude( "DT_BaseEntity", "m_angRotation" ),
  439. SendPropExclude( "DT_BaseEntity", "m_vecOrigin" ),
  440. SendPropExclude( "DT_BaseEntity", "m_flSimulationTime" ),
  441. SendPropVector(SENDINFO(m_vecOrigin), -1, SPROP_COORD|SPROP_CHANGES_OFTEN, 0.0f, HIGH_DEFAULT, SendProxy_FuncRotatingOrigin ),
  442. SendPropAngle( SENDINFO_VECTORELEM(m_angRotation, 0), 13, SPROP_CHANGES_OFTEN, SendProxy_FuncRotatingAngle ),
  443. SendPropAngle( SENDINFO_VECTORELEM(m_angRotation, 1), 13, SPROP_CHANGES_OFTEN, SendProxy_FuncRotatingAngle ),
  444. SendPropAngle( SENDINFO_VECTORELEM(m_angRotation, 2), 13, SPROP_CHANGES_OFTEN, SendProxy_FuncRotatingAngle ),
  445. SendPropInt(SENDINFO(m_flSimulationTime), SIMULATION_TIME_WINDOW_BITS, SPROP_UNSIGNED|SPROP_CHANGES_OFTEN|SPROP_ENCODED_AGAINST_TICKCOUNT, SendProxy_FuncRotatingSimulationTime),
  446. END_SEND_TABLE()
  447. //-----------------------------------------------------------------------------
  448. // Purpose: Handles keyvalues from the BSP. Called before spawning.
  449. //-----------------------------------------------------------------------------
  450. bool CFuncRotating::KeyValue( const char *szKeyName, const char *szValue )
  451. {
  452. if (FStrEq(szKeyName, "fanfriction"))
  453. {
  454. m_flFanFriction = atof(szValue)/100;
  455. }
  456. else if (FStrEq(szKeyName, "Volume"))
  457. {
  458. m_flVolume = atof(szValue) / 10.0;
  459. m_flVolume = clamp(m_flVolume, 0.0, 1.0f);
  460. }
  461. else
  462. {
  463. return BaseClass::KeyValue( szKeyName, szValue );
  464. }
  465. return true;
  466. }
  467. //-----------------------------------------------------------------------------
  468. // Purpose: Called when spawning, after keyvalues have been set.
  469. //-----------------------------------------------------------------------------
  470. void CFuncRotating::Spawn( )
  471. {
  472. #if defined(TF_DLL)
  473. AddSpawnFlags( SF_BRUSH_ROTATE_CLIENTSIDE );
  474. #endif
  475. //
  476. // Maintain compatibility with previous maps.
  477. //
  478. if (m_flVolume == 0.0)
  479. {
  480. m_flVolume = 1.0;
  481. }
  482. //
  483. // If the designer didn't set a sound attenuation, default to one.
  484. //
  485. if ( HasSpawnFlags(SF_BRUSH_ROTATE_SMALLRADIUS) )
  486. {
  487. m_flAttenuation = ATTN_IDLE;
  488. }
  489. else if ( HasSpawnFlags(SF_BRUSH_ROTATE_MEDIUMRADIUS) )
  490. {
  491. m_flAttenuation = ATTN_STATIC;
  492. }
  493. else if ( HasSpawnFlags(SF_BRUSH_ROTATE_LARGERADIUS) )
  494. {
  495. m_flAttenuation = ATTN_NORM;
  496. }
  497. else
  498. {
  499. m_flAttenuation = ATTN_NORM;
  500. }
  501. //
  502. // Prevent divide by zero if level designer forgets friction!
  503. //
  504. if ( m_flFanFriction == 0 )
  505. {
  506. m_flFanFriction = 1;
  507. }
  508. //
  509. // Build the axis of rotation based on spawnflags.
  510. //
  511. if ( HasSpawnFlags(SF_BRUSH_ROTATE_Z_AXIS) )
  512. {
  513. m_vecMoveAng = QAngle(0,0,1);
  514. }
  515. else if ( HasSpawnFlags(SF_BRUSH_ROTATE_X_AXIS) )
  516. {
  517. m_vecMoveAng = QAngle(1,0,0);
  518. }
  519. else
  520. {
  521. m_vecMoveAng = QAngle(0,1,0); // y-axis
  522. }
  523. //
  524. // Check for reverse rotation.
  525. //
  526. if ( HasSpawnFlags(SF_BRUSH_ROTATE_BACKWARDS) )
  527. {
  528. m_vecMoveAng = m_vecMoveAng * -1;
  529. }
  530. SetSolid( SOLID_VPHYSICS );
  531. //
  532. // Some rotating objects like fake volumetric lights will not be solid.
  533. //
  534. if ( HasSpawnFlags(SF_ROTATING_NOT_SOLID) )
  535. {
  536. AddSolidFlags( FSOLID_NOT_SOLID );
  537. SetMoveType( MOVETYPE_PUSH );
  538. }
  539. else
  540. {
  541. RemoveSolidFlags( FSOLID_NOT_SOLID );
  542. SetMoveType( MOVETYPE_PUSH );
  543. }
  544. SetModel( STRING( GetModelName() ) );
  545. SetUse( &CFuncRotating::RotatingUse );
  546. //
  547. // Did level designer forget to assign a maximum speed? Prevent a divide by
  548. // zero in RampPitchVol as well as allowing the rotator to work.
  549. //
  550. m_flMaxSpeed = fabs( m_flMaxSpeed );
  551. if (m_flMaxSpeed == 0)
  552. {
  553. m_flMaxSpeed = 100;
  554. }
  555. //
  556. // If the brush should be initially rotating, use it in a little while.
  557. //
  558. if ( HasSpawnFlags(SF_BRUSH_ROTATE_START_ON) )
  559. {
  560. SetThink( &CFuncRotating::SUB_CallUseToggle );
  561. SetNextThink( gpGlobals->curtime + .2 ); // leave a magic delay for client to start up
  562. }
  563. else
  564. {
  565. SetThink( &CFuncRotating::NormalizeAngleIfNeeded );
  566. SetNextThink( gpGlobals->curtime + .2 );
  567. }
  568. //
  569. // Can this brush inflict pain?
  570. //
  571. if ( HasSpawnFlags(SF_BRUSH_HURT) )
  572. {
  573. SetTouch( &CFuncRotating::HurtTouch );
  574. }
  575. //
  576. // Set speed to 0 in case there's an old "speed" key lying around.
  577. //
  578. m_flSpeed = 0;
  579. Precache( );
  580. CreateVPhysics();
  581. m_angStart = GetLocalAngles();
  582. // Slam the object back to solid - if we really want it to be solid.
  583. if ( m_bSolidBsp )
  584. {
  585. SetSolid( SOLID_BSP );
  586. }
  587. #ifdef TF_DLL
  588. if ( HasSpawnFlags(SF_BRUSH_ROTATE_CLIENTSIDE) )
  589. {
  590. m_vecClientOrigin = GetLocalOrigin();
  591. m_vecClientAngles = GetLocalAngles();
  592. }
  593. #endif
  594. }
  595. //-----------------------------------------------------------------------------
  596. // Purpose:
  597. //-----------------------------------------------------------------------------
  598. bool CFuncRotating::CreateVPhysics( void )
  599. {
  600. if ( !IsSolidFlagSet( FSOLID_NOT_SOLID ))
  601. {
  602. VPhysicsInitShadow( false, false );
  603. }
  604. return true;
  605. }
  606. //-----------------------------------------------------------------------------
  607. // Purpose:
  608. //-----------------------------------------------------------------------------
  609. void CFuncRotating::Precache( void )
  610. {
  611. //
  612. // Set up rotation sound.
  613. //
  614. char *szSoundFile = ( char * )STRING( m_NoiseRunning );
  615. if ( !m_NoiseRunning || strlen( szSoundFile ) == 0 )
  616. {
  617. // No sound set up, use the null sound.
  618. m_NoiseRunning = AllocPooledString("DoorSound.Null");
  619. }
  620. PrecacheScriptSound( STRING( m_NoiseRunning ) );
  621. if (GetLocalAngularVelocity() != vec3_angle )
  622. {
  623. //
  624. // If fan was spinning, and we went through transition or save/restore,
  625. // make sure we restart the sound. 1.5 sec delay is a magic number.
  626. //
  627. SetMoveDone( &CFuncRotating::SpinUpMove );
  628. SetMoveDoneTime( 1.5 );
  629. }
  630. }
  631. //-----------------------------------------------------------------------------
  632. // Purpose: Will hurt others based on how fast the brush is spinning.
  633. // Input : pOther -
  634. //-----------------------------------------------------------------------------
  635. void CFuncRotating::HurtTouch ( CBaseEntity *pOther )
  636. {
  637. // we can't hurt this thing, so we're not concerned with it
  638. if ( !pOther->m_takedamage )
  639. return;
  640. // calculate damage based on rotation speed
  641. m_flBlockDamage = GetLocalAngularVelocity().Length() / 10;
  642. pOther->TakeDamage( CTakeDamageInfo( this, this, m_flBlockDamage, DMG_CRUSH ) );
  643. Vector vecNewVelocity = pOther->GetAbsOrigin() - WorldSpaceCenter();
  644. VectorNormalize(vecNewVelocity);
  645. vecNewVelocity *= m_flBlockDamage;
  646. pOther->SetAbsVelocity( vecNewVelocity );
  647. }
  648. #define FANPITCHMIN 30
  649. #define FANPITCHMAX 100
  650. //-----------------------------------------------------------------------------
  651. // Purpose: Ramp pitch and volume up to maximum values, based on the difference
  652. // between how fast we're going vs how fast we can go.
  653. //-----------------------------------------------------------------------------
  654. void CFuncRotating::RampPitchVol( void )
  655. {
  656. //
  657. // Calc volume and pitch as % of maximum vol and pitch.
  658. //
  659. float fpct = fabs(m_flSpeed) / m_flMaxSpeed;
  660. float fvol = clamp(m_flVolume * fpct, 0, 1); // slowdown volume ramps down to 0
  661. float fpitch = FANPITCHMIN + (FANPITCHMAX - FANPITCHMIN) * fpct;
  662. int pitch = clamp(fpitch, 0, 255);
  663. if (pitch == PITCH_NORM)
  664. {
  665. pitch = PITCH_NORM - 1;
  666. }
  667. //
  668. // Update the fan's volume and pitch.
  669. //
  670. CBroadcastRecipientFilter filter;
  671. EmitSound_t ep;
  672. ep.m_nChannel = CHAN_STATIC;
  673. ep.m_pSoundName = STRING(m_NoiseRunning);
  674. ep.m_flVolume = fvol;
  675. ep.m_SoundLevel = ATTN_TO_SNDLVL( m_flAttenuation );
  676. ep.m_nFlags = SND_CHANGE_PITCH | SND_CHANGE_VOL;
  677. ep.m_nPitch = pitch;
  678. EmitSound( filter, entindex(), ep );
  679. }
  680. //-----------------------------------------------------------------------------
  681. // Purpose:
  682. // Output : float
  683. //-----------------------------------------------------------------------------
  684. float CFuncRotating::GetNextMoveInterval() const
  685. {
  686. if ( m_bStopAtStartPos )
  687. {
  688. return TICK_INTERVAL;
  689. }
  690. return 0.1f;
  691. }
  692. //-----------------------------------------------------------------------------
  693. // Purpose: stop our rotation value from becoming too large
  694. //-----------------------------------------------------------------------------
  695. void CFuncRotating::NormalizeAngleIfNeeded()
  696. {
  697. // entity max angle is 1000 rotations, so we'll renormalize after ~200.
  698. // note that we expect this to be a multiple of 360
  699. static const float kMaxAngle = 200 * 360.0f;
  700. // check our rotation for normalization every 15-30 seconds.
  701. static const float kTimeToRenormalize = 15.0f;
  702. // check angle
  703. QAngle angle = GetLocalAngles();
  704. bool ok = true;
  705. if ( angle.x > kMaxAngle ) { ok = false; angle.x -= kMaxAngle; }
  706. if ( angle.x < -kMaxAngle ) { ok = false; angle.x += kMaxAngle; }
  707. if ( angle.y > kMaxAngle ) { ok = false; angle.y -= kMaxAngle; }
  708. if ( angle.y < -kMaxAngle ) { ok = false; angle.y += kMaxAngle; }
  709. if ( angle.z > kMaxAngle ) { ok = false; angle.z -= kMaxAngle; }
  710. if ( angle.z < -kMaxAngle ) { ok = false; angle.z += kMaxAngle; }
  711. // if we changed it, update with new values
  712. if ( !ok )
  713. {
  714. // Disable interpolation on this entity for 1 frame (so it doesn't 'spin backwards 100 times')
  715. AddEffects( EF_NOINTERP );
  716. SetLocalAngles( angle );
  717. }
  718. // think at semi-random intervals so func rotatings don't all stack up on the same tick
  719. SetThink( &CFuncRotating::NormalizeAngleIfNeeded );
  720. SetNextThink( gpGlobals->curtime + RandomFloat( kTimeToRenormalize, kTimeToRenormalize * 2.0f ) );
  721. }
  722. //-----------------------------------------------------------------------------
  723. // Purpose: Sets the current speed to the given value and manages the sound effects.
  724. // Input : flNewSpeed - New speed in degrees per second.
  725. //-----------------------------------------------------------------------------
  726. void CFuncRotating::UpdateSpeed( float flNewSpeed )
  727. {
  728. float flOldSpeed = m_flSpeed;
  729. m_flSpeed = clamp( flNewSpeed, -m_flMaxSpeed, m_flMaxSpeed );
  730. if ( m_bStopAtStartPos )
  731. {
  732. int checkAxis = 2;
  733. // See if we got close to the starting orientation
  734. if ( m_vecMoveAng[0] != 0 )
  735. {
  736. checkAxis = 0;
  737. }
  738. else if ( m_vecMoveAng[1] != 0 )
  739. {
  740. checkAxis = 1;
  741. }
  742. float angDelta = anglemod( GetLocalAngles()[ checkAxis ] - m_angStart[ checkAxis ] );
  743. if ( angDelta > 180.0f )
  744. {
  745. angDelta -= 360.0f;
  746. }
  747. if ( flNewSpeed < 100 )
  748. {
  749. if ( flNewSpeed <= 25 && fabs( angDelta ) < 1.0f )
  750. {
  751. m_flTargetSpeed = 0;
  752. m_bStopAtStartPos = false;
  753. m_flSpeed = 0.0f;
  754. SetLocalAngles( m_angStart );
  755. }
  756. else if ( fabs( angDelta ) > 90.0f )
  757. {
  758. // Keep rotating at same speed for now
  759. m_flSpeed = flOldSpeed;
  760. }
  761. else
  762. {
  763. float minSpeed = fabs( angDelta );
  764. if ( minSpeed < 20 )
  765. minSpeed = 20;
  766. m_flSpeed = flOldSpeed > 0.0f ? minSpeed : -minSpeed;
  767. }
  768. }
  769. }
  770. if ( ( flOldSpeed == 0 ) && ( m_flSpeed != 0 ) )
  771. {
  772. // Starting to move - emit the sound.
  773. CBroadcastRecipientFilter filter;
  774. EmitSound_t ep;
  775. ep.m_nChannel = CHAN_STATIC;
  776. ep.m_pSoundName = STRING(m_NoiseRunning);
  777. ep.m_flVolume = 0.01;
  778. ep.m_SoundLevel = ATTN_TO_SNDLVL( m_flAttenuation );
  779. ep.m_nPitch = FANPITCHMIN;
  780. EmitSound( filter, entindex(), ep );
  781. RampPitchVol();
  782. }
  783. else if ( ( flOldSpeed != 0 ) && ( m_flSpeed == 0 ) )
  784. {
  785. // Stopping - stop the sound.
  786. StopSound( entindex(), CHAN_STATIC, STRING(m_NoiseRunning) );
  787. }
  788. else
  789. {
  790. // Changing speed - adjust the pitch and volume.
  791. RampPitchVol();
  792. }
  793. SetLocalAngularVelocity( m_vecMoveAng * m_flSpeed );
  794. }
  795. //-----------------------------------------------------------------------------
  796. // Purpose: Think function. Accelerates a func_rotating to a higher angular velocity.
  797. //-----------------------------------------------------------------------------
  798. void CFuncRotating::SpinUpMove( void )
  799. {
  800. //
  801. // Calculate our new speed.
  802. //
  803. bool bSpinUpDone = false;
  804. float flNewSpeed = fabs( m_flSpeed ) + 0.2 * m_flMaxSpeed * m_flFanFriction;
  805. if ( fabs( flNewSpeed ) >= fabs( m_flTargetSpeed ) )
  806. {
  807. // Reached our target speed.
  808. flNewSpeed = m_flTargetSpeed;
  809. bSpinUpDone = !m_bStopAtStartPos;
  810. }
  811. else if ( m_flTargetSpeed < 0 )
  812. {
  813. // Spinning up in reverse - negate the speed.
  814. flNewSpeed *= -1;
  815. }
  816. //
  817. // Apply the new speed, adjust sound pitch and volume.
  818. //
  819. UpdateSpeed( flNewSpeed );
  820. //
  821. // If we've met or exceeded target speed, stop spinning up.
  822. //
  823. if ( bSpinUpDone )
  824. {
  825. SetMoveDone( &CFuncRotating::RotateMove );
  826. RotateMove();
  827. }
  828. SetMoveDoneTime( GetNextMoveInterval() );
  829. }
  830. //-----------------------------------------------------------------------------
  831. // Purpose: Decelerates the rotator from a higher speed to a lower one.
  832. // Input : flTargetSpeed - Speed to spin down to.
  833. // Output : Returns true if we reached the target speed, false otherwise.
  834. //-----------------------------------------------------------------------------
  835. bool CFuncRotating::SpinDown( float flTargetSpeed )
  836. {
  837. //
  838. // Bleed off a little speed due to friction.
  839. //
  840. bool bSpinDownDone = false;
  841. float flNewSpeed = fabs( m_flSpeed ) - 0.1 * m_flMaxSpeed * m_flFanFriction;
  842. if ( flNewSpeed < 0 )
  843. {
  844. flNewSpeed = 0;
  845. }
  846. if ( fabs( flNewSpeed ) <= fabs( flTargetSpeed ) )
  847. {
  848. // Reached our target speed.
  849. flNewSpeed = flTargetSpeed;
  850. bSpinDownDone = !m_bStopAtStartPos;
  851. }
  852. else if ( m_flSpeed < 0 )
  853. {
  854. // Spinning down in reverse - negate the speed.
  855. flNewSpeed *= -1;
  856. }
  857. //
  858. // Apply the new speed, adjust sound pitch and volume.
  859. //
  860. UpdateSpeed( flNewSpeed );
  861. //
  862. // If we've met or exceeded target speed, stop spinning down.
  863. //
  864. return bSpinDownDone;
  865. }
  866. //-----------------------------------------------------------------------------
  867. // Purpose: Think function. Decelerates a func_rotating to a lower angular velocity.
  868. //-----------------------------------------------------------------------------
  869. void CFuncRotating::SpinDownMove( void )
  870. {
  871. //
  872. // If we've met or exceeded target speed, stop spinning down.
  873. //
  874. if ( SpinDown( m_flTargetSpeed ) )
  875. {
  876. SetMoveDone( &CFuncRotating::RotateMove );
  877. RotateMove();
  878. }
  879. else
  880. {
  881. SetMoveDoneTime( GetNextMoveInterval() );
  882. }
  883. }
  884. //-----------------------------------------------------------------------------
  885. // Purpose: Think function for reversing directions. Spins down to zero, then
  886. // starts spinning up to the target speed.
  887. //-----------------------------------------------------------------------------
  888. void CFuncRotating::ReverseMove( void )
  889. {
  890. if ( SpinDown( 0 ) )
  891. {
  892. // We've reached zero - spin back up to the target speed.
  893. SetTargetSpeed( m_flTargetSpeed );
  894. }
  895. else
  896. {
  897. SetMoveDoneTime( GetNextMoveInterval() );
  898. }
  899. }
  900. //-----------------------------------------------------------------------------
  901. // Purpose: Think function. Called while rotating at a constant angular velocity.
  902. //-----------------------------------------------------------------------------
  903. void CFuncRotating::RotateMove( void )
  904. {
  905. SetMoveDoneTime( 10 );
  906. if ( m_bStopAtStartPos )
  907. {
  908. SetMoveDoneTime( GetNextMoveInterval() );
  909. int checkAxis = 2;
  910. // See if we got close to the starting orientation
  911. if ( m_vecMoveAng[0] != 0 )
  912. {
  913. checkAxis = 0;
  914. }
  915. else if ( m_vecMoveAng[1] != 0 )
  916. {
  917. checkAxis = 1;
  918. }
  919. float angDelta = anglemod( GetLocalAngles()[ checkAxis ] - m_angStart[ checkAxis ] );
  920. if ( angDelta > 180.0f )
  921. angDelta -= 360.0f;
  922. QAngle avel = GetLocalAngularVelocity();
  923. // Delta per tick
  924. QAngle avelpertick = avel * TICK_INTERVAL;
  925. if ( fabs( angDelta ) < fabs( avelpertick[ checkAxis ] ) )
  926. {
  927. SetTargetSpeed( 0 );
  928. SetLocalAngles( m_angStart );
  929. m_bStopAtStartPos = false;
  930. }
  931. }
  932. }
  933. //-----------------------------------------------------------------------------
  934. // Purpose: Used for debug output. Returns the given speed considering our current
  935. // direction of rotation, so that positive values are forward and negative
  936. // values are backward.
  937. // Input : flSpeed - Angular speed in degrees per second.
  938. //-----------------------------------------------------------------------------
  939. float CFuncRotating::GetMoveSpeed( float flSpeed )
  940. {
  941. if ( m_vecMoveAng[0] != 0 )
  942. {
  943. return flSpeed * m_vecMoveAng[0];
  944. }
  945. if ( m_vecMoveAng[1] != 0 )
  946. {
  947. return flSpeed * m_vecMoveAng[1];
  948. }
  949. return flSpeed * m_vecMoveAng[2];
  950. }
  951. //-----------------------------------------------------------------------------
  952. // Purpose: Sets a new angular velocity to achieve.
  953. // Input : flSpeed - Target angular velocity in degrees per second.
  954. //-----------------------------------------------------------------------------
  955. void CFuncRotating::SetTargetSpeed( float flSpeed )
  956. {
  957. //
  958. // Make sure the sign is correct - positive for forward rotation,
  959. // negative for reverse rotation.
  960. //
  961. flSpeed = fabs( flSpeed );
  962. if ( m_bReversed )
  963. {
  964. flSpeed *= -1;
  965. }
  966. m_flTargetSpeed = flSpeed;
  967. //
  968. // If we don't accelerate, change to the new speed instantly.
  969. //
  970. if ( !HasSpawnFlags(SF_BRUSH_ACCDCC ) )
  971. {
  972. UpdateSpeed( m_flTargetSpeed );
  973. SetMoveDone( &CFuncRotating::RotateMove );
  974. }
  975. //
  976. // Otherwise deal with acceleration/deceleration:
  977. //
  978. else
  979. {
  980. //
  981. // Check for reversing directions.
  982. //
  983. if ((( m_flSpeed > 0 ) && ( m_flTargetSpeed < 0 )) ||
  984. (( m_flSpeed < 0 ) && ( m_flTargetSpeed > 0 )))
  985. {
  986. SetMoveDone( &CFuncRotating::ReverseMove );
  987. }
  988. //
  989. // If we are below the new target speed, spin up to the target speed.
  990. //
  991. else if ( fabs( m_flSpeed ) < fabs( m_flTargetSpeed ) )
  992. {
  993. SetMoveDone( &CFuncRotating::SpinUpMove );
  994. }
  995. //
  996. // If we are above the new target speed, spin down to the target speed.
  997. //
  998. else if ( fabs( m_flSpeed ) > fabs( m_flTargetSpeed ) )
  999. {
  1000. SetMoveDone( &CFuncRotating::SpinDownMove );
  1001. }
  1002. //
  1003. // We are already at the new target speed. Just keep rotating.
  1004. //
  1005. else
  1006. {
  1007. SetMoveDone( &CFuncRotating::RotateMove );
  1008. }
  1009. }
  1010. SetMoveDoneTime( GetNextMoveInterval() );
  1011. }
  1012. //-----------------------------------------------------------------------------
  1013. // Purpose: Called when a rotating brush is used by the player.
  1014. // Input : pActivator -
  1015. // pCaller -
  1016. // useType -
  1017. // value -
  1018. //-----------------------------------------------------------------------------
  1019. void CFuncRotating::RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  1020. {
  1021. //
  1022. // If the rotator is spinning, stop it.
  1023. //
  1024. if ( m_flSpeed != 0 )
  1025. {
  1026. SetTargetSpeed( 0 );
  1027. }
  1028. //
  1029. // Rotator is not moving, so start it.
  1030. //
  1031. else
  1032. {
  1033. SetTargetSpeed( m_flMaxSpeed );
  1034. }
  1035. // start renormalization thinker
  1036. SetThink( &CFuncRotating::NormalizeAngleIfNeeded );
  1037. SetNextThink( gpGlobals->curtime + 0.2f );
  1038. }
  1039. //-----------------------------------------------------------------------------
  1040. // Purpose: Input handler that reverses the direction of rotation.
  1041. //-----------------------------------------------------------------------------
  1042. void CFuncRotating::InputReverse( inputdata_t &inputdata )
  1043. {
  1044. m_bStopAtStartPos = false;
  1045. m_bReversed = !m_bReversed;
  1046. SetTargetSpeed( m_flSpeed );
  1047. }
  1048. //-----------------------------------------------------------------------------
  1049. // Purpose: Input handler for setting the speed of the rotator.
  1050. // Input : Float target angular velocity as a ratio of maximum speed [0, 1].
  1051. //-----------------------------------------------------------------------------
  1052. void CFuncRotating::InputSetSpeed( inputdata_t &inputdata )
  1053. {
  1054. m_bStopAtStartPos = false;
  1055. float flSpeed = inputdata.value.Float();
  1056. m_bReversed = flSpeed < 0 ? true : false;
  1057. flSpeed = fabs(flSpeed);
  1058. SetTargetSpeed( clamp( flSpeed, 0, 1 ) * m_flMaxSpeed );
  1059. }
  1060. //-----------------------------------------------------------------------------
  1061. //-----------------------------------------------------------------------------
  1062. void CFuncRotating::InputGetSpeed( inputdata_t &inputdata )
  1063. {
  1064. float flOutValue = m_flSpeed;
  1065. if ( flOutValue < 0 )
  1066. flOutValue *= -1;
  1067. m_OnGetSpeed.Set( flOutValue, inputdata.pActivator, inputdata.pCaller );
  1068. }
  1069. //-----------------------------------------------------------------------------
  1070. // Purpose: Input handler to start the rotator spinning.
  1071. //-----------------------------------------------------------------------------
  1072. void CFuncRotating::InputStart( inputdata_t &inputdata )
  1073. {
  1074. m_bStopAtStartPos = false;
  1075. SetTargetSpeed( m_flMaxSpeed );
  1076. }
  1077. //-----------------------------------------------------------------------------
  1078. // Purpose: Input handler to start the rotator spinning.
  1079. //-----------------------------------------------------------------------------
  1080. void CFuncRotating::InputStartForward( inputdata_t &inputdata )
  1081. {
  1082. m_bReversed = false;
  1083. SetTargetSpeed( m_flMaxSpeed );
  1084. }
  1085. //-----------------------------------------------------------------------------
  1086. // Purpose: Input handler to start the rotator spinning.
  1087. //-----------------------------------------------------------------------------
  1088. void CFuncRotating::InputStartBackward( inputdata_t &inputdata )
  1089. {
  1090. m_bStopAtStartPos = false;
  1091. m_bReversed = true;
  1092. SetTargetSpeed( m_flMaxSpeed );
  1093. }
  1094. //-----------------------------------------------------------------------------
  1095. // Purpose: Input handler to stop the rotator from spinning.
  1096. //-----------------------------------------------------------------------------
  1097. void CFuncRotating::InputStop( inputdata_t &inputdata )
  1098. {
  1099. m_bStopAtStartPos = false;
  1100. SetTargetSpeed( 0 );
  1101. }
  1102. //-----------------------------------------------------------------------------
  1103. // Purpose:
  1104. // Input : &inputdata -
  1105. //-----------------------------------------------------------------------------
  1106. void CFuncRotating::InputStopAtStartPos( inputdata_t &inputdata )
  1107. {
  1108. m_bStopAtStartPos = true;
  1109. SetTargetSpeed( 0 );
  1110. SetMoveDoneTime( GetNextMoveInterval() );
  1111. }
  1112. //-----------------------------------------------------------------------------
  1113. // Purpose: Starts the rotator if it is still, stops it if it is spinning.
  1114. //-----------------------------------------------------------------------------
  1115. void CFuncRotating::InputToggle( inputdata_t &inputdata )
  1116. {
  1117. if (m_flSpeed > 0)
  1118. {
  1119. SetTargetSpeed( 0 );
  1120. }
  1121. else
  1122. {
  1123. SetTargetSpeed( m_flMaxSpeed );
  1124. }
  1125. }
  1126. //-----------------------------------------------------------------------------
  1127. // Purpose: An entity has blocked the brush.
  1128. // Input : pOther -
  1129. //-----------------------------------------------------------------------------
  1130. void CFuncRotating::Blocked( CBaseEntity *pOther )
  1131. {
  1132. pOther->TakeDamage( CTakeDamageInfo( this, this, m_flBlockDamage, DMG_CRUSH ) );
  1133. }
  1134. //-----------------------------------------------------------------------------
  1135. // Purpose: Draw any debug text overlays
  1136. // Input :
  1137. // Output : Current text offset from the top
  1138. //-----------------------------------------------------------------------------
  1139. int CFuncRotating::DrawDebugTextOverlays(void)
  1140. {
  1141. int text_offset = BaseClass::DrawDebugTextOverlays();
  1142. if (m_debugOverlays & OVERLAY_TEXT_BIT)
  1143. {
  1144. char tempstr[512];
  1145. Q_snprintf( tempstr, sizeof( tempstr ),"Speed cur (target): %3.2f (%3.2f)", GetMoveSpeed( m_flSpeed ), GetMoveSpeed( m_flTargetSpeed ) );
  1146. EntityText(text_offset,tempstr,0);
  1147. text_offset++;
  1148. }
  1149. return text_offset;
  1150. }
  1151. class CFuncVPhysicsClip : public CBaseEntity
  1152. {
  1153. DECLARE_DATADESC();
  1154. DECLARE_CLASS( CFuncVPhysicsClip, CBaseEntity );
  1155. public:
  1156. void Spawn();
  1157. void Activate();
  1158. bool CreateVPhysics( void );
  1159. bool EntityPassesFilter( CBaseEntity *pOther );
  1160. bool ForceVPhysicsCollide( CBaseEntity *pEntity );
  1161. void InputEnable( inputdata_t &inputdata );
  1162. void InputDisable( inputdata_t &inputdata );
  1163. private:
  1164. string_t m_iFilterName;
  1165. CHandle<CBaseFilter> m_hFilter;
  1166. bool m_bDisabled;
  1167. };
  1168. // Global Savedata for base trigger
  1169. BEGIN_DATADESC( CFuncVPhysicsClip )
  1170. // Keyfields
  1171. DEFINE_KEYFIELD( m_iFilterName, FIELD_STRING, "filtername" ),
  1172. DEFINE_FIELD( m_hFilter, FIELD_EHANDLE ),
  1173. DEFINE_FIELD( m_bDisabled, FIELD_BOOLEAN ),
  1174. DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
  1175. DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
  1176. END_DATADESC()
  1177. LINK_ENTITY_TO_CLASS( func_clip_vphysics, CFuncVPhysicsClip );
  1178. void CFuncVPhysicsClip::Spawn( void )
  1179. {
  1180. SetMoveType( MOVETYPE_PUSH ); // so it doesn't get pushed by anything
  1181. SetSolid( SOLID_VPHYSICS );
  1182. AddSolidFlags( FSOLID_NOT_SOLID );
  1183. SetModel( STRING( GetModelName() ) );
  1184. AddEffects( EF_NODRAW );
  1185. CreateVPhysics();
  1186. VPhysicsGetObject()->EnableCollisions( !m_bDisabled );
  1187. }
  1188. bool CFuncVPhysicsClip::CreateVPhysics( void )
  1189. {
  1190. VPhysicsInitStatic();
  1191. return true;
  1192. }
  1193. void CFuncVPhysicsClip::Activate( void )
  1194. {
  1195. // Get a handle to my filter entity if there is one
  1196. if (m_iFilterName != NULL_STRING)
  1197. {
  1198. m_hFilter = dynamic_cast<CBaseFilter *>(gEntList.FindEntityByName( NULL, m_iFilterName ));
  1199. }
  1200. BaseClass::Activate();
  1201. }
  1202. bool CFuncVPhysicsClip::EntityPassesFilter( CBaseEntity *pOther )
  1203. {
  1204. CBaseFilter* pFilter = (CBaseFilter*)(m_hFilter.Get());
  1205. if ( pFilter )
  1206. return pFilter->PassesFilter( this, pOther );
  1207. if ( !pOther->VPhysicsGetObject() )
  1208. return false;
  1209. if ( pOther->GetMoveType() == MOVETYPE_VPHYSICS && pOther->VPhysicsGetObject()->IsMoveable() )
  1210. return true;
  1211. return false;
  1212. }
  1213. bool CFuncVPhysicsClip::ForceVPhysicsCollide( CBaseEntity *pEntity )
  1214. {
  1215. return EntityPassesFilter(pEntity);
  1216. }
  1217. void CFuncVPhysicsClip::InputEnable( inputdata_t &inputdata )
  1218. {
  1219. VPhysicsGetObject()->EnableCollisions(true);
  1220. m_bDisabled = false;
  1221. }
  1222. void CFuncVPhysicsClip::InputDisable( inputdata_t &inputdata )
  1223. {
  1224. VPhysicsGetObject()->EnableCollisions(false);
  1225. m_bDisabled = true;
  1226. }