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.

526 lines
15 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: One of the two ends of a portal pair which can be picked up and placed by weapon_camera
  4. //
  5. //===========================================================================//
  6. #include "cbase.h"
  7. #include "portal_mp_gamerules.h"
  8. #include "cvisibilitymonitor.h"
  9. #include "cegclientwrapper.h"
  10. // memdbgon must be the last include file in a .cpp file!!!
  11. #include "tier0/memdbgon.h"
  12. #define PROP_BUTTON_MODEL_NAME "models/props/switch001.mdl"
  13. #define PROP_UNDER_BUTTON_MODEL_NAME "models/props_underground/underground_testchamber_button.mdl"
  14. ConVar sv_portal2_button_hint_range( "sv_portal2_button_hint_range", "350.0", FCVAR_NONE );
  15. //-----------------------------------------------------------------------------
  16. // Context think
  17. //-----------------------------------------------------------------------------
  18. static const char *s_pTimerThinkContext = "TimerThinkContext";
  19. class CPropButton : public CBaseAnimating
  20. {
  21. public:
  22. DECLARE_CLASS( CPropButton, CBaseAnimating );
  23. DECLARE_DATADESC();
  24. CPropButton( void );
  25. virtual void Precache( void );
  26. virtual void Spawn( void );
  27. virtual bool CreateVPhysics( void );
  28. virtual void Activate( void );
  29. virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
  30. virtual int ObjectCaps( void ) { return (BaseClass::ObjectCaps() | FCAP_IMPULSE_USE ); }
  31. void AnimateThink( void );
  32. void TimerThink( void );
  33. void Lock();
  34. void Unlock();
  35. int DrawDebugTextOverlays();
  36. virtual const char *GetButtonModelName();
  37. private:
  38. void Press( CBaseEntity *pActivator );
  39. void InputPress( inputdata_t &input );
  40. void InputLock( inputdata_t &inputdata );
  41. void InputUnlock( inputdata_t &inputdata );
  42. void InputCancelPress( inputdata_t &input );
  43. void OnPressed( void );
  44. void OnButtonReset( void );
  45. EHANDLE m_hActivator;
  46. COutputEvent m_OnPressed;
  47. COutputEvent m_OnPressedOrange;
  48. COutputEvent m_OnPressedBlue;
  49. COutputEvent m_OnButtonReset;
  50. bool m_bLocked;
  51. float m_flDelayBeforeReset;
  52. float m_flGoalTime; // goal time when a pressed button should unpress
  53. bool m_bIsTimer;
  54. bool m_bTimerCancelled;
  55. bool m_bPreventFastReset;
  56. protected:
  57. virtual void LookUpAnimationSequences( void );
  58. // animation sequences for the button
  59. int m_UpSequence;
  60. int m_DownSequence;
  61. int m_IdleDownSequence;
  62. int m_IdleUpSequence;
  63. };
  64. LINK_ENTITY_TO_CLASS( prop_button, CPropButton );
  65. BEGIN_DATADESC( CPropButton )
  66. DEFINE_THINKFUNC( AnimateThink ),
  67. DEFINE_THINKFUNC( TimerThink ),
  68. DEFINE_KEYFIELD( m_flDelayBeforeReset, FIELD_FLOAT, "Delay" ),
  69. DEFINE_KEYFIELD( m_bIsTimer, FIELD_BOOLEAN, "IsTimer" ),
  70. DEFINE_KEYFIELD( m_bPreventFastReset, FIELD_BOOLEAN, "PreventFastReset" ),
  71. DEFINE_FIELD( m_hActivator, FIELD_EHANDLE ),
  72. DEFINE_FIELD( m_bLocked, FIELD_BOOLEAN ),
  73. DEFINE_FIELD( m_bTimerCancelled, FIELD_BOOLEAN ),
  74. DEFINE_FIELD( m_flGoalTime, FIELD_TIME ),
  75. DEFINE_FIELD( m_UpSequence, FIELD_INTEGER ),
  76. DEFINE_FIELD( m_DownSequence, FIELD_INTEGER ),
  77. DEFINE_FIELD( m_IdleDownSequence, FIELD_INTEGER ),
  78. DEFINE_FIELD( m_IdleUpSequence, FIELD_INTEGER ),
  79. DEFINE_INPUTFUNC( FIELD_VOID, "Press", InputPress ),
  80. DEFINE_INPUTFUNC( FIELD_VOID, "Lock", InputLock ),
  81. DEFINE_INPUTFUNC( FIELD_VOID, "Unlock", InputUnlock ),
  82. DEFINE_INPUTFUNC( FIELD_VOID, "CancelPress", InputCancelPress ),
  83. DEFINE_OUTPUT( m_OnPressed, "OnPressed" ),
  84. DEFINE_OUTPUT( m_OnPressedOrange, "OnPressedOrange" ),
  85. DEFINE_OUTPUT( m_OnPressedBlue, "OnPressedBlue" ),
  86. DEFINE_OUTPUT( m_OnButtonReset, "OnButtonReset" ),
  87. END_DATADESC()
  88. //-----------------------------------------------------------------------------
  89. // Purpose: constructor
  90. //-----------------------------------------------------------------------------
  91. CPropButton::CPropButton( void )
  92. {
  93. // set the default locked state on spawn
  94. m_bLocked = false;
  95. m_bTimerCancelled = false;
  96. RemoveEffects( EF_SHADOWDEPTH_NOCACHE );
  97. AddEffects( EF_MARKED_FOR_FAST_REFLECTION );
  98. }
  99. const char *CPropButton::GetButtonModelName()
  100. {
  101. return PROP_BUTTON_MODEL_NAME;
  102. }
  103. void CPropButton::LookUpAnimationSequences( void )
  104. {
  105. // look up animation sequences
  106. m_UpSequence = LookupSequence( "up" );
  107. m_DownSequence = LookupSequence( "down" );
  108. m_IdleUpSequence = LookupSequence( "idle" );
  109. m_IdleDownSequence = LookupSequence( "idle_down" );
  110. }
  111. //-----------------------------------------------------------------------------
  112. // Purpose:
  113. //-----------------------------------------------------------------------------
  114. void CPropButton::Precache( void )
  115. {
  116. PrecacheModel( GetButtonModelName() );
  117. // sounds for button
  118. PrecacheScriptSound( "Portal.button_down" );
  119. PrecacheScriptSound( "Portal.button_up" );
  120. PrecacheScriptSound( "Portal.button_locked" );
  121. PrecacheScriptSound( "Portal.room1_TickTock" );
  122. BaseClass::Precache();
  123. }
  124. //-----------------------------------------------------------------------------
  125. // Purpose:
  126. //-----------------------------------------------------------------------------
  127. void CPropButton::Spawn( void )
  128. {
  129. Precache();
  130. BaseClass::Spawn();
  131. SetMoveType( MOVETYPE_NONE );
  132. SetSolid( SOLID_VPHYSICS );
  133. SetModel( GetButtonModelName() );
  134. //Buttons are unpaintable
  135. AddFlag( FL_UNPAINTABLE );
  136. LookUpAnimationSequences();
  137. m_flGoalTime = 0;
  138. CreateVPhysics();
  139. VisibilityMonitor_AddEntity_NotVisibleThroughGlass( this, sv_portal2_button_hint_range.GetFloat() - 50.0f, NULL, NULL );
  140. // Never let crucial game components fade out!
  141. SetFadeDistance( -1.0f, 0.0f );
  142. SetGlobalFadeScale( 0.0f );
  143. // Start "up"
  144. ResetSequence( m_IdleUpSequence );
  145. }
  146. bool CPropButton::CreateVPhysics( void )
  147. {
  148. VPhysicsInitStatic();
  149. return true;
  150. }
  151. void CPropButton::Activate( void )
  152. {
  153. BaseClass::Activate();
  154. SetThink( &CPropButton::AnimateThink );
  155. SetNextThink( gpGlobals->curtime + 0.1f );
  156. }
  157. //-----------------------------------------------------------------------------
  158. // Purpose: Animate and catch edge cases for us stopping / starting our animation
  159. //-----------------------------------------------------------------------------
  160. void CPropButton::AnimateThink( void )
  161. {
  162. // Update our animation
  163. StudioFrameAdvance();
  164. DispatchAnimEvents( this );
  165. // this loop runs every time an animation finishes
  166. // and figures out the next animation to play.
  167. if ( IsSequenceFinished() )
  168. {
  169. int nSequence = GetSequence();
  170. if ( nSequence == m_UpSequence )
  171. {
  172. ResetSequence( m_IdleUpSequence );
  173. // fire the OnButtonReset output
  174. OnButtonReset();
  175. }
  176. else if ( nSequence == m_DownSequence )
  177. {
  178. ResetSequence( m_IdleDownSequence );
  179. // set the time for the button to reset
  180. m_flGoalTime = gpGlobals->curtime + m_flDelayBeforeReset;
  181. // fire the OnPressed output
  182. OnPressed();
  183. //if the button is a timer play the tick-tock sound while button is down
  184. if ( m_bIsTimer )
  185. {
  186. SetContextThink( &CPropButton::TimerThink, gpGlobals->curtime + 1.0f, s_pTimerThinkContext );
  187. if( !m_bPreventFastReset )
  188. {
  189. // since this is a timer button the button resets to the up position immediately after being pressed
  190. ResetSequence( m_UpSequence );
  191. }
  192. }
  193. }
  194. else if ( nSequence == m_IdleDownSequence )
  195. {
  196. // reset the button if it is time
  197. if ( gpGlobals->curtime > m_flGoalTime )
  198. {
  199. ResetSequence( m_UpSequence );
  200. }
  201. }
  202. }
  203. SetThink( &CPropButton::AnimateThink );
  204. SetNextThink( gpGlobals->curtime + 0.1f );
  205. }
  206. void CPropButton::TimerThink( void )
  207. {
  208. // determine if we should play the tick-tock sound
  209. if ( m_flGoalTime > gpGlobals->curtime )
  210. {
  211. EmitSound( "Portal.room1_TickTock" );
  212. // tick again in 1 second
  213. SetContextThink( &CPropButton::TimerThink, gpGlobals->curtime + 1.0f, s_pTimerThinkContext );
  214. }
  215. else
  216. {
  217. // stop ticking
  218. SetContextThink( NULL, TICK_NEVER_THINK, s_pTimerThinkContext );
  219. // skip the button reset events if the timer was cancelled
  220. if ( m_bTimerCancelled )
  221. {
  222. m_bTimerCancelled = false;
  223. }
  224. else
  225. {
  226. // play the button up sound
  227. EmitSound( "Portal.button_up" );
  228. // fire the OnReset output
  229. m_OnButtonReset.FireOutput( this, this );
  230. }
  231. }
  232. }
  233. //-----------------------------------------------------------------------------
  234. // Purpose: Press the button
  235. //-----------------------------------------------------------------------------
  236. void CPropButton::Press( CBaseEntity *pActivator )
  237. {
  238. if ( m_bLocked )
  239. {
  240. // button is locked so play a locked sound
  241. EmitSound( "Portal.button_locked" );
  242. }
  243. else
  244. {
  245. // animate the button being pressed
  246. int nCurrentSequence = GetSequence();
  247. if (nCurrentSequence == m_IdleUpSequence )
  248. {
  249. ResetSequence( m_DownSequence );
  250. // play the button press sound
  251. EmitSound( "Portal.button_down" );
  252. }
  253. m_hActivator = pActivator;
  254. }
  255. }
  256. //-----------------------------------------------------------------------------
  257. // Purpose: Press the button (via input)
  258. //-----------------------------------------------------------------------------
  259. void CPropButton::InputPress( inputdata_t &input )
  260. {
  261. Press( input.pActivator );
  262. }
  263. //-----------------------------------------------------------------------------
  264. // Purpose: Expire the timer
  265. //-----------------------------------------------------------------------------
  266. void CPropButton::InputCancelPress( inputdata_t &input )
  267. {
  268. m_bTimerCancelled = true;
  269. // set the goal time to the current time so the timer logic will expire
  270. m_flGoalTime = gpGlobals->curtime;
  271. }
  272. //-----------------------------------------------------------------------------
  273. // Purpose: Fire output for button being pressed
  274. //-----------------------------------------------------------------------------
  275. void CPropButton::OnPressed( void )
  276. {
  277. // fire the OnPressed output
  278. if ( m_hActivator.Get() != NULL )
  279. {
  280. CBaseEntity *pOther = dynamic_cast<CBaseEntity*>(m_hActivator.Get());
  281. if ( GameRules() && GameRules()->IsMultiplayer() && pOther && pOther->IsPlayer() )
  282. {
  283. if ( pOther->GetTeamNumber() == TEAM_RED )
  284. {
  285. m_OnPressedOrange.FireOutput( pOther, this );
  286. }
  287. else if ( pOther->GetTeamNumber() == TEAM_BLUE )
  288. {
  289. m_OnPressedBlue.FireOutput( pOther, this );
  290. }
  291. }
  292. m_OnPressed.FireOutput( m_hActivator.Get(), this );
  293. }
  294. else
  295. m_OnPressed.FireOutput( this, this );
  296. }
  297. //-----------------------------------------------------------------------------
  298. // Purpose: Fire output when button has reset after being pressed
  299. //-----------------------------------------------------------------------------
  300. void CPropButton::OnButtonReset( void )
  301. {
  302. // skip the button reset events if the timer was cancelled
  303. if ( m_bTimerCancelled )
  304. {
  305. m_bTimerCancelled = false;
  306. }
  307. else if( !m_bIsTimer ) // if the button is a timer then don't do this. the timer will handle this step when it expires.
  308. {
  309. // play the button up sound
  310. EmitSound( "Portal.button_up" );
  311. // fire the OnReset output
  312. m_OnButtonReset.FireOutput( this, this );
  313. }
  314. else
  315. {
  316. STEAMWORKS_SELFCHECK();
  317. }
  318. }
  319. //-----------------------------------------------------------------------------
  320. // Purpose:
  321. // Input : *pActivator -
  322. // *pCaller -
  323. // useType -
  324. // value -
  325. //-----------------------------------------------------------------------------
  326. void CPropButton::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  327. {
  328. CBasePlayer *pPlayer = ToBasePlayer( pActivator );
  329. if ( pPlayer )
  330. {
  331. // press the button
  332. Press( pActivator );
  333. }
  334. }
  335. //-----------------------------------------------------------------------------
  336. // Purpose: Locks the button. If locked, the button will play the locked sound
  337. // when the player tries to use it.
  338. //-----------------------------------------------------------------------------
  339. void CPropButton::Lock()
  340. {
  341. m_bLocked = true;
  342. }
  343. //-----------------------------------------------------------------------------
  344. // Purpose: Unlocks the button, making it able to be pressed again.
  345. //-----------------------------------------------------------------------------
  346. void CPropButton::Unlock()
  347. {
  348. m_bLocked = false;
  349. }
  350. //-----------------------------------------------------------------------------
  351. // Purpose: Locks the button. If locked, the button will play the locked sound
  352. // when the player tries to use it.
  353. //-----------------------------------------------------------------------------
  354. void CPropButton::InputLock( inputdata_t &inputdata )
  355. {
  356. Lock();
  357. }
  358. //-----------------------------------------------------------------------------
  359. // Purpose: Unlocks the button, making it able to be pressed again.
  360. //-----------------------------------------------------------------------------
  361. void CPropButton::InputUnlock( inputdata_t &inputdata )
  362. {
  363. Unlock();
  364. }
  365. //-----------------------------------------------------------------------------
  366. // Draw debug overlays
  367. //-----------------------------------------------------------------------------
  368. int CPropButton::DrawDebugTextOverlays()
  369. {
  370. int text_offset = BaseClass::DrawDebugTextOverlays();
  371. char tempstr[255];
  372. Q_snprintf( tempstr, sizeof(tempstr), "%s", m_bLocked ? "Locked" : "Unlocked" );
  373. EntityText( text_offset, tempstr, 0 );
  374. text_offset++;
  375. Q_snprintf( tempstr, sizeof(tempstr), "%s", m_bIsTimer ? "Is a timer" : "Is not a timer" );
  376. EntityText( text_offset, tempstr, 0 );
  377. text_offset++;
  378. Q_snprintf( tempstr, sizeof(tempstr), "Delay: %f", m_flDelayBeforeReset );
  379. EntityText( text_offset, tempstr, 0 );
  380. text_offset++;
  381. if ( ( m_flGoalTime - gpGlobals->curtime) > 0 )
  382. {
  383. Q_snprintf( tempstr, sizeof(tempstr), "Timer expires in: %.2f", ( m_flGoalTime - gpGlobals->curtime) );
  384. EntityText( text_offset, tempstr, 0 );
  385. text_offset++;
  386. }
  387. return text_offset;
  388. }
  389. //-----------------------------------------------------------------------------
  390. // Underground button
  391. //-----------------------------------------------------------------------------
  392. class CPropUnderButton : public CPropButton
  393. {
  394. DECLARE_CLASS( CPropUnderButton, CPropButton );
  395. DECLARE_DATADESC()
  396. public:
  397. virtual const char *GetButtonModelName();
  398. protected:
  399. virtual void LookUpAnimationSequences( void );
  400. };
  401. LINK_ENTITY_TO_CLASS( prop_under_button, CPropUnderButton );
  402. BEGIN_DATADESC( CPropUnderButton )
  403. END_DATADESC()
  404. const char *CPropUnderButton::GetButtonModelName()
  405. {
  406. return PROP_UNDER_BUTTON_MODEL_NAME;
  407. }
  408. void CPropUnderButton::LookUpAnimationSequences( void )
  409. {
  410. // look up animation sequences
  411. m_UpSequence = LookupSequence( "release" );
  412. m_DownSequence = LookupSequence( "press" );
  413. m_IdleUpSequence = LookupSequence( "release_idle" );
  414. m_IdleDownSequence = LookupSequence( "press_idle" );
  415. }