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.

1052 lines
26 KiB

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