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.

422 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "c_prop_vehicle.h"
  9. #include "hud.h"
  10. #include <vgui_controls/Controls.h>
  11. #include <Color.h>
  12. #include "view.h"
  13. #include "engine/ivdebugoverlay.h"
  14. #include "movevars_shared.h"
  15. #include "iviewrender.h"
  16. #include "vgui/ISurface.h"
  17. #include "client_virtualreality.h"
  18. #include "../hud_crosshair.h"
  19. #include "sourcevr/isourcevirtualreality.h"
  20. // NVNT haptic utils
  21. #include "haptics/haptic_utils.h"
  22. // memdbgon must be the last include file in a .cpp file!!!
  23. #include "tier0/memdbgon.h"
  24. int ScreenTransform( const Vector& point, Vector& screen );
  25. extern ConVar default_fov;
  26. extern ConVar joy_response_move_vehicle;
  27. IMPLEMENT_CLIENTCLASS_DT(C_PropVehicleDriveable, DT_PropVehicleDriveable, CPropVehicleDriveable)
  28. RecvPropEHandle( RECVINFO(m_hPlayer) ),
  29. RecvPropInt( RECVINFO( m_nSpeed ) ),
  30. RecvPropInt( RECVINFO( m_nRPM ) ),
  31. RecvPropFloat( RECVINFO( m_flThrottle ) ),
  32. RecvPropInt( RECVINFO( m_nBoostTimeLeft ) ),
  33. RecvPropInt( RECVINFO( m_nHasBoost ) ),
  34. RecvPropInt( RECVINFO( m_nScannerDisabledWeapons ) ),
  35. RecvPropInt( RECVINFO( m_nScannerDisabledVehicle ) ),
  36. RecvPropInt( RECVINFO( m_bEnterAnimOn ) ),
  37. RecvPropInt( RECVINFO( m_bExitAnimOn ) ),
  38. RecvPropInt( RECVINFO( m_bUnableToFire ) ),
  39. RecvPropVector( RECVINFO( m_vecEyeExitEndpoint ) ),
  40. RecvPropBool( RECVINFO( m_bHasGun ) ),
  41. RecvPropVector( RECVINFO( m_vecGunCrosshair ) ),
  42. END_RECV_TABLE()
  43. BEGIN_DATADESC( C_PropVehicleDriveable )
  44. DEFINE_EMBEDDED( m_ViewSmoothingData ),
  45. END_DATADESC()
  46. ConVar r_VehicleViewClamp( "r_VehicleViewClamp", "1", FCVAR_CHEAT );
  47. #define ROLL_CURVE_ZERO 20 // roll less than this is clamped to zero
  48. #define ROLL_CURVE_LINEAR 90 // roll greater than this is copied out
  49. #define PITCH_CURVE_ZERO 10 // pitch less than this is clamped to zero
  50. #define PITCH_CURVE_LINEAR 45 // pitch greater than this is copied out
  51. // spline in between
  52. //-----------------------------------------------------------------------------
  53. // Purpose: Constructor
  54. //-----------------------------------------------------------------------------
  55. C_PropVehicleDriveable::C_PropVehicleDriveable() :
  56. m_iv_vecGunCrosshair( "C_PropVehicleDriveable::m_iv_vecGunCrosshair" )
  57. {
  58. m_hPrevPlayer = NULL;
  59. memset( &m_ViewSmoothingData, 0, sizeof( m_ViewSmoothingData ) );
  60. m_ViewSmoothingData.pVehicle = this;
  61. m_ViewSmoothingData.bClampEyeAngles = true;
  62. m_ViewSmoothingData.bDampenEyePosition = true;
  63. m_ViewSmoothingData.flPitchCurveZero = PITCH_CURVE_ZERO;
  64. m_ViewSmoothingData.flPitchCurveLinear = PITCH_CURVE_LINEAR;
  65. m_ViewSmoothingData.flRollCurveZero = ROLL_CURVE_ZERO;
  66. m_ViewSmoothingData.flRollCurveLinear = ROLL_CURVE_LINEAR;
  67. m_ViewSmoothingData.flFOV = m_flFOV = default_fov.GetFloat();
  68. AddVar( &m_vecGunCrosshair, &m_iv_vecGunCrosshair, LATCH_SIMULATION_VAR );
  69. }
  70. //-----------------------------------------------------------------------------
  71. // Purpose: De-constructor
  72. //-----------------------------------------------------------------------------
  73. C_PropVehicleDriveable::~C_PropVehicleDriveable()
  74. {
  75. }
  76. //-----------------------------------------------------------------------------
  77. // By default all driveable vehicles use the curve defined by the convar.
  78. //-----------------------------------------------------------------------------
  79. int C_PropVehicleDriveable::GetJoystickResponseCurve() const
  80. {
  81. return joy_response_move_vehicle.GetInt();
  82. }
  83. //-----------------------------------------------------------------------------
  84. // Purpose:
  85. //-----------------------------------------------------------------------------
  86. C_BaseCombatCharacter *C_PropVehicleDriveable::GetPassenger( int nRole )
  87. {
  88. if ( nRole == VEHICLE_ROLE_DRIVER )
  89. return m_hPlayer.Get();
  90. return NULL;
  91. }
  92. //-----------------------------------------------------------------------------
  93. // Returns the role of the passenger
  94. //-----------------------------------------------------------------------------
  95. int C_PropVehicleDriveable::GetPassengerRole( C_BaseCombatCharacter *pPassenger )
  96. {
  97. if ( m_hPlayer.Get() == pPassenger )
  98. return VEHICLE_ROLE_DRIVER;
  99. return VEHICLE_ROLE_NONE;
  100. }
  101. //-----------------------------------------------------------------------------
  102. // Purpose:
  103. // Input : updateType -
  104. //-----------------------------------------------------------------------------
  105. void C_PropVehicleDriveable::OnPreDataChanged( DataUpdateType_t updateType )
  106. {
  107. BaseClass::OnPreDataChanged( updateType );
  108. m_hPrevPlayer = m_hPlayer;
  109. }
  110. //-----------------------------------------------------------------------------
  111. // Purpose:
  112. //-----------------------------------------------------------------------------
  113. void C_PropVehicleDriveable::OnDataChanged( DataUpdateType_t updateType )
  114. {
  115. BaseClass::OnDataChanged( updateType );
  116. if ( m_hPlayer && !m_hPrevPlayer )
  117. {
  118. OnEnteredVehicle( m_hPlayer );
  119. SetNextClientThink( CLIENT_THINK_ALWAYS );
  120. g_ClientVirtualReality.AlignTorsoAndViewToWeapon();
  121. }
  122. else if ( !m_hPlayer && m_hPrevPlayer )
  123. {
  124. // NVNT notify haptics system of navigation exit
  125. OnExitedVehicle( m_hPrevPlayer );
  126. // They have just exited the vehicle.
  127. // Sometimes we never reach the end of our exit anim, such as if the
  128. // animation doesn't have fadeout 0 specified in the QC, so we fail to
  129. // catch it in VehicleViewSmoothing. Catch it here instead.
  130. m_ViewSmoothingData.bWasRunningAnim = false;
  131. SetNextClientThink( CLIENT_THINK_NEVER );
  132. }
  133. }
  134. //-----------------------------------------------------------------------------
  135. // Should this object cast render-to-texture shadows?
  136. //-----------------------------------------------------------------------------
  137. ShadowType_t C_PropVehicleDriveable::ShadowCastType()
  138. {
  139. CStudioHdr *pStudioHdr = GetModelPtr();
  140. if ( !pStudioHdr )
  141. return SHADOWS_NONE;
  142. if ( IsEffectActive(EF_NODRAW | EF_NOSHADOW) )
  143. return SHADOWS_NONE;
  144. // Always use render-to-texture. We'll always the dirty bits in our think function
  145. return SHADOWS_RENDER_TO_TEXTURE;
  146. }
  147. //-----------------------------------------------------------------------------
  148. // Mark the shadow as dirty while the vehicle is being driven
  149. //-----------------------------------------------------------------------------
  150. void C_PropVehicleDriveable::ClientThink( void )
  151. {
  152. // The vehicle is always dirty owing to pose parameters while it's being driven.
  153. g_pClientShadowMgr->MarkRenderToTextureShadowDirty( GetShadowHandle() );
  154. }
  155. //-----------------------------------------------------------------------------
  156. // Purpose:
  157. //-----------------------------------------------------------------------------
  158. void C_PropVehicleDriveable::DampenEyePosition( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles )
  159. {
  160. }
  161. //-----------------------------------------------------------------------------
  162. // Purpose: Modify the player view/camera while in a vehicle
  163. //-----------------------------------------------------------------------------
  164. void C_PropVehicleDriveable::GetVehicleViewPosition( int nRole, Vector *pAbsOrigin, QAngle *pAbsAngles, float *pFOV /*=NULL*/ )
  165. {
  166. SharedVehicleViewSmoothing( m_hPlayer,
  167. pAbsOrigin, pAbsAngles,
  168. m_bEnterAnimOn, m_bExitAnimOn,
  169. m_vecEyeExitEndpoint,
  170. &m_ViewSmoothingData,
  171. pFOV );
  172. }
  173. //-----------------------------------------------------------------------------
  174. // Futzes with the clip planes
  175. //-----------------------------------------------------------------------------
  176. void C_PropVehicleDriveable::GetVehicleClipPlanes( float &flZNear, float &flZFar ) const
  177. {
  178. // FIXME: Need something a better long-term, this fixes the buggy.
  179. flZNear = 6;
  180. }
  181. //-----------------------------------------------------------------------------
  182. // Renders hud elements
  183. //-----------------------------------------------------------------------------
  184. //-----------------------------------------------------------------------------
  185. // Simply used to return intensity value based upon current timer passed in
  186. //-----------------------------------------------------------------------------
  187. int GetFlashColorIntensity( int LowIntensity, int HighIntensity, bool Dimming, int Increment, int Timer )
  188. {
  189. if ( Dimming )
  190. return ( HighIntensity - Timer * Increment );
  191. else
  192. return ( LowIntensity + Timer * Increment );
  193. }
  194. #define TRIANGULATED_CROSSHAIR 1
  195. void C_PropVehicleDriveable::DrawHudElements( )
  196. {
  197. CHudTexture *pIcon;
  198. int iIconX, iIconY;
  199. if (m_bHasGun)
  200. {
  201. // draw crosshairs for vehicle gun
  202. pIcon = gHUD.GetIcon( "gunhair" );
  203. if ( pIcon != NULL )
  204. {
  205. float x, y;
  206. if( UseVR() )
  207. {
  208. C_BasePlayer *pPlayer = (C_BasePlayer *)GetPassenger( VEHICLE_ROLE_DRIVER );
  209. Vector vecStart, vecDirection;
  210. pPlayer->EyePositionAndVectors( &vecStart, &vecDirection, NULL, NULL );
  211. Vector vecEnd = vecStart + vecDirection * MAX_TRACE_LENGTH;
  212. trace_t tr;
  213. UTIL_TraceLine( vecStart, vecEnd, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
  214. Vector screen;
  215. screen.Init();
  216. ScreenTransform(tr.endpos, screen);
  217. int vx, vy, vw, vh;
  218. vgui::surface()->GetFullscreenViewport( vx, vy, vw, vh );
  219. float screenWidth = vw;
  220. float screenHeight = vh;
  221. x = 0.5f * ( 1.0f + screen[0] ) * screenWidth + 0.5f;
  222. y = 0.5f * ( 1.0f - screen[1] ) * screenHeight + 0.5f;
  223. }
  224. else
  225. {
  226. Vector screen;
  227. x = ScreenWidth()/2;
  228. y = ScreenHeight()/2;
  229. #if TRIANGULATED_CROSSHAIR
  230. ScreenTransform( m_vecGunCrosshair, screen );
  231. x += 0.5 * screen[0] * ScreenWidth() + 0.5;
  232. y -= 0.5 * screen[1] * ScreenHeight() + 0.5;
  233. #endif
  234. }
  235. x -= pIcon->Width() / 2;
  236. y -= pIcon->Height() / 2;
  237. Color clr = ( m_bUnableToFire ) ? gHUD.m_clrCaution : gHUD.m_clrNormal;
  238. pIcon->DrawSelf( x, y, clr );
  239. }
  240. if ( m_nScannerDisabledWeapons )
  241. {
  242. // Draw icons for scanners "weps disabled"
  243. pIcon = gHUD.GetIcon( "dmg_bio" );
  244. if ( pIcon )
  245. {
  246. iIconY = 467 - pIcon->Height() / 2;
  247. iIconX = 385;
  248. if ( !m_bScannerWepIcon )
  249. {
  250. pIcon->DrawSelf( XRES(iIconX), YRES(iIconY), Color( 0, 0, 255, 255 ) );
  251. m_bScannerWepIcon = true;
  252. m_iScannerWepFlashTimer = 0;
  253. m_bScannerWepDim = true;
  254. }
  255. else
  256. {
  257. pIcon->DrawSelf( XRES(iIconX), YRES(iIconY), Color( 0, 0, GetFlashColorIntensity(55, 255, m_bScannerWepDim, 10, m_iScannerWepFlashTimer), 255 ) );
  258. m_iScannerWepFlashTimer++;
  259. m_iScannerWepFlashTimer %= 20;
  260. if(!m_iScannerWepFlashTimer)
  261. m_bScannerWepDim ^= 1;
  262. }
  263. }
  264. }
  265. }
  266. if ( m_nScannerDisabledVehicle )
  267. {
  268. // Draw icons for scanners "vehicle disabled"
  269. pIcon = gHUD.GetIcon( "dmg_bio" );
  270. if ( pIcon )
  271. {
  272. iIconY = 467 - pIcon->Height() / 2;
  273. iIconX = 410;
  274. if ( !m_bScannerVehicleIcon )
  275. {
  276. pIcon->DrawSelf( XRES(iIconX), YRES(iIconY), Color( 0, 0, 255, 255 ) );
  277. m_bScannerVehicleIcon = true;
  278. m_iScannerVehicleFlashTimer = 0;
  279. m_bScannerVehicleDim = true;
  280. }
  281. else
  282. {
  283. pIcon->DrawSelf( XRES(iIconX), YRES(iIconY), Color( 0, 0, GetFlashColorIntensity(55, 255, m_bScannerVehicleDim, 10, m_iScannerVehicleFlashTimer), 255 ) );
  284. m_iScannerVehicleFlashTimer++;
  285. m_iScannerVehicleFlashTimer %= 20;
  286. if(!m_iScannerVehicleFlashTimer)
  287. m_bScannerVehicleDim ^= 1;
  288. }
  289. }
  290. }
  291. }
  292. //-----------------------------------------------------------------------------
  293. // Purpose:
  294. //-----------------------------------------------------------------------------
  295. void C_PropVehicleDriveable::RestrictView( float *pYawBounds, float *pPitchBounds,
  296. float *pRollBounds, QAngle &vecViewAngles )
  297. {
  298. int eyeAttachmentIndex = LookupAttachment( "vehicle_driver_eyes" );
  299. Vector vehicleEyeOrigin;
  300. QAngle vehicleEyeAngles;
  301. GetAttachmentLocal( eyeAttachmentIndex, vehicleEyeOrigin, vehicleEyeAngles );
  302. // Limit the yaw.
  303. if ( pYawBounds )
  304. {
  305. float flAngleDiff = AngleDiff( vecViewAngles.y, vehicleEyeAngles.y );
  306. flAngleDiff = clamp( flAngleDiff, pYawBounds[0], pYawBounds[1] );
  307. vecViewAngles.y = vehicleEyeAngles.y + flAngleDiff;
  308. }
  309. // Limit the pitch.
  310. if ( pPitchBounds )
  311. {
  312. float flAngleDiff = AngleDiff( vecViewAngles.x, vehicleEyeAngles.x );
  313. flAngleDiff = clamp( flAngleDiff, pPitchBounds[0], pPitchBounds[1] );
  314. vecViewAngles.x = vehicleEyeAngles.x + flAngleDiff;
  315. }
  316. // Limit the roll.
  317. if ( pRollBounds )
  318. {
  319. float flAngleDiff = AngleDiff( vecViewAngles.z, vehicleEyeAngles.z );
  320. flAngleDiff = clamp( flAngleDiff, pRollBounds[0], pRollBounds[1] );
  321. vecViewAngles.z = vehicleEyeAngles.z + flAngleDiff;
  322. }
  323. }
  324. //-----------------------------------------------------------------------------
  325. // Purpose:
  326. //-----------------------------------------------------------------------------
  327. void C_PropVehicleDriveable::UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd )
  328. {
  329. if ( r_VehicleViewClamp.GetInt() )
  330. {
  331. float pitchBounds[2] = { -85.0f, 25.0f };
  332. RestrictView( NULL, pitchBounds, NULL, pCmd->viewangles );
  333. }
  334. }
  335. //-----------------------------------------------------------------------------
  336. // Purpose:
  337. //-----------------------------------------------------------------------------
  338. void C_PropVehicleDriveable::OnEnteredVehicle( C_BaseCombatCharacter *pPassenger )
  339. {
  340. #if defined( WIN32 ) && !defined( _X360 )
  341. // NVNT notify haptics system of navigation change
  342. HapticsEnteredVehicle(this,pPassenger);
  343. #endif
  344. }
  345. // NVNT - added function
  346. void C_PropVehicleDriveable::OnExitedVehicle( C_BaseCombatCharacter *pPassenger )
  347. {
  348. #if defined( WIN32 ) && !defined( _X360 )
  349. // NVNT notify haptics system of navigation exit
  350. HapticsExitedVehicle(this,pPassenger);
  351. #endif
  352. }