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.

452 lines
12 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: This is the molotov weapon
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. // $NoKeywords: $
  8. //=============================================================================//
  9. #include "cbase.h"
  10. #include "npcevent.h"
  11. #include "basehlcombatweapon.h"
  12. #include "basecombatcharacter.h"
  13. #include "ai_basenpc.h"
  14. #include "AI_Memory.h"
  15. #include "player.h"
  16. #include "gamerules.h" // For g_pGameRules
  17. #include "weapon_molotov.h"
  18. #include "grenade_molotov.h"
  19. #include "in_buttons.h"
  20. #include "game.h"
  21. #include "vstdlib/random.h"
  22. #include "movevars_shared.h"
  23. // memdbgon must be the last include file in a .cpp file!!!
  24. #include "tier0/memdbgon.h"
  25. BEGIN_DATADESC( CWeaponMolotov )
  26. DEFINE_FIELD( m_nNumAmmoTypes, FIELD_INTEGER ),
  27. DEFINE_FIELD( m_bNeedDraw, FIELD_BOOLEAN ),
  28. DEFINE_FIELD( m_iThrowBits, FIELD_INTEGER ),
  29. DEFINE_FIELD( m_fNextThrowCheck, FIELD_TIME ),
  30. DEFINE_FIELD( m_vecTossVelocity, FIELD_VECTOR ),
  31. // Function Pointers
  32. DEFINE_FUNCTION( MolotovTouch ),
  33. END_DATADESC()
  34. IMPLEMENT_SERVERCLASS_ST(CWeaponMolotov, DT_WeaponMolotov)
  35. END_SEND_TABLE()
  36. LINK_ENTITY_TO_CLASS( weapon_molotov, CWeaponMolotov );
  37. PRECACHE_WEAPON_REGISTER(weapon_molotov);
  38. acttable_t CWeaponMolotov::m_acttable[] =
  39. {
  40. { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_THROW, true },
  41. };
  42. IMPLEMENT_ACTTABLE(CWeaponMolotov);
  43. void CWeaponMolotov::Precache( void )
  44. {
  45. PrecacheModel("models/props_junk/w_garb_beerbottle.mdl"); //<<TEMP>> need real model
  46. BaseClass::Precache();
  47. }
  48. void CWeaponMolotov::Spawn( void )
  49. {
  50. // Call base class first
  51. BaseClass::Spawn();
  52. m_bNeedDraw = true;
  53. SetModel( GetWorldModel() );
  54. UTIL_SetSize(this, Vector( -6, -6, -2), Vector(6, 6, 2));
  55. }
  56. //------------------------------------------------------------------------------
  57. // Purpose : Override to use molotovs pickup touch function
  58. // Input :
  59. // Output :
  60. //------------------------------------------------------------------------------
  61. void CWeaponMolotov::SetPickupTouch( void )
  62. {
  63. SetTouch(MolotovTouch);
  64. }
  65. //-----------------------------------------------------------------------------
  66. // Purpose: Override so give correct ammo
  67. // Input : pOther - the entity that touched me
  68. // Output :
  69. //-----------------------------------------------------------------------------
  70. void CWeaponMolotov::MolotovTouch( CBaseEntity *pOther )
  71. {
  72. // ---------------------------------------------------
  73. // First give weapon to touching entity if allowed
  74. // ---------------------------------------------------
  75. BaseClass::DefaultTouch(pOther);
  76. // ----------------------------------------------------
  77. // Give molotov ammo if touching client
  78. // ----------------------------------------------------
  79. if (pOther->GetFlags() & FL_CLIENT)
  80. {
  81. // ------------------------------------------------
  82. // If already owned weapon of this type remove me
  83. // ------------------------------------------------
  84. CBaseCombatCharacter* pBCC = ToBaseCombatCharacter( pOther );
  85. CWeaponMolotov* oldWeapon = (CWeaponMolotov*)pBCC->Weapon_OwnsThisType( GetClassname() );
  86. if (oldWeapon != this)
  87. {
  88. UTIL_Remove( this );
  89. }
  90. else
  91. {
  92. pBCC->GiveAmmo( 1, m_iSecondaryAmmoType );
  93. SetThink (NULL);
  94. }
  95. }
  96. }
  97. //-----------------------------------------------------------------------------
  98. // Purpose: Gets event from anim stream and throws the object
  99. // Input :
  100. // Output :
  101. //-----------------------------------------------------------------------------
  102. void CWeaponMolotov::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator )
  103. {
  104. switch( pEvent->event )
  105. {
  106. case EVENT_WEAPON_THROW:
  107. {
  108. CAI_BaseNPC *pNPC = GetOwner()->MyNPCPointer();
  109. if (!pNPC)
  110. {
  111. return;
  112. }
  113. CBaseEntity *pEnemy = pNPC->GetEnemy();
  114. if (!pEnemy)
  115. {
  116. return;
  117. }
  118. Vector vec_target = pNPC->GetEnemyLKP();
  119. // -----------------------------------------------------
  120. // Get position of throw
  121. // -----------------------------------------------------
  122. // If owner has a hand, set position to the hand bone position
  123. Vector launchPos;
  124. int iBIndex = pNPC->LookupBone("Bip01 R Hand");
  125. if (iBIndex != -1)
  126. {
  127. Vector origin;
  128. QAngle angles;
  129. pNPC->GetBonePosition( iBIndex, launchPos, angles);
  130. }
  131. // Otherwise just set to in front of the owner
  132. else
  133. {
  134. Vector vFacingDir = pNPC->BodyDirection2D( );
  135. vFacingDir = vFacingDir * 60.0;
  136. launchPos = pNPC->GetAbsOrigin()+vFacingDir;
  137. }
  138. //Vector vecVelocity = VecCheckToss( pNPC, launchPos, vec_target, 1.0 );
  139. ThrowMolotov( launchPos, m_vecTossVelocity);
  140. // Drop the weapon and remove as no more ammo
  141. pNPC->Weapon_Drop( this );
  142. UTIL_Remove( this );
  143. }
  144. break;
  145. default:
  146. BaseClass::Operator_HandleAnimEvent( pEvent, pOperator );
  147. break;
  148. }
  149. }
  150. //-----------------------------------------------------------------------------
  151. // Purpose:
  152. // Input :
  153. // Output :
  154. //-----------------------------------------------------------------------------
  155. bool CWeaponMolotov::ObjectInWay( void )
  156. {
  157. CBaseCombatCharacter *pOwner = GetOwner();
  158. if (!pOwner)
  159. {
  160. return false;
  161. }
  162. Vector vecSrc = pOwner->Weapon_ShootPosition( );
  163. Vector vecAiming = pOwner->BodyDirection2D( );
  164. trace_t tr;
  165. Vector vecEnd = vecSrc + (vecAiming * 32);
  166. UTIL_TraceLine( vecSrc, vecEnd, MASK_SOLID, pOwner, COLLISION_GROUP_NONE, &tr );
  167. if (tr.fraction < 1.0)
  168. {
  169. // Don't block on a living creature
  170. if (tr.m_pEnt)
  171. {
  172. CBaseEntity *pEntity = tr.m_pEnt;
  173. CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( pEntity );
  174. if (pBCC)
  175. {
  176. return false;
  177. }
  178. }
  179. return true;
  180. }
  181. else
  182. {
  183. return false;
  184. }
  185. }
  186. //-----------------------------------------------------------------------------
  187. // Purpose: Override to allow throw w/o LOS
  188. // Input :
  189. // Output :
  190. //-----------------------------------------------------------------------------
  191. bool CWeaponMolotov::WeaponLOSCondition(const Vector &ownerPos, const Vector &targetPos,bool bSetConditions)
  192. {
  193. // <<TODO>> should test if can throw from present location here...
  194. return true;
  195. }
  196. //-----------------------------------------------------------------------------
  197. // Purpose: Override to check throw
  198. // Input :
  199. // Output :
  200. //-----------------------------------------------------------------------------
  201. int CWeaponMolotov::WeaponRangeAttack1Condition( float flDot, float flDist )
  202. {
  203. // If things haven't changed too much since last time
  204. // just return that previously calculated value
  205. if (gpGlobals->curtime < m_fNextThrowCheck )
  206. {
  207. return m_iThrowBits;
  208. }
  209. if ( flDist < m_fMinRange1) {
  210. m_iThrowBits = COND_TOO_CLOSE_TO_ATTACK;
  211. }
  212. else if (flDist > m_fMaxRange1) {
  213. m_iThrowBits = COND_TOO_FAR_TO_ATTACK;
  214. }
  215. else if (flDot < 0.5) {
  216. m_iThrowBits = COND_NOT_FACING_ATTACK;
  217. }
  218. // If moving, can't throw.
  219. else if ( m_flGroundSpeed != 0 )
  220. {
  221. m_iThrowBits = COND_NONE;
  222. }
  223. else {
  224. // Ok we should check again as some time has passed
  225. // This function is only used by NPC's so we can cast to a Base Monster
  226. CAI_BaseNPC *pNPC = GetOwner()->MyNPCPointer();
  227. CBaseEntity *pEnemy = pNPC->GetEnemy();
  228. if (!pEnemy)
  229. {
  230. m_iThrowBits = COND_NONE;
  231. }
  232. // Get Enemy Position
  233. Vector vecTarget;
  234. pEnemy->CollisionProp()->NormalizedToWorldSpace( Vector( 0.5f, 0.5f, 0.0f ), &vecTarget );
  235. // Get Toss Vector
  236. Vector throwStart = pNPC->Weapon_ShootPosition();
  237. Vector vecToss;
  238. CBaseEntity* pBlocker = NULL;
  239. float throwDist = (throwStart - vecTarget).Length();
  240. float fGravity = GetCurrentGravity();
  241. float throwLimit = pNPC->ThrowLimit(throwStart, vecTarget, fGravity, 35, WorldAlignMins(), WorldAlignMaxs(), pEnemy, &vecToss, &pBlocker);
  242. // If I can make the throw (or most of the throw)
  243. if (!throwLimit || (throwLimit != throwDist && throwLimit > 0.8*throwDist))
  244. {
  245. m_vecTossVelocity = vecToss;
  246. m_iThrowBits = COND_CAN_RANGE_ATTACK1;
  247. }
  248. else
  249. {
  250. m_iThrowBits = COND_NONE;
  251. }
  252. }
  253. // don't check again for a while.
  254. m_fNextThrowCheck = gpGlobals->curtime + 0.33; // 1/3 second.
  255. return m_iThrowBits;
  256. }
  257. //-----------------------------------------------------------------------------
  258. // Purpose:
  259. //
  260. //
  261. //-----------------------------------------------------------------------------
  262. void CWeaponMolotov::ThrowMolotov( const Vector &vecSrc, const Vector &vecVelocity)
  263. {
  264. CGrenade_Molotov *pMolotov = (CGrenade_Molotov*)Create( "grenade_molotov", vecSrc, vec3_angle, GetOwner() );
  265. if (!pMolotov)
  266. {
  267. Msg("Couldn't make molotov!\n");
  268. return;
  269. }
  270. pMolotov->SetAbsVelocity( vecVelocity );
  271. // Tumble through the air
  272. QAngle angVel( random->RandomFloat ( -100, -500 ), random->RandomFloat ( -100, -500 ), random->RandomFloat ( -100, -500 ) );
  273. pMolotov->SetLocalAngularVelocity( angVel );
  274. pMolotov->SetThrower( GetOwner() );
  275. pMolotov->SetOwnerEntity( ((CBaseEntity*)GetOwner()) );
  276. }
  277. //-----------------------------------------------------------------------------
  278. // Purpose:
  279. //
  280. //
  281. //-----------------------------------------------------------------------------
  282. void CWeaponMolotov::PrimaryAttack( void )
  283. {
  284. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  285. if (!pPlayer)
  286. {
  287. return;
  288. }
  289. Vector vecSrc = pPlayer->WorldSpaceCenter();
  290. Vector vecFacing = pPlayer->BodyDirection3D( );
  291. vecSrc = vecSrc + vecFacing * 18.0;
  292. // BUGBUG: is this some hack because it's not at the eye position????
  293. vecSrc.z += 24.0f;
  294. // Player may have turned to face a wall during the throw anim in which case
  295. // we don't want to throw the SLAM into the wall
  296. if (ObjectInWay())
  297. {
  298. vecSrc = pPlayer->WorldSpaceCenter() + vecFacing * 5.0;
  299. }
  300. Vector vecAiming = pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES );
  301. vecAiming.z += 0.20; // Raise up so passes through reticle
  302. ThrowMolotov(vecSrc, vecAiming*800);
  303. pPlayer->RemoveAmmo( 1, m_iSecondaryAmmoType );
  304. // Don't fire again until fire animation has completed
  305. //m_flNextPrimaryAttack = gpGlobals->curtime + CurSequenceDuration();
  306. //<<TEMP>> - till real animation is avaible
  307. m_flNextPrimaryAttack = gpGlobals->curtime + 1.0;
  308. m_flNextSecondaryAttack = gpGlobals->curtime + 1.0;
  309. m_bNeedDraw = true;
  310. }
  311. //-----------------------------------------------------------------------------
  312. // Purpose:
  313. //
  314. //
  315. //-----------------------------------------------------------------------------
  316. void CWeaponMolotov::SecondaryAttack( void )
  317. {
  318. //<<TEMP>>
  319. // Hmmm... what should I do here?
  320. }
  321. //-----------------------------------------------------------------------------
  322. // Purpose:
  323. //
  324. //
  325. //-----------------------------------------------------------------------------
  326. void CWeaponMolotov::DrawAmmo( void )
  327. {
  328. // -------------------------------------------
  329. // Make sure I have ammo of the current type
  330. // -------------------------------------------
  331. CBaseCombatCharacter *pOwner = GetOwner();
  332. if (pOwner->GetAmmoCount(m_iSecondaryAmmoType) <=0)
  333. {
  334. pOwner->Weapon_Drop( this );
  335. UTIL_Remove(this);
  336. return;
  337. }
  338. Msg("Drawing Molotov...\n");
  339. m_bNeedDraw = false;
  340. //<<TEMP>> - till real animation is avaible
  341. m_flNextPrimaryAttack = gpGlobals->curtime + 2.0;
  342. m_flNextSecondaryAttack = gpGlobals->curtime + 2.0;
  343. }
  344. //-----------------------------------------------------------------------------
  345. // Purpose: Override so shotgun can do mulitple reloads in a row
  346. // Input :
  347. // Output :
  348. //-----------------------------------------------------------------------------
  349. void CWeaponMolotov::ItemPostFrame( void )
  350. {
  351. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  352. if (!pOwner)
  353. {
  354. return;
  355. }
  356. if ((pOwner->m_nButtons & IN_ATTACK2) && (m_flNextSecondaryAttack <= gpGlobals->curtime))
  357. {
  358. SecondaryAttack();
  359. }
  360. else if ((pOwner->m_nButtons & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime))
  361. {
  362. // Uses secondary ammo only
  363. if (pOwner->GetAmmoCount(m_iSecondaryAmmoType))
  364. {
  365. PrimaryAttack();
  366. }
  367. }
  368. else if (m_bNeedDraw)
  369. {
  370. DrawAmmo();
  371. }
  372. else
  373. {
  374. WeaponIdle( );
  375. }
  376. }
  377. //-----------------------------------------------------------------------------
  378. // Purpose: Constructor
  379. //-----------------------------------------------------------------------------
  380. CWeaponMolotov::CWeaponMolotov( void )
  381. {
  382. #ifdef _DEBUG
  383. m_vecTossVelocity.Init();
  384. #endif
  385. m_fMinRange1 = 200;
  386. m_fMaxRange1 = 1000;
  387. }