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.

460 lines
14 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Client's CWeaponBuilder class
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. // $NoKeywords: $
  8. //=============================================================================//
  9. #include "cbase.h"
  10. #include "hud.h"
  11. #include "in_buttons.h"
  12. #include "clientmode_tf.h"
  13. #include "engine/IEngineSound.h"
  14. #include "c_tf_weapon_builder.h"
  15. #include "c_weapon__stubs.h"
  16. #include "iinput.h"
  17. #include <vgui/IVGui.h>
  18. #include "c_tf_player.h"
  19. #include "c_vguiscreen.h"
  20. #include "ienginevgui.h"
  21. STUB_WEAPON_CLASS_IMPLEMENT( tf_weapon_builder, C_TFWeaponBuilder );
  22. PRECACHE_WEAPON_REGISTER( tf_weapon_builder );
  23. // SUPER HACK TO FIX DEMOS. For a couple days, we accidently renamed
  24. // CTFWeaponBuilder to C_TFWeaponBuilder on the server. This was fine for
  25. // playing the game but broke all previously recorded demos. Fixing this and
  26. // re-renaming the class back to the original name fixed all demos recorded
  27. // with the brokenly-renamed class. To handle these demos that think the class
  28. // is called C_TFWeaponBuilder on the server, we're creating a new class that derives from
  29. // the real C_TFWeaponBuilder and does nothing special except that it calls
  30. // IMPLEMENT_CLIENTCLASS and maps itself to serverclass "C_TFWeaponBuilder"
  31. // (which, if you've followed along, doesn't exist anymore).
  32. //
  33. // As a history lesson, this broke from the change in tf_player_shared.h in cl 1722245
  34. class C_TFWeaponBuilderReplayHack : public C_TFWeaponBuilder
  35. {
  36. DECLARE_CLASS( C_TFWeaponBuilderReplayHack, C_TFWeaponBuilder );
  37. public:
  38. DECLARE_CLIENTCLASS();
  39. DECLARE_PREDICTABLE();
  40. };
  41. IMPLEMENT_CLIENTCLASS( C_TFWeaponBuilderReplayHack, DT_TFWeaponBuilder, C_TFWeaponBuilder )
  42. BEGIN_PREDICTION_DATA( C_TFWeaponBuilderReplayHack )
  43. END_PREDICTION_DATA()
  44. IMPLEMENT_NETWORKCLASS_ALIASED( TFWeaponBuilder, DT_TFWeaponBuilder )
  45. // Recalc object sprite when we receive a new object type to build
  46. void RecvProxy_ObjectType( const CRecvProxyData *pData, void *pStruct, void *pOut )
  47. {
  48. // Pass to normal Int recvproxy
  49. RecvProxy_Int32ToInt32( pData, pStruct, pOut );
  50. // Reset the object sprite
  51. C_TFWeaponBuilder *pBuilder = ( C_TFWeaponBuilder * )pStruct;
  52. pBuilder->SetupObjectSelectionSprite();
  53. }
  54. BEGIN_NETWORK_TABLE_NOBASE( C_TFWeaponBuilder, DT_BuilderLocalData )
  55. RecvPropInt( RECVINFO(m_iObjectType), 0, RecvProxy_ObjectType ),
  56. RecvPropEHandle( RECVINFO(m_hObjectBeingBuilt) ),
  57. RecvPropArray3( RECVINFO_ARRAY( m_aBuildableObjectTypes ), RecvPropBool( RECVINFO( m_aBuildableObjectTypes[0] ) ) ),
  58. END_NETWORK_TABLE()
  59. BEGIN_NETWORK_TABLE( C_TFWeaponBuilder, DT_TFWeaponBuilder )
  60. RecvPropInt( RECVINFO(m_iBuildState) ),
  61. RecvPropDataTable( "BuilderLocalData", 0, 0, &REFERENCE_RECV_TABLE( DT_BuilderLocalData ) ),
  62. RecvPropInt( RECVINFO(m_iObjectMode) ),
  63. RecvPropFloat( RECVINFO( m_flWheatleyTalkingUntil) ),
  64. END_RECV_TABLE()
  65. //-----------------------------------------------------------------------------
  66. IMPLEMENT_NETWORKCLASS_ALIASED( TFWeaponSapper, DT_TFWeaponSapper )
  67. BEGIN_NETWORK_TABLE( C_TFWeaponSapper, DT_TFWeaponSapper )
  68. RecvPropFloat( RECVINFO( m_flChargeBeginTime ) ),
  69. END_NETWORK_TABLE()
  70. //-----------------------------------------------------------------------------
  71. // Purpose:
  72. //-----------------------------------------------------------------------------
  73. C_TFWeaponBuilder::C_TFWeaponBuilder()
  74. {
  75. m_iBuildState = 0;
  76. m_iObjectType = BUILDER_INVALID_OBJECT;
  77. m_pSelectionTextureActive = NULL;
  78. m_pSelectionTextureInactive = NULL;
  79. m_iValidBuildPoseParam = -1;
  80. m_flWheatleyTalkingUntil = 0;
  81. }
  82. //-----------------------------------------------------------------------------
  83. // Purpose:
  84. //-----------------------------------------------------------------------------
  85. C_TFWeaponBuilder::~C_TFWeaponBuilder()
  86. {
  87. }
  88. //-----------------------------------------------------------------------------
  89. // Purpose:
  90. // Output : char const
  91. //-----------------------------------------------------------------------------
  92. const char *C_TFWeaponBuilder::GetCurrentSelectionObjectName( void )
  93. {
  94. if ( m_iObjectType == -1 || (m_iBuildState == BS_SELECTING) )
  95. return "";
  96. return GetObjectInfo( m_iObjectType )->m_pBuilderWeaponName;
  97. }
  98. //-----------------------------------------------------------------------------
  99. // Purpose:
  100. //-----------------------------------------------------------------------------
  101. bool C_TFWeaponBuilder::Deploy( void )
  102. {
  103. bool bDeploy = BaseClass::Deploy();
  104. if ( bDeploy )
  105. {
  106. m_flNextPrimaryAttack = gpGlobals->curtime + 0.35f;
  107. m_flNextSecondaryAttack = gpGlobals->curtime; // asap
  108. CTFPlayer *pPlayer = ToTFPlayer( GetOwner() );
  109. if (!pPlayer)
  110. return false;
  111. pPlayer->SetNextAttack( gpGlobals->curtime );
  112. m_iWorldModelIndex = modelinfo->GetModelIndex( GetWorldModel() );
  113. }
  114. return bDeploy;
  115. }
  116. //-----------------------------------------------------------------------------
  117. // Purpose:
  118. //-----------------------------------------------------------------------------
  119. void C_TFWeaponBuilder::SecondaryAttack( void )
  120. {
  121. if ( m_bInAttack2 )
  122. return;
  123. // require a re-press
  124. m_bInAttack2 = true;
  125. CTFPlayer *pOwner = ToTFPlayer( GetOwner() );
  126. if ( !pOwner )
  127. return;
  128. pOwner->DoClassSpecialSkill();
  129. m_flNextSecondaryAttack = gpGlobals->curtime + 0.2f;
  130. }
  131. //-----------------------------------------------------------------------------
  132. // Purpose: cache the build pos pose param
  133. //-----------------------------------------------------------------------------
  134. CStudioHdr *C_TFWeaponBuilder::OnNewModel( void )
  135. {
  136. CStudioHdr *hdr = BaseClass::OnNewModel();
  137. m_iValidBuildPoseParam = LookupPoseParameter( "valid_build_pos" );
  138. return hdr;
  139. }
  140. //-----------------------------------------------------------------------------
  141. // Purpose:
  142. // ----------------------------------------------------------------------------
  143. void C_TFWeaponBuilder::PostDataUpdate( DataUpdateType_t type )
  144. {
  145. if ( type == DATA_UPDATE_CREATED )
  146. {
  147. // m_iViewModelIndex is set by the base Precache(), which didn't know what
  148. // type of object we built, so it didn't get the right viewmodel index.
  149. // Now that our data is filled in, go and get the right index.
  150. const char *pszViewModel = GetViewModel(0);
  151. if ( pszViewModel && pszViewModel[0] )
  152. {
  153. m_iViewModelIndex = CBaseEntity::PrecacheModel( pszViewModel );
  154. }
  155. }
  156. BaseClass::PostDataUpdate( type );
  157. }
  158. //-----------------------------------------------------------------------------
  159. // Purpose: only called for local player
  160. //-----------------------------------------------------------------------------
  161. void C_TFWeaponBuilder::Redraw()
  162. {
  163. if ( m_iValidBuildPoseParam >= 0 )
  164. {
  165. CTFPlayer *pOwner = ToTFPlayer( GetOwner() );
  166. if ( !pOwner )
  167. return;
  168. // Assuming here that our model is the same as our viewmodel's model!
  169. CBaseViewModel *pViewModel = pOwner->GetViewModel(0);
  170. if ( pViewModel )
  171. {
  172. float flPoseParamValue = pViewModel->GetPoseParameter( m_iValidBuildPoseParam );
  173. C_BaseObject *pObj = m_hObjectBeingBuilt.Get();
  174. if ( pObj && pObj->WasLastPlacementPosValid() )
  175. {
  176. // pose param approach 1.0
  177. flPoseParamValue = Approach( 1.0, flPoseParamValue, 3.0 * gpGlobals->frametime );
  178. }
  179. else
  180. {
  181. // pose param approach 0.0
  182. flPoseParamValue = Approach( 0.0, flPoseParamValue, 1.5 * gpGlobals->frametime );
  183. }
  184. pViewModel->SetPoseParameter( m_iValidBuildPoseParam, flPoseParamValue );
  185. }
  186. }
  187. BaseClass::Redraw();
  188. }
  189. //-----------------------------------------------------------------------------
  190. // Purpose:
  191. // Output : Returns true on success, false on failure.
  192. //-----------------------------------------------------------------------------
  193. bool C_TFWeaponBuilder::IsPlacingObject( void )
  194. {
  195. if ( m_iBuildState == BS_PLACING || m_iBuildState == BS_PLACING_INVALID )
  196. return true;
  197. return false;
  198. }
  199. //-----------------------------------------------------------------------------
  200. // Purpose:
  201. //-----------------------------------------------------------------------------
  202. int C_TFWeaponBuilder::GetSlot( void ) const
  203. {
  204. return GetObjectInfo( m_iObjectType )->m_SelectionSlot;
  205. }
  206. //-----------------------------------------------------------------------------
  207. // Purpose:
  208. //-----------------------------------------------------------------------------
  209. int C_TFWeaponBuilder::GetPosition( void ) const
  210. {
  211. return GetObjectInfo( m_iObjectType )->m_SelectionPosition;
  212. }
  213. //-----------------------------------------------------------------------------
  214. // Purpose:
  215. //-----------------------------------------------------------------------------
  216. void C_TFWeaponBuilder::SetupObjectSelectionSprite( void )
  217. {
  218. #ifdef CLIENT_DLL
  219. // Use the sprite details from the text file, with a custom sprite
  220. char *iconTexture = GetObjectInfo( m_iObjectType )->m_pIconActive;
  221. if ( iconTexture && iconTexture[ 0 ] )
  222. {
  223. m_pSelectionTextureActive = gHUD.GetIcon( iconTexture );
  224. }
  225. else
  226. {
  227. m_pSelectionTextureActive = NULL;
  228. }
  229. iconTexture = GetObjectInfo( m_iObjectType )->m_pIconInactive;
  230. if ( iconTexture && iconTexture[ 0 ] )
  231. {
  232. m_pSelectionTextureInactive = gHUD.GetIcon( iconTexture );
  233. }
  234. else
  235. {
  236. m_pSelectionTextureInactive = NULL;
  237. }
  238. #endif
  239. }
  240. //-----------------------------------------------------------------------------
  241. // Purpose:
  242. //-----------------------------------------------------------------------------
  243. CHudTexture const *C_TFWeaponBuilder::GetSpriteActive( void ) const
  244. {
  245. return m_pSelectionTextureActive;
  246. }
  247. //-----------------------------------------------------------------------------
  248. // Purpose:
  249. //-----------------------------------------------------------------------------
  250. CHudTexture const *C_TFWeaponBuilder::GetSpriteInactive( void ) const
  251. {
  252. return m_pSelectionTextureInactive;
  253. }
  254. //-----------------------------------------------------------------------------
  255. // Purpose:
  256. // Output : char const
  257. //-----------------------------------------------------------------------------
  258. const char *C_TFWeaponBuilder::GetPrintName( void ) const
  259. {
  260. return GetObjectInfo( m_iObjectType )->m_AltModes[m_iObjectMode].pszStatusName;
  261. }
  262. //-----------------------------------------------------------------------------
  263. // Purpose:
  264. //-----------------------------------------------------------------------------
  265. int C_TFWeaponBuilder::GetSubType( void )
  266. {
  267. return m_iObjectType;
  268. }
  269. //-----------------------------------------------------------------------------
  270. // Purpose: Return true if this weapon can be selected via the weapon selection
  271. //-----------------------------------------------------------------------------
  272. bool C_TFWeaponBuilder::CanBeSelected( void )
  273. {
  274. CTFPlayer *pOwner = ToTFPlayer( GetOwner() );
  275. if ( !pOwner )
  276. return false;
  277. if ( pOwner->CanBuild( m_iObjectType, m_iObjectMode ) != CB_CAN_BUILD )
  278. return false;
  279. return HasAmmo();
  280. }
  281. //-----------------------------------------------------------------------------
  282. // Purpose: Return true if this weapon should be visible in the weapon selection
  283. //-----------------------------------------------------------------------------
  284. bool C_TFWeaponBuilder::VisibleInWeaponSelection( void )
  285. {
  286. if ( BaseClass::VisibleInWeaponSelection() == false )
  287. return false;
  288. if ( m_iObjectType != BUILDER_INVALID_OBJECT )
  289. return GetObjectInfo( m_iObjectType )->m_bVisibleInWeaponSelection;
  290. return false;
  291. }
  292. //-----------------------------------------------------------------------------
  293. // Purpose: Return true if this weapon has some ammo
  294. //-----------------------------------------------------------------------------
  295. bool C_TFWeaponBuilder::HasAmmo( void )
  296. {
  297. CTFPlayer *pOwner = ToTFPlayer( GetOwner() );
  298. if ( !pOwner )
  299. return false;
  300. int iCost = pOwner->m_Shared.CalculateObjectCost( pOwner, m_iObjectType );
  301. return ( pOwner->GetBuildResources() >= iCost );
  302. }
  303. // -----------------------------------------------------------------------------
  304. // Purpose:
  305. // -----------------------------------------------------------------------------
  306. bool C_TFWeaponBuilder::CanBuildObjectType( int iObjectType )
  307. {
  308. if ( iObjectType < 0 || iObjectType >= OBJ_LAST )
  309. return false;
  310. return m_aBuildableObjectTypes[iObjectType];
  311. }
  312. // -----------------------------------------------------------------------------
  313. // Purpose:
  314. // -----------------------------------------------------------------------------
  315. void C_TFWeaponBuilder::UpdateAttachmentModels( void )
  316. {
  317. if ( m_iObjectType != BUILDER_INVALID_OBJECT && GetObjectInfo( m_iObjectType )->m_bUseItemInfo )
  318. {
  319. BaseClass::UpdateAttachmentModels();
  320. }
  321. }
  322. // -----------------------------------------------------------------------------
  323. // Purpose:
  324. // -----------------------------------------------------------------------------
  325. const char *C_TFWeaponBuilder::GetViewModel( int iViewModel ) const
  326. {
  327. if ( GetPlayerOwner() == NULL )
  328. {
  329. return BaseClass::GetViewModel();
  330. }
  331. if ( m_iObjectType != BUILDER_INVALID_OBJECT )
  332. {
  333. if ( GetObjectInfo( m_iObjectType )->m_bUseItemInfo )
  334. return BaseClass::GetViewModel();
  335. return GetObjectInfo( m_iObjectType )->m_pViewModel;
  336. }
  337. return BaseClass::GetViewModel();
  338. }
  339. //-----------------------------------------------------------------------------
  340. // Purpose:
  341. //-----------------------------------------------------------------------------
  342. const char *C_TFWeaponBuilder::GetWorldModel( void ) const
  343. {
  344. if ( GetPlayerOwner() == NULL )
  345. {
  346. return BaseClass::GetWorldModel();
  347. }
  348. if ( m_iObjectType != BUILDER_INVALID_OBJECT )
  349. {
  350. return GetObjectInfo( m_iObjectType )->m_pPlayerModel;
  351. }
  352. return BaseClass::GetWorldModel();
  353. }
  354. Activity C_TFWeaponBuilder::GetDrawActivity( void )
  355. {
  356. // sapper used to call different draw animations , one when invis and one when not.
  357. // now you can go invis *while* deploying, so let's always use the one-handed deploy.
  358. if ( GetType() == OBJ_ATTACHMENT_SAPPER )
  359. {
  360. return ACT_VM_DRAW_DEPLOYED;
  361. }
  362. return BaseClass::GetDrawActivity();
  363. }
  364. //-----------------------------------------------------------------------------
  365. // Purpose:
  366. //-----------------------------------------------------------------------------
  367. bool C_TFWeaponBuilder::EffectMeterShouldFlash( void )
  368. {
  369. if ( !GetOwner() )
  370. return false;
  371. int iRoboSapper = 0;
  372. CALL_ATTRIB_HOOK_INT_ON_OTHER( GetOwner(), iRoboSapper, robo_sapper );
  373. return ( iRoboSapper && GetEffectBarProgress() >= 1.f );
  374. }
  375. const char *C_TFWeaponSapper::GetViewModel( int iViewModel ) const
  376. {
  377. // Skip over Builder's version
  378. return C_TFWeaponBase::GetViewModel();
  379. }
  380. //-----------------------------------------------------------------------------
  381. // Purpose:
  382. //-----------------------------------------------------------------------------
  383. const char *C_TFWeaponSapper::GetWorldModel( void ) const
  384. {
  385. // Skip over Builder's version
  386. return C_TFWeaponBase::GetWorldModel();
  387. }