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.

380 lines
9.8 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "basehlcombatweapon.h"
  9. #include "gamerules.h"
  10. #include "game.h"
  11. #include "in_buttons.h"
  12. #include "extinguisherjet.h"
  13. #include "entitylist.h"
  14. #include "fire.h"
  15. #include "ar2_explosion.h"
  16. #include "ndebugoverlay.h"
  17. #include "engine/IEngineSound.h"
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include "tier0/memdbgon.h"
  20. ConVar fire_extinguisher_debug( "fire_extinguisher_debug", "0" );
  21. ConVar fire_extinguisher_radius( "fire_extinguisher_radius", "45" );
  22. ConVar fire_extinguisher_distance( "fire_extinguisher_distance", "200" );
  23. ConVar fire_extinguisher_strength( "fire_extinguisher_strength", "0.97" ); //TODO: Stub for real numbers
  24. ConVar fire_extinguisher_explode_radius( "fire_extinguisher_explode_radius", "256" );
  25. ConVar fire_extinguisher_explode_strength( "fire_extinguisher_explode_strength", "0.3" ); //TODO: Stub for real numbers
  26. #define EXTINGUISHER_AMMO_RATE 0.2
  27. extern short g_sModelIndexFireball; // (in combatweapon.cpp) holds the index for the smoke cloud
  28. class CWeaponExtinguisher: public CHLSelectFireMachineGun
  29. {
  30. DECLARE_DATADESC();
  31. public:
  32. DECLARE_CLASS( CWeaponExtinguisher, CHLSelectFireMachineGun );
  33. DECLARE_SERVERCLASS();
  34. CWeaponExtinguisher();
  35. void Spawn( void );
  36. void Precache( void );
  37. void ItemPostFrame( void );
  38. void Event_Killed( const CTakeDamageInfo &info );
  39. void Equip( CBaseCombatCharacter *pOwner );
  40. protected:
  41. void StartJet( void );
  42. void StopJet( void );
  43. CExtinguisherJet *m_pJet;
  44. };
  45. IMPLEMENT_SERVERCLASS_ST(CWeaponExtinguisher, DT_WeaponExtinguisher)
  46. END_SEND_TABLE()
  47. LINK_ENTITY_TO_CLASS( weapon_extinguisher, CWeaponExtinguisher );
  48. PRECACHE_WEAPON_REGISTER( weapon_extinguisher );
  49. //---------------------------------------------------------
  50. // Save/Restore
  51. //---------------------------------------------------------
  52. BEGIN_DATADESC( CWeaponExtinguisher )
  53. DEFINE_FIELD( m_pJet, FIELD_CLASSPTR ),
  54. END_DATADESC()
  55. CWeaponExtinguisher::CWeaponExtinguisher( void )
  56. {
  57. m_pJet = NULL;
  58. }
  59. //-----------------------------------------------------------------------------
  60. // Purpose:
  61. //-----------------------------------------------------------------------------
  62. void CWeaponExtinguisher::Precache( void )
  63. {
  64. BaseClass::Precache();
  65. PrecacheScriptSound( "ExtinguisherCharger.Use" );
  66. UTIL_PrecacheOther( "env_extinguisherjet" );
  67. }
  68. //-----------------------------------------------------------------------------
  69. // Purpose:
  70. //-----------------------------------------------------------------------------
  71. void CWeaponExtinguisher::Spawn( void )
  72. {
  73. BaseClass::Spawn();
  74. m_takedamage = DAMAGE_YES;
  75. m_iHealth = 25;//FIXME: Define
  76. }
  77. //-----------------------------------------------------------------------------
  78. // Purpose:
  79. // Input : *pOwner -
  80. //-----------------------------------------------------------------------------
  81. void CWeaponExtinguisher::Equip( CBaseCombatCharacter *pOwner )
  82. {
  83. BaseClass::Equip( pOwner );
  84. m_takedamage = DAMAGE_NO;
  85. }
  86. //-----------------------------------------------------------------------------
  87. // Purpose:
  88. // Input : *pInflictor -
  89. // *pAttacker -
  90. // flDamage -
  91. // bitsDamageType -
  92. //-----------------------------------------------------------------------------
  93. void CWeaponExtinguisher::Event_Killed( const CTakeDamageInfo &info )
  94. {
  95. //TODO: Use a real effect
  96. if ( AR2Explosion *pExplosion = AR2Explosion::CreateAR2Explosion( GetAbsOrigin() ) )
  97. {
  98. pExplosion->SetLifetime( 10 );
  99. }
  100. //TODO: Use a real effect
  101. CPASFilter filter( GetAbsOrigin() );
  102. te->Explosion( filter, 0.0,
  103. &GetAbsOrigin(),
  104. g_sModelIndexFireball,
  105. 2.0,
  106. 15,
  107. TE_EXPLFLAG_NONE,
  108. 250,
  109. 100 );
  110. //Put out fire in a radius
  111. FireSystem_ExtinguishInRadius( GetAbsOrigin(), fire_extinguisher_explode_radius.GetInt(), fire_extinguisher_explode_strength.GetFloat() );
  112. SetThink( SUB_Remove );
  113. SetNextThink( gpGlobals->curtime + 0.1f );
  114. }
  115. //-----------------------------------------------------------------------------
  116. // Purpose: Turn the jet effect and noise on
  117. //-----------------------------------------------------------------------------
  118. void CWeaponExtinguisher::StartJet( void )
  119. {
  120. //See if the jet needs to be created
  121. if ( m_pJet == NULL )
  122. {
  123. m_pJet = (CExtinguisherJet *) CreateEntityByName( "env_extinguisherjet" );
  124. if ( m_pJet == NULL )
  125. {
  126. Msg( "Unable to create jet for weapon_extinguisher!\n" );
  127. return;
  128. }
  129. //Setup the jet
  130. m_pJet->m_bEmit = false;
  131. UTIL_SetOrigin( m_pJet, GetAbsOrigin() );
  132. m_pJet->SetParent( this );
  133. m_pJet->m_bUseMuzzlePoint = true;
  134. m_pJet->m_bAutoExtinguish = false;
  135. m_pJet->m_nLength = fire_extinguisher_distance.GetInt();
  136. }
  137. //Turn the jet on
  138. if ( m_pJet != NULL )
  139. {
  140. m_pJet->TurnOn();
  141. }
  142. }
  143. //-----------------------------------------------------------------------------
  144. // Purpose: Turn the jet effect and noise off
  145. //-----------------------------------------------------------------------------
  146. void CWeaponExtinguisher::StopJet( void )
  147. {
  148. //Turn the jet off
  149. if ( m_pJet != NULL )
  150. {
  151. m_pJet->TurnOff();
  152. }
  153. }
  154. //-----------------------------------------------------------------------------
  155. // Purpose:
  156. //-----------------------------------------------------------------------------
  157. void CWeaponExtinguisher::ItemPostFrame( void )
  158. {
  159. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  160. if ( pOwner == NULL )
  161. return;
  162. //Only shoot if we have ammo
  163. if ( pOwner->GetAmmoCount(m_iSecondaryAmmoType) <= 0 )
  164. {
  165. StopJet();
  166. return;
  167. }
  168. //See if we should try and extinguish fires
  169. if ( pOwner->m_nButtons & IN_ATTACK )
  170. {
  171. //Drain ammo
  172. if ( m_flNextPrimaryAttack < gpGlobals->curtime )
  173. {
  174. pOwner->RemoveAmmo( 1, m_iSecondaryAmmoType );
  175. m_flNextPrimaryAttack = gpGlobals->curtime + EXTINGUISHER_AMMO_RATE;
  176. }
  177. //If we're just run out...
  178. if ( pOwner->GetAmmoCount(m_iSecondaryAmmoType) <= 0 )
  179. {
  180. StopJet();
  181. return;
  182. }
  183. //Turn the jet on
  184. StartJet();
  185. Vector vTestPos, vMuzzlePos;
  186. Vector vForward, vRight, vUp;
  187. pOwner->EyeVectors( &vForward, &vRight, &vUp );
  188. vMuzzlePos = pOwner->Weapon_ShootPosition( );
  189. //FIXME: Need to get the exact same muzzle point!
  190. //FIXME: This needs to be adjusted so the server collision matches the visuals on the client
  191. vMuzzlePos += vForward * 15.0f;
  192. vMuzzlePos += vRight * 6.0f;
  193. vMuzzlePos += vUp * -4.0f;
  194. QAngle aTmp;
  195. VectorAngles( vForward, aTmp );
  196. aTmp[PITCH] += 10;
  197. AngleVectors( aTmp, &vForward );
  198. vTestPos = vMuzzlePos + ( vForward * fire_extinguisher_distance.GetInt() );
  199. trace_t tr;
  200. UTIL_TraceLine( vMuzzlePos, vTestPos, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
  201. //Extinguish the fire where we hit
  202. FireSystem_ExtinguishInRadius( tr.endpos, fire_extinguisher_radius.GetInt(), fire_extinguisher_strength.GetFloat() );
  203. //Debug visualization
  204. if ( fire_extinguisher_debug.GetInt() )
  205. {
  206. int radius = fire_extinguisher_radius.GetInt();
  207. NDebugOverlay::Line( vMuzzlePos, tr.endpos, 0, 0, 128, false, 0.0f );
  208. NDebugOverlay::Box( vMuzzlePos, Vector(-1, -1, -1), Vector(1, 1, 1), 0, 0, 128, false, 0.0f );
  209. NDebugOverlay::Box( tr.endpos, Vector(-2, -2, -2), Vector(2, 2, 2), 0, 0, 128, false, 0.0f );
  210. NDebugOverlay::Box( tr.endpos, Vector(-radius, -radius, -radius), Vector(radius, radius, radius), 0, 0, 255, false, 0.0f );
  211. }
  212. }
  213. else
  214. {
  215. StopJet();
  216. }
  217. }
  218. class CExtinguisherCharger : public CBaseToggle
  219. {
  220. public:
  221. DECLARE_CLASS( CExtinguisherCharger, CBaseToggle );
  222. void Spawn( void );
  223. bool CreateVPhysics();
  224. void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
  225. virtual int ObjectCaps( void ) { return (BaseClass::ObjectCaps() | FCAP_CONTINUOUS_USE) & ~FCAP_ACROSS_TRANSITION; }
  226. protected:
  227. float m_flNextCharge;
  228. bool m_bSoundOn;
  229. void TurnOff( void );
  230. DECLARE_DATADESC();
  231. };
  232. LINK_ENTITY_TO_CLASS( func_extinguishercharger, CExtinguisherCharger );
  233. BEGIN_DATADESC( CExtinguisherCharger )
  234. DEFINE_FIELD( m_flNextCharge, FIELD_TIME),
  235. DEFINE_FIELD( m_bSoundOn, FIELD_BOOLEAN ),
  236. DEFINE_FUNCTION( TurnOff ),
  237. END_DATADESC()
  238. //-----------------------------------------------------------------------------
  239. // Purpose: Spawn the object
  240. //-----------------------------------------------------------------------------
  241. void CExtinguisherCharger::Spawn( void )
  242. {
  243. Precache();
  244. SetSolid( SOLID_BSP );
  245. SetMoveType( MOVETYPE_PUSH );
  246. SetModel( STRING( GetModelName() ) );
  247. m_bSoundOn = false;
  248. CreateVPhysics();
  249. }
  250. //-----------------------------------------------------------------------------
  251. bool CExtinguisherCharger::CreateVPhysics()
  252. {
  253. VPhysicsInitStatic();
  254. return true;
  255. }
  256. //-----------------------------------------------------------------------------
  257. // Purpose:
  258. // Input : *pActivator -
  259. // *pCaller -
  260. // useType -
  261. // value -
  262. //-----------------------------------------------------------------------------
  263. void CExtinguisherCharger::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  264. {
  265. // Make sure that we have a caller
  266. if ( pActivator == NULL )
  267. return;
  268. // If it's not a player, ignore
  269. if ( pActivator->IsPlayer() == false )
  270. return;
  271. // Turn our sound on, if it's not already
  272. if ( m_bSoundOn == false )
  273. {
  274. EmitSound( "ExtinguisherCharger.Use" );
  275. m_bSoundOn = true;
  276. }
  277. SetNextThink( gpGlobals->curtime + 0.25 );
  278. SetThink( TurnOff );
  279. CBasePlayer *pPlayer = ToBasePlayer( pActivator );
  280. if ( pPlayer )
  281. {
  282. //FIXME: Need a way to do this silently
  283. pPlayer->GiveAmmo( 1, "extinguisher" );
  284. }
  285. }
  286. //-----------------------------------------------------------------------------
  287. // Purpose:
  288. //-----------------------------------------------------------------------------
  289. void CExtinguisherCharger::TurnOff( void )
  290. {
  291. //Turn the sound off
  292. if ( m_bSoundOn )
  293. {
  294. StopSound( "ExtinguisherCharger.Use" );
  295. m_bSoundOn = false;
  296. }
  297. }