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.

996 lines
25 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "basehlcombatweapon.h"
  8. #include "player.h"
  9. #include "gamerules.h"
  10. #include "grenade_tripmine.h"
  11. #include "grenade_satchel.h"
  12. #include "entitylist.h"
  13. #include "weapon_slam.h"
  14. #include "npcevent.h"
  15. #include "in_buttons.h"
  16. #include "engine/IEngineSound.h"
  17. // memdbgon must be the last include file in a .cpp file!!!
  18. #include "tier0/memdbgon.h"
  19. #define SLAM_PRIMARY_VOLUME 450
  20. BEGIN_DATADESC( CWeapon_SLAM )
  21. DEFINE_FIELD( m_tSlamState, FIELD_INTEGER ),
  22. DEFINE_FIELD( m_bDetonatorArmed, FIELD_BOOLEAN ),
  23. DEFINE_FIELD( m_bNeedDetonatorDraw, FIELD_BOOLEAN ),
  24. DEFINE_FIELD( m_bNeedDetonatorHolster, FIELD_BOOLEAN ),
  25. DEFINE_FIELD( m_bNeedReload, FIELD_BOOLEAN ),
  26. DEFINE_FIELD( m_bClearReload, FIELD_BOOLEAN ),
  27. DEFINE_FIELD( m_bThrowSatchel, FIELD_BOOLEAN ),
  28. DEFINE_FIELD( m_bAttachSatchel, FIELD_BOOLEAN ),
  29. DEFINE_FIELD( m_bAttachTripmine, FIELD_BOOLEAN ),
  30. DEFINE_FIELD( m_flWallSwitchTime, FIELD_TIME ),
  31. // Function Pointers
  32. DEFINE_FUNCTION( SLAMThink ),
  33. DEFINE_FUNCTION( SlamTouch ),
  34. END_DATADESC()
  35. IMPLEMENT_SERVERCLASS_ST(CWeapon_SLAM, DT_Weapon_SLAM)
  36. END_SEND_TABLE()
  37. LINK_ENTITY_TO_CLASS( weapon_slam, CWeapon_SLAM );
  38. PRECACHE_WEAPON_REGISTER(weapon_slam);
  39. acttable_t CWeapon_SLAM::m_acttable[] =
  40. {
  41. { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SLAM, true },
  42. };
  43. IMPLEMENT_ACTTABLE(CWeapon_SLAM);
  44. void CWeapon_SLAM::Spawn( )
  45. {
  46. BaseClass::Spawn();
  47. Precache( );
  48. UTIL_SetSize(this, Vector(-4,-4,-2),Vector(4,4,2));
  49. FallInit();// get ready to fall down
  50. SetThink( NULL );
  51. m_tSlamState = SLAM_TRIPMINE_READY;
  52. m_flWallSwitchTime = 0;
  53. // Give 1 piece of default ammo when first picked up
  54. m_iClip2 = 1;
  55. }
  56. void CWeapon_SLAM::Precache( void )
  57. {
  58. BaseClass::Precache();
  59. UTIL_PrecacheOther( "npc_tripmine" );
  60. UTIL_PrecacheOther( "npc_satchel" );
  61. PrecacheScriptSound( "Weapon_SLAM.ThrowMode" );
  62. PrecacheScriptSound( "Weapon_SLAM.TripMineMode" );
  63. PrecacheScriptSound( "Weapon_SLAM.SatchelDetonate" );
  64. PrecacheScriptSound( "Weapon_SLAM.TripMineAttach" );
  65. PrecacheScriptSound( "Weapon_SLAM.SatchelThrow" );
  66. PrecacheScriptSound( "Weapon_SLAM.SatchelAttach" );
  67. }
  68. //------------------------------------------------------------------------------
  69. // Purpose : Override to use slam's pickup touch function
  70. // Input :
  71. // Output :
  72. //------------------------------------------------------------------------------
  73. void CWeapon_SLAM::SetPickupTouch( void )
  74. {
  75. SetTouch(SlamTouch);
  76. }
  77. //-----------------------------------------------------------------------------
  78. // Purpose: Override so give correct ammo
  79. // Input : pOther - the entity that touched me
  80. // Output :
  81. //-----------------------------------------------------------------------------
  82. void CWeapon_SLAM::SlamTouch( CBaseEntity *pOther )
  83. {
  84. CBaseCombatCharacter* pBCC = ToBaseCombatCharacter( pOther );
  85. // Can I even pick stuff up?
  86. if ( pBCC && !pBCC->IsAllowedToPickupWeapons() )
  87. return;
  88. // ---------------------------------------------------
  89. // First give weapon to touching entity if allowed
  90. // ---------------------------------------------------
  91. BaseClass::DefaultTouch(pOther);
  92. // ----------------------------------------------------
  93. // Give slam ammo if touching client
  94. // ----------------------------------------------------
  95. if (pOther->GetFlags() & FL_CLIENT)
  96. {
  97. // ------------------------------------------------
  98. // If already owned weapon of this type remove me
  99. // ------------------------------------------------
  100. CWeapon_SLAM* oldWeapon = (CWeapon_SLAM*)pBCC->Weapon_OwnsThisType( GetClassname() );
  101. if (oldWeapon != this)
  102. {
  103. UTIL_Remove( this );
  104. }
  105. else
  106. {
  107. pBCC->GiveAmmo( 1, m_iSecondaryAmmoType );
  108. SetThink(NULL);
  109. }
  110. }
  111. }
  112. //------------------------------------------------------------------------------
  113. // Purpose :
  114. // Input :
  115. // Output :
  116. //------------------------------------------------------------------------------
  117. bool CWeapon_SLAM::Holster( CBaseCombatWeapon *pSwitchingTo )
  118. {
  119. SetThink(NULL);
  120. return BaseClass::Holster(pSwitchingTo);
  121. }
  122. //-----------------------------------------------------------------------------
  123. // Purpose: SLAM has no reload, but must call weapon idle to update state
  124. // Input :
  125. // Output :
  126. //-----------------------------------------------------------------------------
  127. bool CWeapon_SLAM::Reload( void )
  128. {
  129. WeaponIdle( );
  130. return true;
  131. }
  132. //-----------------------------------------------------------------------------
  133. // Purpose:
  134. // Input :
  135. // Output :
  136. //-----------------------------------------------------------------------------
  137. void CWeapon_SLAM::PrimaryAttack( void )
  138. {
  139. CBaseCombatCharacter *pOwner = GetOwner();
  140. if (!pOwner)
  141. {
  142. return;
  143. }
  144. if (pOwner->GetAmmoCount(m_iSecondaryAmmoType) <= 0)
  145. {
  146. return;
  147. }
  148. switch (m_tSlamState)
  149. {
  150. case SLAM_TRIPMINE_READY:
  151. if (CanAttachSLAM())
  152. {
  153. StartTripmineAttach();
  154. }
  155. break;
  156. case SLAM_SATCHEL_THROW:
  157. StartSatchelThrow();
  158. break;
  159. case SLAM_SATCHEL_ATTACH:
  160. StartSatchelAttach();
  161. break;
  162. }
  163. }
  164. //-----------------------------------------------------------------------------
  165. // Purpose: Secondary attack switches between satchel charge and tripmine mode
  166. // Input :
  167. // Output :
  168. //-----------------------------------------------------------------------------
  169. void CWeapon_SLAM::SecondaryAttack( void )
  170. {
  171. return; // Nothin for now. SLAM's just a tripmine.
  172. CBaseCombatCharacter *pOwner = GetOwner();
  173. if (!pOwner)
  174. {
  175. return;
  176. }
  177. if (m_bDetonatorArmed)
  178. {
  179. StartSatchelDetonate();
  180. }
  181. else if (pOwner->GetAmmoCount(m_iSecondaryAmmoType) > 0)
  182. {
  183. if (m_tSlamState == SLAM_TRIPMINE_READY)
  184. {
  185. // Play sound for going to throw mode
  186. EmitSound( "Weapon_SLAM.ThrowMode" );
  187. if (CanAttachSLAM())
  188. {
  189. SetSlamState(SLAM_SATCHEL_ATTACH);
  190. SendWeaponAnim( ACT_SLAM_TRIPMINE_TO_STICKWALL_ND );
  191. }
  192. else
  193. {
  194. SetSlamState(SLAM_SATCHEL_THROW);
  195. SendWeaponAnim( ACT_SLAM_TRIPMINE_TO_THROW_ND );
  196. }
  197. }
  198. else
  199. {
  200. // Play sound for going to tripmine mode
  201. EmitSound( "Weapon_SLAM.TripMineMode" );
  202. if (m_tSlamState == SLAM_SATCHEL_ATTACH)
  203. {
  204. SetSlamState(SLAM_TRIPMINE_READY);
  205. SendWeaponAnim( ACT_SLAM_STICKWALL_TO_TRIPMINE_ND );
  206. }
  207. else
  208. {
  209. SetSlamState(SLAM_TRIPMINE_READY);
  210. SendWeaponAnim( ACT_SLAM_THROW_TO_TRIPMINE_ND );
  211. }
  212. }
  213. m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
  214. }
  215. }
  216. //-----------------------------------------------------------------------------
  217. // Purpose:
  218. // Input :
  219. // Output :
  220. //-----------------------------------------------------------------------------
  221. void CWeapon_SLAM::SatchelDetonate()
  222. {
  223. CBaseEntity *pEntity = NULL;
  224. while ((pEntity = gEntList.FindEntityByClassname( pEntity, "npc_satchel" )) != NULL)
  225. {
  226. CSatchelCharge *pSatchel = dynamic_cast<CSatchelCharge *>(pEntity);
  227. if (pSatchel->m_bIsLive && pSatchel->GetThrower() && GetOwner() && pSatchel->GetThrower() == GetOwner())
  228. {
  229. pSatchel->Use( GetOwner(), GetOwner(), USE_ON, 0 );
  230. }
  231. }
  232. // Play sound for pressing the detonator
  233. EmitSound( "Weapon_SLAM.SatchelDetonate" );
  234. m_bDetonatorArmed = false;
  235. }
  236. //-----------------------------------------------------------------------------
  237. // Purpose: Returns true if there are any undetonated charges in the world
  238. // that belong to this player
  239. // Input :
  240. // Output :
  241. //-----------------------------------------------------------------------------
  242. bool CWeapon_SLAM::AnyUndetonatedCharges(void)
  243. {
  244. CBaseEntity *pEntity = NULL;
  245. while ((pEntity = gEntList.FindEntityByClassname( pEntity, "npc_satchel" )) != NULL)
  246. {
  247. CSatchelCharge* pSatchel = dynamic_cast<CSatchelCharge *>(pEntity);
  248. if (pSatchel->m_bIsLive && pSatchel->GetThrower() && pSatchel->GetThrower() == GetOwner())
  249. {
  250. return true;
  251. }
  252. }
  253. return false;
  254. }
  255. //-----------------------------------------------------------------------------
  256. // Purpose:
  257. // Input :
  258. // Output :
  259. //-----------------------------------------------------------------------------
  260. void CWeapon_SLAM::StartSatchelDetonate()
  261. {
  262. // -----------------------------------------
  263. // Play detonate animation
  264. // -----------------------------------------
  265. if (m_bNeedReload)
  266. {
  267. SendWeaponAnim(ACT_SLAM_DETONATOR_DETONATE);
  268. }
  269. else if (m_tSlamState == SLAM_SATCHEL_ATTACH)
  270. {
  271. SendWeaponAnim(ACT_SLAM_STICKWALL_DETONATE);
  272. }
  273. else if (m_tSlamState == SLAM_SATCHEL_THROW)
  274. {
  275. SendWeaponAnim(ACT_SLAM_THROW_DETONATE);
  276. }
  277. else
  278. {
  279. return;
  280. }
  281. SatchelDetonate();
  282. m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  283. m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
  284. }
  285. //-----------------------------------------------------------------------------
  286. // Purpose:
  287. // Input :
  288. // Output :
  289. //-----------------------------------------------------------------------------
  290. void CWeapon_SLAM::TripmineAttach( void )
  291. {
  292. CBaseCombatCharacter *pOwner = GetOwner();
  293. if (!pOwner)
  294. {
  295. return;
  296. }
  297. m_bAttachTripmine = false;
  298. Vector vecSrc = pOwner->Weapon_ShootPosition();
  299. Vector vecAiming = pOwner->EyeDirection3D();
  300. trace_t tr;
  301. UTIL_TraceLine( vecSrc, vecSrc + (vecAiming * 128), MASK_SOLID, pOwner, COLLISION_GROUP_NONE, &tr );
  302. if (tr.fraction < 1.0)
  303. {
  304. CBaseEntity *pEntity = tr.m_pEnt;
  305. if (pEntity && !(pEntity->GetFlags() & FL_CONVEYOR))
  306. {
  307. QAngle angles;
  308. VectorAngles(tr.plane.normal, angles);
  309. angles.x += 90;
  310. CBaseEntity *pEnt = CBaseEntity::Create( "npc_tripmine", tr.endpos + tr.plane.normal * 3, angles, NULL );
  311. CTripmineGrenade *pMine = (CTripmineGrenade *)pEnt;
  312. pMine->m_hOwner = GetOwner();
  313. pOwner->RemoveAmmo( 1, m_iSecondaryAmmoType );
  314. EmitSound( "Weapon_SLAM.TripMineAttach" );
  315. }
  316. }
  317. }
  318. //-----------------------------------------------------------------------------
  319. // Purpose:
  320. // Input :
  321. // Output :
  322. //-----------------------------------------------------------------------------
  323. void CWeapon_SLAM::StartTripmineAttach( void )
  324. {
  325. // Only the player fires this way so we can cast
  326. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  327. if (!pPlayer)
  328. {
  329. return;
  330. }
  331. Vector vecSrc = pPlayer->Weapon_ShootPosition();
  332. Vector vecAiming = pPlayer->BodyDirection3D( );
  333. trace_t tr;
  334. UTIL_TraceLine( vecSrc, vecSrc + (vecAiming * 128), MASK_SOLID, pPlayer, COLLISION_GROUP_NONE, &tr );
  335. if (tr.fraction < 1.0)
  336. {
  337. // ALERT( at_console, "hit %f\n", tr.flFraction );
  338. CBaseEntity *pEntity = tr.m_pEnt;
  339. if (pEntity && !(pEntity->GetFlags() & FL_CONVEYOR))
  340. {
  341. // player "shoot" animation
  342. pPlayer->SetAnimation( PLAYER_ATTACK1 );
  343. // -----------------------------------------
  344. // Play attach animation
  345. // -----------------------------------------
  346. SendWeaponAnim(ACT_SLAM_TRIPMINE_ATTACH);
  347. m_bNeedReload = true;
  348. m_bAttachTripmine = true;
  349. }
  350. else
  351. {
  352. // ALERT( at_console, "no deploy\n" );
  353. }
  354. }
  355. m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  356. m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
  357. // SetWeaponIdleTime( gpGlobals->curtime + SequenceDuration() );
  358. }
  359. //-----------------------------------------------------------------------------
  360. // Purpose:
  361. // Input :
  362. // Output :
  363. //-----------------------------------------------------------------------------
  364. void CWeapon_SLAM::SatchelThrow( void )
  365. {
  366. m_bThrowSatchel = false;
  367. // Only the player fires this way so we can cast
  368. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  369. Vector vecSrc = pPlayer->WorldSpaceCenter();
  370. Vector vecFacing = pPlayer->BodyDirection3D( );
  371. vecSrc = vecSrc + vecFacing * 18.0;
  372. // BUGBUG: is this because vecSrc is not from Weapon_ShootPosition()???
  373. vecSrc.z += 24.0f;
  374. Vector vecThrow;
  375. GetOwner()->GetVelocity( &vecThrow, NULL );
  376. vecThrow += vecFacing * 500;
  377. // Player may have turned to face a wall during the throw anim in which case
  378. // we don't want to throw the SLAM into the wall
  379. if (CanAttachSLAM())
  380. {
  381. vecThrow = vecFacing;
  382. vecSrc = pPlayer->WorldSpaceCenter() + vecFacing * 5.0;
  383. }
  384. CSatchelCharge *pSatchel = (CSatchelCharge*)Create( "npc_satchel", vecSrc, vec3_angle, GetOwner() );
  385. pSatchel->SetThrower( GetOwner() );
  386. pSatchel->ApplyAbsVelocityImpulse( vecThrow );
  387. pSatchel->SetLocalAngularVelocity( QAngle( 0, 400, 0 ) );
  388. pSatchel->m_bIsLive = true;
  389. pSatchel->m_pMyWeaponSLAM = this;
  390. pPlayer->RemoveAmmo( 1, m_iSecondaryAmmoType );
  391. // Play throw sound
  392. EmitSound( "Weapon_SLAM.SatchelThrow" );
  393. }
  394. //-----------------------------------------------------------------------------
  395. // Purpose:
  396. // Input :
  397. // Output :
  398. //-----------------------------------------------------------------------------
  399. void CWeapon_SLAM::StartSatchelThrow( void )
  400. {
  401. // -----------------------------------------
  402. // Play throw animation
  403. // -----------------------------------------
  404. if (m_bDetonatorArmed)
  405. {
  406. SendWeaponAnim(ACT_SLAM_THROW_THROW);
  407. }
  408. else
  409. {
  410. SendWeaponAnim(ACT_SLAM_THROW_THROW_ND);
  411. if (!m_bDetonatorArmed)
  412. {
  413. m_bDetonatorArmed = true;
  414. m_bNeedDetonatorDraw = true;
  415. }
  416. }
  417. m_bNeedReload = true;
  418. m_bThrowSatchel = true;
  419. m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  420. m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
  421. }
  422. //-----------------------------------------------------------------------------
  423. // Purpose:
  424. // Input :
  425. // Output :
  426. //-----------------------------------------------------------------------------
  427. void CWeapon_SLAM::SatchelAttach( void )
  428. {
  429. CBaseCombatCharacter *pOwner = GetOwner();
  430. if (!pOwner)
  431. {
  432. return;
  433. }
  434. m_bAttachSatchel = false;
  435. Vector vecSrc = pOwner->Weapon_ShootPosition( );
  436. Vector vecAiming = pOwner->BodyDirection2D( );
  437. trace_t tr;
  438. UTIL_TraceLine( vecSrc, vecSrc + (vecAiming * 128), MASK_SOLID, pOwner, COLLISION_GROUP_NONE, &tr );
  439. if (tr.fraction < 1.0)
  440. {
  441. CBaseEntity *pEntity = tr.m_pEnt;
  442. if (pEntity && !(pEntity->GetFlags() & FL_CONVEYOR))
  443. {
  444. QAngle angles;
  445. VectorAngles(tr.plane.normal, angles);
  446. angles.y -= 90;
  447. angles.z -= 90;
  448. tr.endpos.z -= 6.0f;
  449. EmitSound( "Weapon_SLAM.SatchelAttach" );
  450. CSatchelCharge *pSatchel = (CSatchelCharge*)CBaseEntity::Create( "npc_satchel", tr.endpos + tr.plane.normal * 3, angles, NULL );
  451. pSatchel->SetMoveType( MOVETYPE_FLY ); // no gravity
  452. pSatchel->m_bIsAttached = true;
  453. pSatchel->m_bIsLive = true;
  454. pSatchel->SetThrower( GetOwner() );
  455. pSatchel->SetOwnerEntity( ((CBaseEntity*)GetOwner()) );
  456. pSatchel->m_pMyWeaponSLAM = this;
  457. pOwner->RemoveAmmo( 1, m_iSecondaryAmmoType );
  458. }
  459. }
  460. }
  461. //-----------------------------------------------------------------------------
  462. // Purpose:
  463. // Input :
  464. // Output :
  465. //-----------------------------------------------------------------------------
  466. void CWeapon_SLAM::StartSatchelAttach( void )
  467. {
  468. CBaseCombatCharacter *pOwner = GetOwner();
  469. if (!pOwner)
  470. {
  471. return;
  472. }
  473. Vector vecSrc = pOwner->Weapon_ShootPosition( );
  474. Vector vecAiming = pOwner->BodyDirection2D( );
  475. trace_t tr;
  476. UTIL_TraceLine( vecSrc, vecSrc + (vecAiming * 128), MASK_SOLID, pOwner, COLLISION_GROUP_NONE, &tr );
  477. if (tr.fraction < 1.0)
  478. {
  479. CBaseEntity *pEntity = tr.m_pEnt;
  480. if (pEntity && !(pEntity->GetFlags() & FL_CONVEYOR))
  481. {
  482. // Only the player fires this way so we can cast
  483. CBasePlayer *pPlayer = ToBasePlayer( pOwner );
  484. // player "shoot" animation
  485. pPlayer->SetAnimation( PLAYER_ATTACK1 );
  486. // -----------------------------------------
  487. // Play attach animation
  488. // -----------------------------------------
  489. if (m_bDetonatorArmed)
  490. {
  491. SendWeaponAnim(ACT_SLAM_STICKWALL_ATTACH);
  492. }
  493. else
  494. {
  495. SendWeaponAnim(ACT_SLAM_STICKWALL_ND_ATTACH);
  496. if (!m_bDetonatorArmed)
  497. {
  498. m_bDetonatorArmed = true;
  499. m_bNeedDetonatorDraw = true;
  500. }
  501. }
  502. m_bNeedReload = true;
  503. m_bAttachSatchel = true;
  504. m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  505. }
  506. }
  507. }
  508. //-----------------------------------------------------------------------------
  509. // Purpose:
  510. // Input :
  511. // Output :
  512. //-----------------------------------------------------------------------------
  513. void CWeapon_SLAM::SetSlamState( SlamState_t newState )
  514. {
  515. // Set set and set idle time so animation gets updated with state change
  516. m_tSlamState = newState;
  517. SetWeaponIdleTime( gpGlobals->curtime );
  518. }
  519. //-----------------------------------------------------------------------------
  520. // Purpose:
  521. // Input :
  522. // Output :
  523. //-----------------------------------------------------------------------------
  524. void CWeapon_SLAM::SLAMThink( void )
  525. {
  526. if (m_flWallSwitchTime <= gpGlobals->curtime)
  527. {
  528. // If not in tripmine mode we need to check to see if we are close to
  529. // a wall. If we are we go into satchel_attach mode
  530. CBaseCombatCharacter *pOwner = GetOwner();
  531. if ((m_tSlamState != SLAM_TRIPMINE_READY) && (pOwner && pOwner->GetAmmoCount(m_iSecondaryAmmoType) > 0))
  532. {
  533. if (CanAttachSLAM())
  534. {
  535. if (m_tSlamState == SLAM_SATCHEL_THROW)
  536. {
  537. SetSlamState(SLAM_SATCHEL_ATTACH);
  538. int iAnim = m_bDetonatorArmed ? ACT_SLAM_THROW_TO_STICKWALL : ACT_SLAM_THROW_TO_STICKWALL_ND;
  539. SendWeaponAnim( iAnim );
  540. m_flWallSwitchTime = gpGlobals->curtime + SequenceDuration();
  541. }
  542. }
  543. else
  544. {
  545. if (m_tSlamState == SLAM_SATCHEL_ATTACH)
  546. {
  547. SetSlamState(SLAM_SATCHEL_THROW);
  548. int iAnim = m_bDetonatorArmed ? ACT_SLAM_STICKWALL_TO_THROW : ACT_SLAM_STICKWALL_TO_THROW_ND;
  549. SendWeaponAnim( iAnim );
  550. m_flWallSwitchTime = gpGlobals->curtime + SequenceDuration();
  551. }
  552. }
  553. }
  554. }
  555. SetNextThink( gpGlobals->curtime + 0.1f );
  556. }
  557. //-----------------------------------------------------------------------------
  558. // Purpose:
  559. // Input :
  560. // Output :
  561. //-----------------------------------------------------------------------------
  562. bool CWeapon_SLAM::CanAttachSLAM( void )
  563. {
  564. CBaseCombatCharacter *pOwner = GetOwner();
  565. if (!pOwner)
  566. {
  567. return false;
  568. }
  569. Vector vecSrc = pOwner->Weapon_ShootPosition( );
  570. Vector vecAiming = pOwner->BodyDirection2D( );
  571. trace_t tr;
  572. Vector vecEnd = vecSrc + (vecAiming * 42);
  573. UTIL_TraceLine( vecSrc, vecEnd, MASK_SOLID, pOwner, COLLISION_GROUP_NONE, &tr );
  574. if (tr.fraction < 1.0)
  575. {
  576. // Don't attach to a living creature
  577. if (tr.m_pEnt)
  578. {
  579. CBaseEntity *pEntity = tr.m_pEnt;
  580. CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( pEntity );
  581. if (pBCC)
  582. {
  583. return false;
  584. }
  585. }
  586. return true;
  587. }
  588. else
  589. {
  590. return false;
  591. }
  592. }
  593. //-----------------------------------------------------------------------------
  594. // Purpose: Override so SLAM to so secondary attack when no secondary ammo
  595. // but satchel is in the world
  596. // Input :
  597. // Output :
  598. //-----------------------------------------------------------------------------
  599. void CWeapon_SLAM::ItemPostFrame( void )
  600. {
  601. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  602. if (!pOwner)
  603. {
  604. return;
  605. }
  606. if ((pOwner->m_nButtons & IN_ATTACK2) && (m_flNextSecondaryAttack <= gpGlobals->curtime))
  607. {
  608. SecondaryAttack();
  609. }
  610. else if (!m_bNeedReload && (pOwner->m_nButtons & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime))
  611. {
  612. PrimaryAttack();
  613. }
  614. // -----------------------
  615. // No buttons down
  616. // -----------------------
  617. else
  618. {
  619. WeaponIdle( );
  620. return;
  621. }
  622. }
  623. //-----------------------------------------------------------------------------
  624. // Purpose: Switch to next best weapon
  625. // Input :
  626. // Output :
  627. //-----------------------------------------------------------------------------
  628. void CWeapon_SLAM::WeaponSwitch( void )
  629. {
  630. // Note that we may pick the SLAM again, when we switch
  631. // weapons, in which case we have to save and restore the
  632. // detonator armed state.
  633. // The SLAMs may be about to blow up, but haven't done so yet
  634. // and the deploy function will find the undetonated charges
  635. // and we are armed
  636. bool saveState = m_bDetonatorArmed;
  637. CBaseCombatCharacter *pOwner = GetOwner();
  638. pOwner->SwitchToNextBestWeapon( pOwner->GetActiveWeapon() );
  639. if (pOwner->GetActiveWeapon() == this)
  640. {
  641. m_bDetonatorArmed = saveState;
  642. }
  643. // If not armed and have no ammo
  644. if (!m_bDetonatorArmed && pOwner->GetAmmoCount(m_iSecondaryAmmoType) <= 0)
  645. {
  646. pOwner->ClearActiveWeapon();
  647. }
  648. }
  649. //-----------------------------------------------------------------------------
  650. // Purpose:
  651. // Input :
  652. // Output :
  653. //-----------------------------------------------------------------------------
  654. void CWeapon_SLAM::WeaponIdle( void )
  655. {
  656. // Ready to switch animations?
  657. if ( HasWeaponIdleTimeElapsed() )
  658. {
  659. // Don't allow throw to attach switch unless in idle
  660. m_flWallSwitchTime = gpGlobals->curtime + 50;
  661. if (m_bClearReload)
  662. {
  663. m_bNeedReload = false;
  664. m_bClearReload = false;
  665. }
  666. CBaseCombatCharacter *pOwner = GetOwner();
  667. if (!pOwner)
  668. {
  669. return;
  670. }
  671. int iAnim = 0;
  672. if (m_bThrowSatchel)
  673. {
  674. SatchelThrow();
  675. if (m_bDetonatorArmed && !m_bNeedDetonatorDraw)
  676. {
  677. iAnim = ACT_SLAM_THROW_THROW2;
  678. }
  679. else
  680. {
  681. iAnim = ACT_SLAM_THROW_THROW_ND2;
  682. }
  683. }
  684. else if (m_bAttachSatchel)
  685. {
  686. SatchelAttach();
  687. if (m_bDetonatorArmed && !m_bNeedDetonatorDraw)
  688. {
  689. iAnim = ACT_SLAM_STICKWALL_ATTACH2;
  690. }
  691. else
  692. {
  693. iAnim = ACT_SLAM_STICKWALL_ND_ATTACH2;
  694. }
  695. }
  696. else if (m_bAttachTripmine)
  697. {
  698. TripmineAttach();
  699. iAnim = ACT_SLAM_TRIPMINE_ATTACH2;
  700. }
  701. else if (m_bNeedReload)
  702. {
  703. // If owner had ammo draw the correct SLAM type
  704. if (pOwner->GetAmmoCount(m_iSecondaryAmmoType) > 0)
  705. {
  706. switch( m_tSlamState)
  707. {
  708. case SLAM_TRIPMINE_READY:
  709. {
  710. iAnim = ACT_SLAM_TRIPMINE_DRAW;
  711. }
  712. break;
  713. case SLAM_SATCHEL_ATTACH:
  714. {
  715. if (m_bNeedDetonatorHolster)
  716. {
  717. iAnim = ACT_SLAM_STICKWALL_DETONATOR_HOLSTER;
  718. m_bNeedDetonatorHolster = false;
  719. }
  720. else if (m_bDetonatorArmed)
  721. {
  722. iAnim = m_bNeedDetonatorDraw ? ACT_SLAM_DETONATOR_STICKWALL_DRAW : ACT_SLAM_STICKWALL_DRAW;
  723. m_bNeedDetonatorDraw = false;
  724. }
  725. else
  726. {
  727. iAnim = ACT_SLAM_STICKWALL_ND_DRAW;
  728. }
  729. }
  730. break;
  731. case SLAM_SATCHEL_THROW:
  732. {
  733. if (m_bNeedDetonatorHolster)
  734. {
  735. iAnim = ACT_SLAM_THROW_DETONATOR_HOLSTER;
  736. m_bNeedDetonatorHolster = false;
  737. }
  738. else if (m_bDetonatorArmed)
  739. {
  740. iAnim = m_bNeedDetonatorDraw ? ACT_SLAM_DETONATOR_THROW_DRAW : ACT_SLAM_THROW_DRAW;
  741. m_bNeedDetonatorDraw = false;
  742. }
  743. else
  744. {
  745. iAnim = ACT_SLAM_THROW_ND_DRAW;
  746. }
  747. }
  748. break;
  749. }
  750. m_bClearReload = true;
  751. }
  752. // If no ammo and armed, idle with only the detonator
  753. else if (m_bDetonatorArmed)
  754. {
  755. iAnim = m_bNeedDetonatorDraw ? ACT_SLAM_DETONATOR_DRAW : ACT_SLAM_DETONATOR_IDLE;
  756. m_bNeedDetonatorDraw = false;
  757. }
  758. else
  759. {
  760. pOwner->Weapon_Drop( this );
  761. UTIL_Remove(this);
  762. }
  763. }
  764. else if (pOwner->GetAmmoCount(m_iSecondaryAmmoType) <= 0)
  765. {
  766. pOwner->Weapon_Drop( this );
  767. UTIL_Remove(this);
  768. }
  769. // If I don't need to reload just do the appropriate idle
  770. else
  771. {
  772. switch( m_tSlamState)
  773. {
  774. case SLAM_TRIPMINE_READY:
  775. {
  776. iAnim = ACT_SLAM_TRIPMINE_IDLE;
  777. }
  778. break;
  779. case SLAM_SATCHEL_THROW:
  780. {
  781. if (m_bNeedDetonatorHolster)
  782. {
  783. iAnim = ACT_SLAM_THROW_DETONATOR_HOLSTER;
  784. m_bNeedDetonatorHolster = false;
  785. }
  786. else
  787. {
  788. iAnim = m_bDetonatorArmed ? ACT_SLAM_THROW_IDLE : ACT_SLAM_THROW_ND_IDLE;
  789. m_flWallSwitchTime = 0;
  790. }
  791. }
  792. break;
  793. case SLAM_SATCHEL_ATTACH:
  794. {
  795. if (m_bNeedDetonatorHolster)
  796. {
  797. iAnim = ACT_SLAM_STICKWALL_DETONATOR_HOLSTER;
  798. m_bNeedDetonatorHolster = false;
  799. }
  800. else
  801. {
  802. iAnim = m_bDetonatorArmed ? ACT_SLAM_STICKWALL_IDLE : ACT_SLAM_STICKWALL_ND_IDLE;
  803. m_flWallSwitchTime = 0;
  804. }
  805. }
  806. break;
  807. }
  808. }
  809. SendWeaponAnim( iAnim );
  810. }
  811. }
  812. bool CWeapon_SLAM::Deploy( void )
  813. {
  814. CBaseCombatCharacter *pOwner = GetOwner();
  815. if (!pOwner)
  816. {
  817. return false;
  818. }
  819. m_bDetonatorArmed = AnyUndetonatedCharges();
  820. SetThink( SLAMThink );
  821. SetNextThink( gpGlobals->curtime + 0.1f );
  822. SetModel( GetViewModel() );
  823. // ------------------------------
  824. // Pick the right draw animation
  825. // ------------------------------
  826. int iActivity;
  827. // If detonator is already armed
  828. m_bNeedReload = false;
  829. if (m_bDetonatorArmed)
  830. {
  831. if (pOwner->GetAmmoCount(m_iSecondaryAmmoType) <= 0)
  832. {
  833. iActivity = ACT_SLAM_DETONATOR_DRAW;
  834. m_bNeedReload = true;
  835. }
  836. else if (CanAttachSLAM())
  837. {
  838. iActivity = ACT_SLAM_DETONATOR_STICKWALL_DRAW;
  839. }
  840. else
  841. {
  842. iActivity = ACT_SLAM_DETONATOR_THROW_DRAW;
  843. }
  844. }
  845. else
  846. {
  847. if (CanAttachSLAM())
  848. {
  849. iActivity = ACT_SLAM_STICKWALL_ND_DRAW;
  850. }
  851. else
  852. {
  853. iActivity = ACT_SLAM_THROW_ND_DRAW;
  854. }
  855. }
  856. return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), iActivity, (char*)GetAnimPrefix() );
  857. }
  858. //-----------------------------------------------------------------------------
  859. // Purpose: Constructor
  860. // Input :
  861. // Output :
  862. //-----------------------------------------------------------------------------
  863. CWeapon_SLAM::CWeapon_SLAM(void)
  864. {
  865. m_tSlamState = SLAM_SATCHEL_THROW;
  866. m_bDetonatorArmed = false;
  867. m_bNeedReload = true;
  868. m_bClearReload = false;
  869. m_bThrowSatchel = false;
  870. m_bAttachSatchel = false;
  871. m_bAttachTripmine = false;
  872. m_bNeedDetonatorDraw = false;
  873. m_bNeedDetonatorHolster = false;
  874. }