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.

462 lines
12 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Engineer's Laser Pointer
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "tf_fx_shared.h"
  8. #include "tf_weapon_laser_pointer.h"
  9. #include "in_buttons.h"
  10. // Client specific.
  11. #ifdef CLIENT_DLL
  12. #include "view.h"
  13. #include "beamdraw.h"
  14. #include "vgui/ISurface.h"
  15. #include <vgui/ILocalize.h>
  16. #include "vgui_controls/Controls.h"
  17. #include "hud_crosshair.h"
  18. #include "functionproxy.h"
  19. #include "materialsystem/imaterialvar.h"
  20. #include "toolframework_client.h"
  21. #include "input.h"
  22. #include "sourcevr/isourcevirtualreality.h"
  23. // forward declarations
  24. void ToolFramework_RecordMaterialParams( IMaterial *pMaterial );
  25. #else
  26. #include "tf_gamerules.h"
  27. #include "tf_obj_sentrygun.h"
  28. #endif
  29. #define TF_WEAPON_SNIPERRIFLE_CHARGE_PER_SEC 50.0
  30. #define TF_WEAPON_SNIPERRIFLE_UNCHARGE_PER_SEC 75.0
  31. #define TF_WEAPON_SNIPERRIFLE_DAMAGE_MIN 50
  32. #define TF_WEAPON_SNIPERRIFLE_DAMAGE_MAX 150
  33. #define TF_WEAPON_SNIPERRIFLE_RELOAD_TIME 1.5f
  34. #define TF_WEAPON_SNIPERRIFLE_ZOOM_TIME 0.3f
  35. #define TF_WEAPON_SNIPERRIFLE_NO_CRIT_AFTER_ZOOM_TIME 0.2f
  36. #define LASER_DOT_SPRITE_RED "effects/sniperdot_red.vmt"
  37. #define LASER_DOT_SPRITE_BLUE "effects/sniperdot_blue.vmt"
  38. //=============================================================================
  39. //
  40. // Weapon Laser Pointer tables.
  41. //
  42. IMPLEMENT_NETWORKCLASS_ALIASED( TFLaserPointer, DT_TFLaserPointer )
  43. BEGIN_NETWORK_TABLE_NOBASE( CTFLaserPointer, DT_LaserPointerLocalData )
  44. END_NETWORK_TABLE()
  45. BEGIN_NETWORK_TABLE( CTFLaserPointer, DT_TFLaserPointer )
  46. END_NETWORK_TABLE()
  47. BEGIN_PREDICTION_DATA( CTFLaserPointer )
  48. END_PREDICTION_DATA()
  49. LINK_ENTITY_TO_CLASS( tf_weapon_laser_pointer, CTFLaserPointer );
  50. PRECACHE_WEAPON_REGISTER( tf_weapon_laser_pointer );
  51. //=============================================================================
  52. //
  53. // Weapon Laser Pointer functions.
  54. //
  55. //-----------------------------------------------------------------------------
  56. // Purpose: Constructor.
  57. //-----------------------------------------------------------------------------
  58. CTFLaserPointer::CTFLaserPointer()
  59. {
  60. #ifdef GAME_DLL
  61. m_hLaserDot = NULL;
  62. #endif
  63. m_flNextAttack = 0.f;
  64. }
  65. //-----------------------------------------------------------------------------
  66. // Purpose: Destructor.
  67. //-----------------------------------------------------------------------------
  68. CTFLaserPointer::~CTFLaserPointer()
  69. {
  70. // Server specific.
  71. #ifdef GAME_DLL
  72. DestroyLaserDot();
  73. #endif
  74. }
  75. //-----------------------------------------------------------------------------
  76. // Purpose:
  77. //-----------------------------------------------------------------------------
  78. void CTFLaserPointer::Precache()
  79. {
  80. BaseClass::Precache();
  81. PrecacheModel( LASER_DOT_SPRITE_RED );
  82. PrecacheModel( LASER_DOT_SPRITE_BLUE );
  83. }
  84. //-----------------------------------------------------------------------------
  85. // Purpose:
  86. //-----------------------------------------------------------------------------
  87. bool CTFLaserPointer::Deploy( void )
  88. {
  89. if ( BaseClass::Deploy() )
  90. {
  91. #ifdef GAME_DLL
  92. SetContextThink( &CTFLaserPointer::CreateLaserDot, gpGlobals->curtime + 0.5f, "CREATE_LASER_DOT" );
  93. #endif
  94. m_bDeployed = true;
  95. return true;
  96. }
  97. return false;
  98. }
  99. //-----------------------------------------------------------------------------
  100. // Purpose:
  101. //-----------------------------------------------------------------------------
  102. bool CTFLaserPointer::Holster( CBaseCombatWeapon *pSwitchingTo )
  103. {
  104. if ( BaseClass::Holster( pSwitchingTo ) )
  105. {
  106. #ifdef GAME_DLL
  107. DestroyLaserDot();
  108. #endif
  109. m_bDeployed = false;
  110. return true;
  111. }
  112. return false;
  113. }
  114. //-----------------------------------------------------------------------------
  115. // Purpose:
  116. //-----------------------------------------------------------------------------
  117. void CTFLaserPointer::ItemPostFrame( void )
  118. {
  119. if ( !m_bDeployed )
  120. return;
  121. // Get the owning player.
  122. CTFPlayer *pPlayer = ToTFPlayer( GetOwner() );
  123. if ( !pPlayer )
  124. return;
  125. #ifdef GAME_DLL
  126. if ( m_hLaserDot )
  127. {
  128. UpdateLaserDot();
  129. }
  130. #endif
  131. BaseClass::ItemPostFrame();
  132. // Return to idle.
  133. if ( GetIdealActivity() == ACT_ITEM1_VM_RELOAD && !( pPlayer->m_nButtons & IN_ATTACK ) )
  134. {
  135. SendWeaponAnim( ACT_ITEM1_RELOAD_FINISH );
  136. if ( gpGlobals->curtime - m_flStartedFiring > 5.f )
  137. {
  138. m_bDoHandIdle = true;
  139. m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration();
  140. }
  141. }
  142. }
  143. void CTFLaserPointer::WeaponIdle( void )
  144. {
  145. #ifdef GAME_DLL
  146. if ( m_bDoHandIdle && !WeaponShouldBeLowered() && HasWeaponIdleTimeElapsed() )
  147. {
  148. m_bDoHandIdle = false;
  149. SendWeaponAnim( ACT_ITEM1_VM_IDLE_2 );
  150. m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration();
  151. return;
  152. }
  153. #endif
  154. BaseClass::WeaponIdle();
  155. }
  156. //-----------------------------------------------------------------------------
  157. // Purpose:
  158. //-----------------------------------------------------------------------------
  159. void CTFLaserPointer::PrimaryAttack( void )
  160. {
  161. CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() );
  162. if ( !pPlayer )
  163. return;
  164. if ( !CanAttack() )
  165. return;
  166. #ifdef GAME_DLL
  167. CObjectSentrygun *pSentry = dynamic_cast<CObjectSentrygun*>( pPlayer->GetObjectOfType( OBJ_SENTRYGUN ) );
  168. if ( !pSentry )
  169. return;
  170. pSentry->FireNextFrame();
  171. if ( GetIdealActivity() != ACT_ITEM1_VM_RELOAD )
  172. {
  173. m_flStartedFiring = gpGlobals->curtime;
  174. }
  175. SendWeaponAnim( ACT_ITEM1_VM_RELOAD );
  176. #endif
  177. }
  178. //-----------------------------------------------------------------------------
  179. // Purpose:
  180. //-----------------------------------------------------------------------------
  181. void CTFLaserPointer::SecondaryAttack( void )
  182. {
  183. CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() );
  184. if ( !pPlayer )
  185. return;
  186. if ( !CanAttack() )
  187. return;
  188. #ifdef GAME_DLL
  189. CObjectSentrygun *pSentry = dynamic_cast<CObjectSentrygun*>( pPlayer->GetObjectOfType( OBJ_SENTRYGUN ) );
  190. if ( !pSentry )
  191. return;
  192. if ( pSentry->GetUpgradeLevel() == 3 )
  193. {
  194. pSentry->FireRocketNextFrame();
  195. }
  196. #endif
  197. }
  198. //-----------------------------------------------------------------------------
  199. // Purpose:
  200. //-----------------------------------------------------------------------------
  201. void CTFLaserPointer::CreateLaserDot( void )
  202. {
  203. #ifdef GAME_DLL
  204. if ( !m_bDeployed )
  205. return;
  206. if ( m_hLaserDot )
  207. return;
  208. CBaseCombatCharacter *pPlayer = GetOwner();
  209. if ( !pPlayer )
  210. return;
  211. m_hLaserDot = CLaserDot::Create( GetAbsOrigin(), pPlayer, true );
  212. m_hLaserDot->ChangeTeam( pPlayer->GetTeamNumber() );
  213. UpdateLaserDot();
  214. #endif
  215. }
  216. //-----------------------------------------------------------------------------
  217. // Purpose:
  218. //-----------------------------------------------------------------------------
  219. void CTFLaserPointer::DestroyLaserDot( void )
  220. {
  221. #ifdef GAME_DLL
  222. CTFPlayer *pPlayer = ToTFPlayer( GetOwner() );
  223. if ( pPlayer )
  224. {
  225. CObjectSentrygun *pSentry = dynamic_cast<CObjectSentrygun*>( pPlayer->GetObjectOfType( OBJ_SENTRYGUN ) );
  226. if ( pSentry )
  227. {
  228. pSentry->ClearTarget();
  229. }
  230. }
  231. if ( m_hLaserDot )
  232. {
  233. UTIL_Remove( m_hLaserDot );
  234. m_hLaserDot = NULL;
  235. }
  236. #endif
  237. }
  238. //-----------------------------------------------------------------------------
  239. // Purpose:
  240. //-----------------------------------------------------------------------------
  241. void CTFLaserPointer::UpdateLaserDot( void )
  242. {
  243. #ifdef GAME_DLL
  244. CTFPlayer *pPlayer = ToTFPlayer( GetOwner() );
  245. if ( !pPlayer )
  246. return;
  247. Vector vecMuzzlePos = pPlayer->Weapon_ShootPosition();
  248. Vector forward;
  249. pPlayer->EyeVectors( &forward );
  250. Vector vecEndPos = vecMuzzlePos + ( forward * MAX_TRACE_LENGTH );
  251. trace_t trace;
  252. CTraceFilterIgnoreTeammatesAndTeamObjects filter( pPlayer, COLLISION_GROUP_NONE, pPlayer->GetTeamNumber() );
  253. UTIL_TraceLine( vecMuzzlePos, vecEndPos, MASK_SOLID, &filter, &trace );
  254. if ( m_hLaserDot )
  255. {
  256. CBaseEntity *pEntity = NULL;
  257. if ( trace.DidHitNonWorldEntity() )
  258. {
  259. pEntity = trace.m_pEnt;
  260. if ( !pEntity || !pEntity->m_takedamage )
  261. {
  262. pEntity = NULL;
  263. }
  264. else if ( pEntity->IsPlayer() )
  265. {
  266. // We lased a player target. We want to auto-aim on this guy for a short period of time.
  267. CObjectSentrygun *pSentry = dynamic_cast<CObjectSentrygun*>( pPlayer->GetObjectOfType( OBJ_SENTRYGUN ) );
  268. if ( pSentry )
  269. {
  270. pSentry->SetAutoAimTarget( ToTFPlayer( pEntity ) );
  271. }
  272. }
  273. }
  274. m_hLaserDot->Update( pEntity, trace.endpos, trace.plane.normal );
  275. }
  276. #endif
  277. }
  278. //=============================================================================
  279. //
  280. // Laser Dot functions.
  281. //
  282. IMPLEMENT_NETWORKCLASS_ALIASED( LaserDot, DT_LaserDot )
  283. BEGIN_NETWORK_TABLE( CLaserDot, DT_LaserDot )
  284. END_NETWORK_TABLE()
  285. LINK_ENTITY_TO_CLASS( env_laserdot, CLaserDot );
  286. BEGIN_DATADESC( CLaserDot )
  287. END_DATADESC()
  288. //-----------------------------------------------------------------------------
  289. // Purpose: Constructor.
  290. //-----------------------------------------------------------------------------
  291. CLaserDot::CLaserDot( void )
  292. {
  293. }
  294. //-----------------------------------------------------------------------------
  295. // Purpose: Destructor.
  296. //-----------------------------------------------------------------------------
  297. CLaserDot::~CLaserDot( void )
  298. {
  299. }
  300. //-----------------------------------------------------------------------------
  301. // Purpose:
  302. //-----------------------------------------------------------------------------
  303. CLaserDot* CLaserDot::Create( const Vector &origin, CBaseEntity *pOwner, bool bVisibleDot )
  304. {
  305. #ifdef CLIENT_DLL
  306. return NULL;
  307. #else
  308. CLaserDot *pDot = static_cast<CLaserDot*>( CBaseEntity::Create( "env_laserdot", origin, QAngle( 0.0f, 0.0f, 0.0f ) ) );
  309. if ( !pDot )
  310. return NULL;
  311. pDot->SetMoveType( MOVETYPE_NONE );
  312. pDot->AddSolidFlags( FSOLID_NOT_SOLID );
  313. pDot->AddEffects( EF_NOSHADOW );
  314. UTIL_SetSize( pDot, -Vector( 4.0f, 4.0f, 4.0f ), Vector( 4.0f, 4.0f, 4.0f ) );
  315. pDot->SetOwnerEntity( pOwner );
  316. pDot->AddEFlags( EFL_FORCE_CHECK_TRANSMIT );
  317. return pDot;
  318. #endif
  319. }
  320. #ifdef CLIENT_DLL
  321. //-----------------------------------------------------------------------------
  322. // Purpose:
  323. //-----------------------------------------------------------------------------
  324. int CLaserDot::DrawModel( int flags )
  325. {
  326. // Get the owning player.
  327. C_TFPlayer *pPlayer = ToTFPlayer( GetOwnerEntity() );
  328. if ( !pPlayer )
  329. return -1;
  330. // Get the sprite rendering position.
  331. Vector vecEndPos;
  332. float flSize = 6.0;
  333. if ( !pPlayer->IsDormant() )
  334. {
  335. Vector vecAttachment, vecDir;
  336. float flDist = MAX_TRACE_LENGTH;
  337. // Always draw the dot in front of our faces when in first-person.
  338. if ( pPlayer->IsLocalPlayer() )
  339. {
  340. // Take our view position and orientation
  341. vecAttachment = CurrentViewOrigin();
  342. vecDir = CurrentViewForward();
  343. if ( UseVR() )
  344. {
  345. // It will basically be a copy of CSniperDot::GetRenderingPositions in tf_weapon_sniperrife.cpp
  346. Assert ( !"Ask Joe Ludwig to fix CLaserDot::DrawModel() for VR." );
  347. }
  348. // Clamp the forward distance for the sniper's firstperson
  349. flDist = 384;
  350. flSize = 2.0;
  351. }
  352. else
  353. {
  354. // Take the owning player eye position and direction.
  355. vecAttachment = pPlayer->EyePosition();
  356. QAngle angles = pPlayer->EyeAngles();
  357. AngleVectors( angles, &vecDir );
  358. }
  359. trace_t trace;
  360. CTraceFilterIgnoreTeammatesAndTeamObjects filter( pPlayer, COLLISION_GROUP_NONE, pPlayer->GetTeamNumber() );
  361. UTIL_TraceLine( vecAttachment, vecAttachment + ( vecDir * flDist ), MASK_SOLID, &filter, &trace );
  362. // Backup off the hit plane, towards the source
  363. vecEndPos = trace.endpos + vecDir * -4;
  364. }
  365. else
  366. {
  367. // Just use our position if we can't predict it otherwise.
  368. vecEndPos = GetAbsOrigin();
  369. }
  370. // Draw our laser dot in space.
  371. CMatRenderContextPtr pRenderContext( materials );
  372. pRenderContext->Bind( m_hSpriteMaterial, this );
  373. float flLifeTime = gpGlobals->curtime - m_flChargeStartTime;
  374. float flStrength = RemapValClamped( flLifeTime, 0.0, TF_WEAPON_SNIPERRIFLE_DAMAGE_MAX / TF_WEAPON_SNIPERRIFLE_CHARGE_PER_SEC, 0.1, 1.0 );
  375. color32 innercolor = { 255, 255, 255, 255 };
  376. color32 outercolor = { 255, 255, 255, 128 };
  377. DrawSprite( vecEndPos, flSize, flSize, outercolor );
  378. DrawSprite( vecEndPos, flSize * flStrength, flSize * flStrength, innercolor );
  379. // Successful.
  380. return 1;
  381. }
  382. #endif