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.

487 lines
14 KiB

  1. //========= Copyright � 1996-2009, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Shared variables, etc. for the paint gun.
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "paint_color_manager.h"
  8. #include "shot_manipulator.h"
  9. #include "in_buttons.h"
  10. #include "debugoverlay_shared.h"
  11. #include "weapon_paintgun_shared.h"
  12. #include "paint_sprayer_shared.h"
  13. #include "paint_stream_shared.h"
  14. #ifdef CLIENT_DLL
  15. #include "c_weapon_paintgun.h"
  16. #include "c_portal_player.h"
  17. #include "igameevents.h"
  18. #else
  19. #include "weapon_paintgun.h"
  20. #include "portal_player.h"
  21. #include "paint_database.h"
  22. #include "portal_base2d.h"
  23. #include "prop_portal_shared.h"
  24. #include "env_speaker.h"
  25. #include "rumble_shared.h"
  26. #include "paint_database.h"
  27. //ConVar sv_paint_erase_range("sv_paint_erase_range", "2000", FCVAR_CHEAT);
  28. //ConVar sv_num_erase_ray("sv_num_erase_ray", "10", FCVAR_CHEAT, "number of ray that shoots out per shot");
  29. //ConVar sv_debug_suck_erase("sv_debug_suck_erase", "0", FCVAR_CHEAT);
  30. extern void Paint( CBaseEntity* pEntity, const Vector& pos, uint8 colorIndex, int nPainted );
  31. extern CPaintDatabase PaintDatabase;
  32. #endif
  33. #define paintgun_blobs_spread_radius 0.f //ConVar paintgun_blobs_spread_radius( "paintgun_blobs_spread_radius", "0.0f", FCVAR_REPLICATED | FCVAR_CHEAT, "The starting radius of the spread of the paint blobs from the gun" );
  34. #define paintgun_blobs_spread_angle 10.f //ConVar paintgun_blobs_spread_angle( "paintgun_blobs_spread_angle", "10.0f", FCVAR_REPLICATED | FCVAR_CHEAT, "The spread (in degrees) of the paint blobs from the gun" );
  35. #define paintgun_blobs_per_second 40.f //ConVar paintgun_blobs_per_second( "paintgun_blobs_per_second", "40.0f", FCVAR_REPLICATED | FCVAR_CHEAT, "Number of blobs shot out of the paint gun per second" );
  36. #define paintgun_blobs_min_speed 950.f //ConVar paintgun_blobs_min_speed( "paintgun_blobs_min_speed", "950.0f", FCVAR_REPLICATED | FCVAR_CHEAT, "The min speed of the blobs shot out of the paint gun" );
  37. #define paintgun_blobs_max_speed 1050.f //ConVar paintgun_blobs_max_speed( "paintgun_blobs_max_speed", "1050.0f", FCVAR_REPLICATED | FCVAR_CHEAT, "The max speed of the blobs shot out of the paint gun" );
  38. #define paintgun_shoot_position_trace_for_wall 1 //ConVar paintgun_shoot_position_trace_for_wall( "paintgun_shoot_position_trace_for_wall", "1", FCVAR_REPLICATED, "If the paint gun shooting position should test if it is inside a wall" );
  39. #define paintgun_blobs_streak_percent 10.f //ConVar paintgun_blobs_streak_percent( "paintgun_blobs_streak_percent", "10.0f", FCVAR_REPLICATED | FCVAR_CHEAT );
  40. #define paintgun_blobs_min_streak_time 0.1f //ConVar paintgun_blobs_min_streak_time( "paintgun_blobs_min_streak_time", "0.1f", FCVAR_REPLICATED | FCVAR_CHEAT );
  41. #define paintgun_blobs_max_streak_time 0.5f //ConVar paintgun_blobs_max_streak_time( "paintgun_blobs_max_streak_time", "0.5f", FCVAR_REPLICATED | FCVAR_CHEAT );
  42. #define paintgun_blobs_min_streak_speed_dampen 4500.f //ConVar paintgun_blobs_min_streak_speed_dampen( "paintgun_blobs_min_streak_speed_dampen", "4500.0f", FCVAR_REPLICATED | FCVAR_CHEAT );
  43. #define paintgun_blobs_max_streak_speed_dampen 5500.f //ConVar paintgun_blobs_max_streak_speed_dampen( "paintgun_blobs_max_streak_speed_dampen", "5500.0f", FCVAR_REPLICATED | FCVAR_CHEAT );
  44. #define paintgun_max_ammo 60 //ConVar paintgun_max_ammo( "paintgun_max_ammo", "60", FCVAR_REPLICATED, "The maximum amount of paint ammo allowed." );
  45. #define paintgun_ammo_type 0 //ConVar paintgun_ammo_type( "paintgun_ammo_type", "0", FCVAR_REPLICATED, "Type of paint ammo. 0: No ammo, 1: Global ammo per-gun, 2: Ammo per-paint type" );
  46. acttable_t CWeaponPaintGun::m_acttable[] =
  47. {
  48. { ACT_MP_STAND_IDLE, ACT_MP_STAND_PRIMARY, false },
  49. { ACT_MP_RUN, ACT_MP_RUN_PRIMARY, false },
  50. { ACT_MP_CROUCH_IDLE, ACT_MP_CROUCH_PRIMARY, false },
  51. { ACT_MP_CROUCHWALK, ACT_MP_CROUCHWALK_PRIMARY, false },
  52. { ACT_MP_JUMP_START, ACT_MP_JUMP_START_PRIMARY, false },
  53. { ACT_MP_JUMP_FLOAT, ACT_MP_JUMP_FLOAT_PRIMARY, false },
  54. { ACT_MP_JUMP_LAND, ACT_MP_JUMP_LAND_PRIMARY, false },
  55. { ACT_MP_AIRWALK, ACT_MP_AIRWALK_PRIMARY, false },
  56. { ACT_MP_RUN_SPEEDPAINT, ACT_MP_RUN_SPEEDPAINT_PRIMARY, false },
  57. { ACT_MP_DROWNING_PRIMARY, ACT_MP_DROWNING_PRIMARY, false },
  58. { ACT_MP_LONG_FALL, ACT_MP_LONG_FALL_PRIMARY, false },
  59. { ACT_MP_TRACTORBEAM_FLOAT, ACT_MP_TRACTORBEAM_FLOAT_PRIMARY, false },
  60. { ACT_MP_DEATH_CRUSH, ACT_MP_DEATH_CRUSH_PRIMARY, false },
  61. };
  62. IMPLEMENT_ACTTABLE(CWeaponPaintGun);
  63. void CWeaponPaintGun::ItemPostFrame()
  64. {
  65. bool bWasFiringPaint = m_bFiringPaint;
  66. bool bWasFiringErase = m_bFiringErase;
  67. // Only the player fires this way so we can cast
  68. CPortal_Player *pPlayer = ToPortalPlayer( GetOwner() );
  69. if ( pPlayer == NULL )
  70. return;
  71. // The paint clearing secondary function can always be used
  72. if( paintgun_ammo_type != PAINT_AMMO_NONE &&
  73. (pPlayer->m_nButtons & IN_ATTACK2) != 0 )
  74. {
  75. // Attack!
  76. SecondaryAttack();
  77. }
  78. else if( pPlayer->GetUseEntity() == NULL )
  79. {
  80. BaseClass::ItemPostFrame();
  81. }
  82. // Was shooting neither and is now shooting either
  83. if( !bWasFiringPaint && !bWasFiringErase &&
  84. ( m_bFiringPaint || m_bFiringErase ) )
  85. {
  86. #if !defined (CLIENT_DLL)
  87. StartShootingSound();
  88. #else
  89. pPlayer->SetAnimation( PLAYER_ATTACK1 );
  90. #endif
  91. }
  92. // Was shooting either and now is shooting neither
  93. else if( ( bWasFiringPaint || bWasFiringErase ) &&
  94. ( !m_bFiringPaint && !m_bFiringErase ) )
  95. {
  96. #if !defined (CLIENT_DLL)
  97. StopShootingSound();
  98. #else
  99. #endif
  100. }
  101. }
  102. void CWeaponPaintGun::PrimaryAttack()
  103. {
  104. bool bHasSelectedColor = false;
  105. #if !defined (CLIENT_DLL)
  106. bHasSelectedColor = HasPaintPower( (PaintPowerType)m_nCurrentColor.Get() );
  107. #else // CLIENT_DLL
  108. bHasSelectedColor = HasPaintPower( (PaintPowerType)m_nCurrentColor );
  109. #endif
  110. // Don't shoot if we dont have the selected color or any color at all
  111. if( !HasAnyPaintPower() || !bHasSelectedColor || !HasPaintAmmo( m_nCurrentColor ) )
  112. {
  113. m_bFiringPaint = m_bFiringErase = false;
  114. return;
  115. }
  116. #if !defined (CLIENT_DLL)
  117. SprayPaint( gpGlobals->frametime, m_nCurrentColor );
  118. if( !m_bFiringPaint )
  119. {
  120. IGameEvent *event = gameeventmanager->CreateEvent( "player_painted" );
  121. if ( event )
  122. {
  123. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  124. assert( pPlayer );
  125. event->SetInt("userid", pPlayer->GetUserID() );
  126. gameeventmanager->FireEvent( event );
  127. }
  128. }
  129. #else // CLIENT_DLL
  130. StartHoseEffect();
  131. //SprayPaint( gpGlobals->frametime, static_cast<PaintPowerType>( m_nCurrentColor ) );
  132. #endif //CLIENT_DLL
  133. m_bFiringPaint = true;
  134. m_bFiringErase = false;
  135. }
  136. void CWeaponPaintGun::SecondaryAttack()
  137. {
  138. if( paintgun_ammo_type == PAINT_AMMO_NONE )
  139. {
  140. # ifdef CLIENT_DLL
  141. StartHoseEffect();
  142. # else
  143. if( !m_bFiringErase )
  144. {
  145. IGameEvent *event = gameeventmanager->CreateEvent( "player_erased" );
  146. if ( event )
  147. {
  148. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  149. assert( pPlayer );
  150. event->SetInt("userid", pPlayer->GetUserID() );
  151. gameeventmanager->FireEvent( event );
  152. }
  153. }
  154. m_bFiringPaint = false;
  155. m_bFiringErase = true;
  156. SprayPaint( gpGlobals->frametime, NO_POWER );
  157. # endif
  158. }
  159. else
  160. {
  161. ResetAmmo();
  162. #ifdef GAME_DLL
  163. PaintDatabase.RemoveAllPaint();
  164. #endif
  165. }
  166. }
  167. bool CWeaponPaintGun::HasPaintPower( PaintPowerType nIndex )
  168. {
  169. return m_bHasPaint[nIndex];
  170. }
  171. bool CWeaponPaintGun::HasAnyPaintPower()
  172. {
  173. for( int i = 0; i < PAINT_POWER_TYPE_COUNT; ++i )
  174. {
  175. if( HasPaintPower( (PaintPowerType)i ) )
  176. {
  177. return true;
  178. }
  179. }
  180. return false;
  181. }
  182. void CWeaponPaintGun::WeaponIdle()
  183. {
  184. #ifdef CLIENT_DLL
  185. StopHoseEffect();
  186. #else
  187. if( m_bFiringPaint || m_bFiringErase )
  188. {
  189. StopShootingSound();
  190. }
  191. #endif
  192. m_bFiringPaint = m_bFiringErase = false;
  193. m_flAccumulatedTime = 1.0f/paintgun_blobs_per_second;
  194. #ifdef CLIENT_DLL
  195. #endif
  196. m_nBlobRandomSeed = 0;
  197. BaseClass::WeaponIdle();
  198. }
  199. bool CWeaponPaintGun::Holster( CBaseCombatWeapon *pSwitchingTo )
  200. {
  201. m_bFiringPaint = m_bFiringErase = false;
  202. #ifdef CLIENT_DLL
  203. ChangeRenderColor();
  204. StopHoseEffect();
  205. #else
  206. StopShootingSound();
  207. IGameEvent *event = gameeventmanager->CreateEvent( "holstered_paintgun" );
  208. if ( event )
  209. {
  210. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  211. if( pPlayer )
  212. {
  213. event->SetInt("userid", pPlayer->GetUserID() );
  214. gameeventmanager->FireEvent( event );
  215. }
  216. }
  217. #endif
  218. return BaseClass::Holster( pSwitchingTo );
  219. }
  220. void CWeaponPaintGun::Drop( const Vector &vecVelocity )
  221. {
  222. m_bFiringPaint = m_bFiringErase = false;
  223. Color color = MapPowerToVisualColor( m_nCurrentColor );
  224. if ( !HasAnyPaintPower() )
  225. color = MapPowerToVisualColor( NO_POWER );
  226. #ifdef CLIENT_DLL
  227. StopHoseEffect();
  228. #else
  229. StopShootingSound();
  230. IGameEvent *event = gameeventmanager->CreateEvent( "dropped_paintgun" );
  231. if ( event )
  232. {
  233. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  234. if( pPlayer )
  235. {
  236. event->SetInt("userid", pPlayer->GetUserID() );
  237. gameeventmanager->FireEvent( event );
  238. }
  239. }
  240. #endif
  241. SetRenderColor( color.r(), color.g(), color.b() );
  242. BaseClass::Drop( vecVelocity );
  243. }
  244. bool CWeaponPaintGun::Deploy()
  245. {
  246. #ifdef CLIENT_DLL
  247. ChangeRenderColor();
  248. #endif
  249. #ifndef CLIENT_DLL
  250. IGameEvent *event = gameeventmanager->CreateEvent( "deployed_paintgun" );
  251. if ( event )
  252. {
  253. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  254. if( pPlayer )
  255. {
  256. event->SetInt("userid", pPlayer->GetUserID() );
  257. event->SetInt("paintcount", GetPaintCount() );
  258. gameeventmanager->FireEvent( event );
  259. }
  260. }
  261. #endif //Only on server
  262. return BaseClass::Deploy();
  263. }
  264. void CWeaponPaintGun::SetSubType( int iType )
  265. {
  266. m_iSubType = iType;
  267. m_nCurrentColor = iType;
  268. #ifdef CLIENT_DLL
  269. ChangeRenderColor();
  270. #else
  271. EmitSound( "Player.WeaponSelected" );
  272. #endif
  273. BaseClass::SetSubType( iType );
  274. }
  275. PaintPowerType CWeaponPaintGun::GetCurrentPaint()
  276. {
  277. #ifdef CLIENT_DLL
  278. return (PaintPowerType)( m_nCurrentColor );
  279. #else //!CLIENT_DLL
  280. return (PaintPowerType)( m_nCurrentColor.Get() );
  281. #endif
  282. }
  283. //Paint Ammo!
  284. bool CWeaponPaintGun::HasPaintAmmo( unsigned paintType ) const
  285. {
  286. switch( paintgun_ammo_type )
  287. {
  288. case PAINT_AMMO_NONE:
  289. return true;
  290. case PAINT_AMMO_GLOBAL:
  291. return m_nPaintAmmo > 0;
  292. case PAINT_AMMO_PER_TYPE:
  293. Assert( paintType < PAINT_POWER_TYPE_COUNT );
  294. return m_PaintAmmoPerType[MIN( paintType, PAINT_POWER_TYPE_COUNT )] > 0;
  295. default:
  296. return true;
  297. }
  298. }
  299. void CWeaponPaintGun::DecrementPaintAmmo( unsigned paintType )
  300. {
  301. switch( paintgun_ammo_type )
  302. {
  303. case PAINT_AMMO_GLOBAL:
  304. --m_nPaintAmmo;
  305. break;
  306. case PAINT_AMMO_PER_TYPE:
  307. const int index = MIN( paintType, PAINT_POWER_TYPE_COUNT );
  308. m_PaintAmmoPerType.Set( index, m_PaintAmmoPerType[index] - 1 );
  309. break;
  310. }
  311. }
  312. void CWeaponPaintGun::ResetAmmo()
  313. {
  314. m_nPaintAmmo = paintgun_max_ammo;
  315. const int maxAmmo = paintgun_max_ammo;
  316. for( int i = 0; i < PAINT_POWER_TYPE_COUNT; ++i )
  317. {
  318. m_PaintAmmoPerType.Set( i, maxAmmo );
  319. }
  320. }
  321. void CWeaponPaintGun::SprayPaint( float flDeltaTime, int paintType )
  322. {
  323. if( flDeltaTime <= 0.0f )
  324. {
  325. return;
  326. }
  327. CPortal_Player *pOwner = ToPortalPlayer( GetOwner() );
  328. if ( pOwner == NULL )
  329. return;
  330. CPaintStream *pPaintStream = assert_cast< CPaintStream* >( m_hPaintStream.Get( paintType ).Get() );
  331. if ( !pPaintStream )
  332. return;
  333. m_flAccumulatedTime += flDeltaTime;
  334. Vector vecEyePosition = pOwner->EyePosition();
  335. Vector vecVelocity = pOwner->GetAbsVelocity();
  336. Vector vecAimDir = pOwner->GetAutoaimVector( 0 );
  337. Vector vecForwardVelocity = vecVelocity.Normalized() * DotProduct( vecVelocity, vecAimDir );
  338. Vector vecBlobFirePos = pOwner->GetPaintGunShootPosition();
  339. if( paintgun_shoot_position_trace_for_wall )
  340. {
  341. // Because the muzzle is so long, it can stick through a wall if the player is right up against it.
  342. // Make sure to adjust the shoot position in this condition by tracing a line between the eye point and the end of the muzzle.
  343. trace_t trace;
  344. Ray_t muzzleRay;
  345. muzzleRay.Init( vecEyePosition, vecBlobFirePos );
  346. CTraceFilterSimple traceFilter( pOwner, COLLISION_GROUP_NONE );
  347. UTIL_TraceRay( muzzleRay, MASK_SOLID, &traceFilter, &trace );
  348. //Check if there is a portal between the player's eye and the muzzle of the paint gun
  349. CPortal_Base2D *pInPortal = NULL;
  350. CPortal_Base2D *pOutPortal = NULL;
  351. if( UTIL_DidTraceTouchPortals( muzzleRay, trace, &pInPortal, &pOutPortal ) )
  352. {
  353. Vector vecPortalForward;
  354. AngleVectors( pInPortal->GetAbsAngles(), &vecPortalForward );
  355. Vector vecTraceDir = vecBlobFirePos - vecEyePosition;
  356. vecTraceDir.NormalizeInPlace();
  357. if( DotProduct( vecPortalForward, vecTraceDir ) < 0 )
  358. {
  359. UTIL_Portal_PointTransform( pInPortal->MatrixThisToLinked(), trace.endpos, vecBlobFirePos );
  360. UTIL_Portal_VectorTransform( pInPortal->MatrixThisToLinked(), vecAimDir, vecAimDir );
  361. }
  362. }
  363. else if ( trace.fraction < 1.0 && ( !trace.m_pEnt || trace.m_pEnt->m_takedamage == DAMAGE_NO ) )
  364. {
  365. // there is something between the eye and the end of the muzzle, most likely a wall
  366. // Move the muzzle position to the end position of the trace so that the wall gets painted
  367. vecBlobFirePos = trace.endpos;
  368. }
  369. //vecBlobFirePos = trace.endpos;
  370. }
  371. const float flBlobPerSecond = 1.0f/paintgun_blobs_per_second;
  372. while ( m_flAccumulatedTime >= flBlobPerSecond && HasPaintAmmo( paintType ) )
  373. {
  374. m_flAccumulatedTime -= flBlobPerSecond;
  375. CPaintBlob *pBlob = FirePaintBlob( vecBlobFirePos,
  376. vecBlobFirePos,
  377. vecForwardVelocity,
  378. vecAimDir,
  379. paintType,
  380. paintgun_blobs_spread_radius,
  381. paintgun_blobs_spread_angle,
  382. paintgun_blobs_min_speed,
  383. paintgun_blobs_max_speed,
  384. paintgun_blobs_streak_percent,
  385. paintgun_blobs_min_streak_time,
  386. paintgun_blobs_max_streak_time,
  387. paintgun_blobs_min_streak_speed_dampen,
  388. paintgun_blobs_max_streak_speed_dampen,
  389. false,
  390. false,
  391. pPaintStream,
  392. m_nBlobRandomSeed );
  393. pPaintStream->AddPaintBlob( pBlob );
  394. ++m_nBlobRandomSeed;
  395. DecrementPaintAmmo( paintType );
  396. }
  397. }