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.

439 lines
11 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Entities that capture the player's UI and move it into game design
  4. // as outputs.
  5. //
  6. // $NoKeywords: $
  7. //=============================================================================//
  8. #include "cbase.h"
  9. #include "entitylist.h"
  10. #include "util.h"
  11. #include "physics.h"
  12. #include "entityoutput.h"
  13. #include "player.h"
  14. #include "in_buttons.h"
  15. #include "basecombatweapon.h"
  16. #include "baseviewmodel.h"
  17. // memdbgon must be the last include file in a .cpp file!!!
  18. #include "tier0/memdbgon.h"
  19. //----------------------------------------------------------------
  20. // Spawn flags
  21. //----------------------------------------------------------------
  22. #define SF_GAMEUI_FREEZE_PLAYER 32
  23. #define SF_GAMEUI_HIDE_WEAPON 64
  24. #define SF_GAMEUI_USE_DEACTIVATES 128
  25. #define SF_GAMEUI_JUMP_DEACTIVATES 256
  26. class CGameUI : public CBaseEntity
  27. {
  28. public:
  29. DECLARE_CLASS( CGameUI, CBaseEntity );
  30. DECLARE_DATADESC();
  31. // Input handlers
  32. void InputDeactivate( inputdata_t &inputdata );
  33. void InputActivate( inputdata_t &inputdata );
  34. void Think( void );
  35. void Deactivate( CBaseEntity *pActivator );
  36. float m_flFieldOfView;
  37. CHandle<CBaseCombatWeapon> m_hSaveWeapon;
  38. COutputEvent m_playerOn;
  39. COutputEvent m_playerOff;
  40. COutputEvent m_pressedMoveLeft;
  41. COutputEvent m_pressedMoveRight;
  42. COutputEvent m_pressedForward;
  43. COutputEvent m_pressedBack;
  44. COutputEvent m_pressedAttack;
  45. COutputEvent m_pressedAttack2;
  46. COutputEvent m_unpressedMoveLeft;
  47. COutputEvent m_unpressedMoveRight;
  48. COutputEvent m_unpressedForward;
  49. COutputEvent m_unpressedBack;
  50. COutputEvent m_unpressedAttack;
  51. COutputEvent m_unpressedAttack2;
  52. COutputFloat m_xaxis;
  53. COutputFloat m_yaxis;
  54. COutputFloat m_attackaxis;
  55. COutputFloat m_attack2axis;
  56. bool m_bForceUpdate;
  57. int m_nLastButtonState;
  58. CHandle<CBasePlayer> m_player;
  59. };
  60. BEGIN_DATADESC( CGameUI )
  61. DEFINE_KEYFIELD( m_flFieldOfView, FIELD_FLOAT, "FieldOfView" ),
  62. DEFINE_FIELD( m_hSaveWeapon, FIELD_EHANDLE ),
  63. DEFINE_FIELD( m_bForceUpdate, FIELD_BOOLEAN ),
  64. DEFINE_FIELD( m_player, FIELD_EHANDLE ),
  65. DEFINE_FIELD( m_nLastButtonState, FIELD_INTEGER ),
  66. DEFINE_INPUTFUNC( FIELD_VOID, "Deactivate", InputDeactivate ),
  67. DEFINE_INPUTFUNC( FIELD_STRING, "Activate", InputActivate ),
  68. DEFINE_OUTPUT( m_playerOn, "PlayerOn" ),
  69. DEFINE_OUTPUT( m_playerOff, "PlayerOff" ),
  70. DEFINE_OUTPUT( m_pressedMoveLeft, "PressedMoveLeft" ),
  71. DEFINE_OUTPUT( m_pressedMoveRight, "PressedMoveRight" ),
  72. DEFINE_OUTPUT( m_pressedForward, "PressedForward" ),
  73. DEFINE_OUTPUT( m_pressedBack, "PressedBack" ),
  74. DEFINE_OUTPUT( m_pressedAttack, "PressedAttack" ),
  75. DEFINE_OUTPUT( m_pressedAttack2, "PressedAttack2" ),
  76. DEFINE_OUTPUT( m_unpressedMoveLeft, "UnpressedMoveLeft" ),
  77. DEFINE_OUTPUT( m_unpressedMoveRight, "UnpressedMoveRight" ),
  78. DEFINE_OUTPUT( m_unpressedForward, "UnpressedForward" ),
  79. DEFINE_OUTPUT( m_unpressedBack, "UnpressedBack" ),
  80. DEFINE_OUTPUT( m_unpressedAttack, "UnpressedAttack" ),
  81. DEFINE_OUTPUT( m_unpressedAttack2, "UnpressedAttack2" ),
  82. DEFINE_OUTPUT( m_xaxis, "XAxis" ),
  83. DEFINE_OUTPUT( m_yaxis, "YAxis" ),
  84. DEFINE_OUTPUT( m_attackaxis, "AttackAxis" ),
  85. DEFINE_OUTPUT( m_attack2axis, "Attack2Axis" ),
  86. END_DATADESC()
  87. LINK_ENTITY_TO_CLASS( game_ui, CGameUI );
  88. //-----------------------------------------------------------------------------
  89. // Purpose:
  90. //-----------------------------------------------------------------------------
  91. void CGameUI::InputDeactivate( inputdata_t &inputdata )
  92. {
  93. Deactivate( inputdata.pActivator );
  94. }
  95. //-----------------------------------------------------------------------------
  96. // Purpose:
  97. //-----------------------------------------------------------------------------
  98. void CGameUI::Deactivate( CBaseEntity *pActivator )
  99. {
  100. CBasePlayer *pPlayer = m_player;
  101. AssertMsg(pPlayer, "CGameUI deactivated without a player!");
  102. if (pPlayer)
  103. {
  104. // Re-enable player motion
  105. if ( FBitSet( m_spawnflags, SF_GAMEUI_FREEZE_PLAYER ) )
  106. {
  107. m_player->RemoveFlag( FL_ATCONTROLS );
  108. }
  109. // Restore weapons
  110. if ( FBitSet( m_spawnflags, SF_GAMEUI_HIDE_WEAPON ) )
  111. {
  112. // Turn the hud back on
  113. pPlayer->m_Local.m_iHideHUD &= ~HIDEHUD_WEAPONSELECTION;
  114. if ( m_hSaveWeapon.Get() )
  115. {
  116. m_player->Weapon_Switch( m_hSaveWeapon.Get() );
  117. m_hSaveWeapon = NULL;
  118. }
  119. if ( pPlayer->GetActiveWeapon() )
  120. {
  121. pPlayer->GetActiveWeapon()->Deploy();
  122. }
  123. }
  124. // Announce that the player is no longer controlling through us
  125. m_playerOff.FireOutput( pPlayer, this, 0 );
  126. // Clear out the axis controls
  127. m_xaxis.Set( 0, pPlayer, this );
  128. m_yaxis.Set( 0, pPlayer, this );
  129. m_attackaxis.Set( 0, pPlayer, this );
  130. m_attack2axis.Set( 0, pPlayer, this );
  131. m_nLastButtonState = 0;
  132. m_player = NULL;
  133. }
  134. else
  135. {
  136. Warning("%s Deactivate(): I have no player when called by %s!\n", GetEntityName().ToCStr(), pActivator->GetEntityName().ToCStr());
  137. }
  138. // Stop thinking
  139. SetNextThink( TICK_NEVER_THINK );
  140. }
  141. //------------------------------------------------------------------------------
  142. // Purpose :
  143. //------------------------------------------------------------------------------
  144. void CGameUI::InputActivate( inputdata_t &inputdata )
  145. {
  146. CBasePlayer *pPlayer;
  147. // Determine if we're specifying this as an override parameter
  148. if ( inputdata.value.StringID() != NULL_STRING )
  149. {
  150. CBaseEntity *pEntity = gEntList.FindEntityByName( NULL, inputdata.value.String(), this, inputdata.pActivator, inputdata.pCaller );
  151. if ( pEntity == NULL || pEntity->IsPlayer() == false )
  152. {
  153. Warning( "%s InputActivate: entity %s not found or is not a player!\n", GetEntityName().ToCStr(), inputdata.value.String() );
  154. return;
  155. }
  156. pPlayer = ToBasePlayer( pEntity );
  157. }
  158. else
  159. {
  160. // Otherwise try to use the activator
  161. if ( inputdata.pActivator == NULL || inputdata.pActivator->IsPlayer() == false )
  162. {
  163. Warning( "%s InputActivate: invalid or missing !activator!\n", GetEntityName().ToCStr() );
  164. return;
  165. }
  166. pPlayer = ToBasePlayer( inputdata.pActivator );
  167. }
  168. // If another player is already using these controls3, ignore this activation
  169. if ( m_player.Get() != NULL && pPlayer != m_player.Get() )
  170. {
  171. // TODO: We could allow this by calling Deactivate() at this point and continuing on -- jdw
  172. return;
  173. }
  174. // Setup our internal data
  175. m_player = pPlayer;
  176. m_playerOn.FireOutput( pPlayer, this, 0 );
  177. // Turn the hud off
  178. SetNextThink( gpGlobals->curtime );
  179. // Disable player's motion
  180. if ( FBitSet( m_spawnflags, SF_GAMEUI_FREEZE_PLAYER ) )
  181. {
  182. m_player->AddFlag( FL_ATCONTROLS );
  183. }
  184. // Store off and hide the currently held weapon
  185. if ( FBitSet( m_spawnflags, SF_GAMEUI_HIDE_WEAPON ) )
  186. {
  187. m_player->m_Local.m_iHideHUD |= HIDEHUD_WEAPONSELECTION;
  188. if ( m_player->GetActiveWeapon() )
  189. {
  190. m_hSaveWeapon = m_player->GetActiveWeapon();
  191. m_player->GetActiveWeapon()->Holster();
  192. m_player->ClearActiveWeapon();
  193. m_player->HideViewModels();
  194. }
  195. }
  196. // We must update our state
  197. m_bForceUpdate = true;
  198. }
  199. //------------------------------------------------------------------------------
  200. // Purpose: Samples the player's inputs and fires outputs based on what buttons
  201. // are currently held down.
  202. //------------------------------------------------------------------------------
  203. void CGameUI::Think( void )
  204. {
  205. CBasePlayer *pPlayer = m_player;
  206. // If player is gone, stop thinking
  207. if (pPlayer == NULL)
  208. {
  209. SetNextThink( TICK_NEVER_THINK );
  210. return;
  211. }
  212. // If we're forcing an update, state with a clean button state
  213. if ( m_bForceUpdate )
  214. {
  215. m_nLastButtonState = pPlayer->m_nButtons;
  216. }
  217. // ------------------------------------------------
  218. // Check that toucher is facing the UI within
  219. // the field of view tolerance. If not disconnect
  220. // ------------------------------------------------
  221. if (m_flFieldOfView > -1)
  222. {
  223. Vector vPlayerFacing;
  224. pPlayer->EyeVectors( &vPlayerFacing );
  225. Vector vPlayerToUI = GetAbsOrigin() - pPlayer->WorldSpaceCenter();
  226. VectorNormalize(vPlayerToUI);
  227. float flDotPr = DotProduct(vPlayerFacing,vPlayerToUI);
  228. if (flDotPr < m_flFieldOfView)
  229. {
  230. Deactivate( pPlayer );
  231. return;
  232. }
  233. }
  234. pPlayer->AddFlag( FL_ONTRAIN );
  235. SetNextThink( gpGlobals->curtime );
  236. // Deactivate if they jump or press +use.
  237. // FIXME: prevent the use from going through in player.cpp
  238. if ((( pPlayer->m_afButtonPressed & IN_USE ) && ( m_spawnflags & SF_GAMEUI_USE_DEACTIVATES )) ||
  239. (( pPlayer->m_afButtonPressed & IN_JUMP ) && ( m_spawnflags & SF_GAMEUI_JUMP_DEACTIVATES )))
  240. {
  241. Deactivate( pPlayer );
  242. return;
  243. }
  244. // Determine what's different
  245. int nButtonsChanged = ( pPlayer->m_nButtons ^ m_nLastButtonState );
  246. //
  247. // Handle all our possible input triggers
  248. //
  249. if ( nButtonsChanged & IN_MOVERIGHT )
  250. {
  251. if ( m_nLastButtonState & IN_MOVERIGHT )
  252. {
  253. m_unpressedMoveRight.FireOutput( pPlayer, this, 0 );
  254. }
  255. else
  256. {
  257. m_pressedMoveRight.FireOutput( pPlayer, this, 0 );
  258. }
  259. }
  260. if ( nButtonsChanged & IN_MOVELEFT )
  261. {
  262. if ( m_nLastButtonState & IN_MOVELEFT )
  263. {
  264. m_unpressedMoveLeft.FireOutput( pPlayer, this, 0 );
  265. }
  266. else
  267. {
  268. m_pressedMoveLeft.FireOutput( pPlayer, this, 0 );
  269. }
  270. }
  271. if ( nButtonsChanged & IN_FORWARD )
  272. {
  273. if ( m_nLastButtonState & IN_FORWARD )
  274. {
  275. m_unpressedForward.FireOutput( pPlayer, this, 0 );
  276. }
  277. else
  278. {
  279. m_pressedForward.FireOutput( pPlayer, this, 0 );
  280. }
  281. }
  282. if ( nButtonsChanged & IN_BACK )
  283. {
  284. if ( m_nLastButtonState & IN_BACK )
  285. {
  286. m_unpressedBack.FireOutput( pPlayer, this, 0 );
  287. }
  288. else
  289. {
  290. m_pressedBack.FireOutput( pPlayer, this, 0 );
  291. }
  292. }
  293. if ( nButtonsChanged & IN_ATTACK )
  294. {
  295. if ( m_nLastButtonState & IN_ATTACK )
  296. {
  297. m_unpressedAttack.FireOutput( pPlayer, this, 0 );
  298. }
  299. else
  300. {
  301. m_pressedAttack.FireOutput( pPlayer, this, 0 );
  302. }
  303. }
  304. if ( nButtonsChanged & IN_ATTACK2 )
  305. {
  306. if ( m_nLastButtonState & IN_ATTACK2 )
  307. {
  308. m_unpressedAttack2.FireOutput( pPlayer, this, 0 );
  309. }
  310. else
  311. {
  312. m_pressedAttack2.FireOutput( pPlayer, this, 0 );
  313. }
  314. }
  315. // Setup for the next frame
  316. m_nLastButtonState = pPlayer->m_nButtons;
  317. float x = 0, y = 0, attack = 0, attack2 = 0;
  318. if ( pPlayer->m_nButtons & IN_MOVERIGHT )
  319. {
  320. x = 1;
  321. }
  322. else if ( pPlayer->m_nButtons & IN_MOVELEFT )
  323. {
  324. x = -1;
  325. }
  326. if ( pPlayer->m_nButtons & IN_FORWARD )
  327. {
  328. y = 1;
  329. }
  330. else if ( pPlayer->m_nButtons & IN_BACK )
  331. {
  332. y = -1;
  333. }
  334. if ( pPlayer->m_nButtons & IN_ATTACK )
  335. {
  336. attack = 1;
  337. }
  338. if ( pPlayer->m_nButtons & IN_ATTACK2 )
  339. {
  340. attack2 = 1;
  341. }
  342. //
  343. // Fire the analog outputs if they changed.
  344. //
  345. if ( m_bForceUpdate || ( m_xaxis.Get() != x ) )
  346. {
  347. m_xaxis.Set( x, pPlayer, this );
  348. }
  349. if ( m_bForceUpdate || ( m_yaxis.Get() != y ) )
  350. {
  351. m_yaxis.Set( y, pPlayer, this );
  352. }
  353. if ( m_bForceUpdate || ( m_attackaxis.Get() != attack ) )
  354. {
  355. m_attackaxis.Set( attack, pPlayer, this );
  356. }
  357. if ( m_bForceUpdate || ( m_attack2axis.Get() != attack2 ) )
  358. {
  359. m_attack2axis.Set( attack2, pPlayer, this );
  360. }
  361. m_bForceUpdate = false;
  362. }