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.

442 lines
10 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "in_buttons.h"
  9. #include "takedamageinfo.h"
  10. #include "ammodef.h"
  11. #include "portal_gamerules.h"
  12. #ifdef CLIENT_DLL
  13. extern IVModelInfoClient* modelinfo;
  14. #else
  15. extern IVModelInfo* modelinfo;
  16. #endif
  17. #if defined( CLIENT_DLL )
  18. #include "vgui/ISurface.h"
  19. #include "vgui_controls/Controls.h"
  20. #include "c_portal_player.h"
  21. #include "hud_crosshair.h"
  22. #include "PortalRender.h"
  23. #else
  24. #include "portal_player.h"
  25. #include "vphysics/constraints.h"
  26. #endif
  27. #include "weapon_portalbase.h"
  28. // ----------------------------------------------------------------------------- //
  29. // Global functions.
  30. // ----------------------------------------------------------------------------- //
  31. bool IsAmmoType( int iAmmoType, const char *pAmmoName )
  32. {
  33. return GetAmmoDef()->Index( pAmmoName ) == iAmmoType;
  34. }
  35. static const char * s_WeaponAliasInfo[] =
  36. {
  37. "none", // WEAPON_NONE = 0,
  38. //Melee
  39. "shotgun", //WEAPON_AMERKNIFE,
  40. NULL, // end of list marker
  41. };
  42. // ----------------------------------------------------------------------------- //
  43. // CWeaponPortalBase tables.
  44. // ----------------------------------------------------------------------------- //
  45. IMPLEMENT_NETWORKCLASS_ALIASED( WeaponPortalBase, DT_WeaponPortalBase )
  46. BEGIN_NETWORK_TABLE( CWeaponPortalBase, DT_WeaponPortalBase )
  47. #ifdef CLIENT_DLL
  48. #else
  49. // world weapon models have no aminations
  50. // SendPropExclude( "DT_AnimTimeMustBeFirst", "m_flAnimTime" ),
  51. // SendPropExclude( "DT_BaseAnimating", "m_nSequence" ),
  52. // SendPropExclude( "DT_LocalActiveWeaponData", "m_flTimeWeaponIdle" ),
  53. #endif
  54. END_NETWORK_TABLE()
  55. BEGIN_PREDICTION_DATA( CWeaponPortalBase )
  56. END_PREDICTION_DATA()
  57. LINK_ENTITY_TO_CLASS( weapon_portal_base, CWeaponPortalBase );
  58. #ifdef GAME_DLL
  59. BEGIN_DATADESC( CWeaponPortalBase )
  60. END_DATADESC()
  61. #endif
  62. // ----------------------------------------------------------------------------- //
  63. // CWeaponPortalBase implementation.
  64. // ----------------------------------------------------------------------------- //
  65. CWeaponPortalBase::CWeaponPortalBase()
  66. {
  67. SetPredictionEligible( true );
  68. AddSolidFlags( FSOLID_TRIGGER ); // Nothing collides with these but it gets touches.
  69. m_flNextResetCheckTime = 0.0f;
  70. }
  71. bool CWeaponPortalBase::IsPredicted() const
  72. {
  73. return false;
  74. }
  75. void CWeaponPortalBase::WeaponSound( WeaponSound_t sound_type, float soundtime /* = 0.0f */ )
  76. {
  77. #ifdef CLIENT_DLL
  78. // If we have some sounds from the weapon classname.txt file, play a random one of them
  79. const char *shootsound = GetWpnData().aShootSounds[ sound_type ];
  80. if ( !shootsound || !shootsound[0] )
  81. return;
  82. CBroadcastRecipientFilter filter; // this is client side only
  83. if ( !te->CanPredict() )
  84. return;
  85. CBaseEntity::EmitSound( filter, GetPlayerOwner()->entindex(), shootsound, &GetPlayerOwner()->GetAbsOrigin() );
  86. #else
  87. BaseClass::WeaponSound( sound_type, soundtime );
  88. #endif
  89. }
  90. CBasePlayer* CWeaponPortalBase::GetPlayerOwner() const
  91. {
  92. return dynamic_cast< CBasePlayer* >( GetOwner() );
  93. }
  94. CPortal_Player* CWeaponPortalBase::GetPortalPlayerOwner() const
  95. {
  96. return dynamic_cast< CPortal_Player* >( GetOwner() );
  97. }
  98. #ifdef CLIENT_DLL
  99. void CWeaponPortalBase::OnDataChanged( DataUpdateType_t type )
  100. {
  101. BaseClass::OnDataChanged( type );
  102. if ( GetPredictable() && !ShouldPredict() )
  103. ShutdownPredictable();
  104. }
  105. int CWeaponPortalBase::DrawModel( int flags )
  106. {
  107. if ( !m_bReadyToDraw )
  108. return 0;
  109. if ( GetOwner() && (GetOwner() == C_BasePlayer::GetLocalPlayer()) && !g_pPortalRender->IsRenderingPortal() && !C_BasePlayer::ShouldDrawLocalPlayer() )
  110. return 0;
  111. //Sometimes the return value of ShouldDrawLocalPlayer() fluctuates too often to draw the correct model all the time, so this is a quick fix if it's changed too fast
  112. int iOriginalIndex = GetModelIndex();
  113. bool bChangeModelBack = false;
  114. int iWorldModelIndex = GetWorldModelIndex();
  115. if( iOriginalIndex != iWorldModelIndex )
  116. {
  117. SetModelIndex( iWorldModelIndex );
  118. bChangeModelBack = true;
  119. }
  120. int iRetVal = BaseClass::DrawModel( flags );
  121. if( bChangeModelBack )
  122. SetModelIndex( iOriginalIndex );
  123. return iRetVal;
  124. }
  125. bool CWeaponPortalBase::ShouldDraw( void )
  126. {
  127. if ( !GetOwner() || GetOwner() != C_BasePlayer::GetLocalPlayer() )
  128. return true;
  129. if ( !IsActiveByLocalPlayer() )
  130. return false;
  131. //if ( GetOwner() && GetOwner() == C_BasePlayer::GetLocalPlayer() && materials->GetRenderTarget() == 0 )
  132. // return false;
  133. return true;
  134. }
  135. bool CWeaponPortalBase::ShouldPredict()
  136. {
  137. if ( GetOwner() && GetOwner() == C_BasePlayer::GetLocalPlayer() )
  138. return true;
  139. return BaseClass::ShouldPredict();
  140. }
  141. //-----------------------------------------------------------------------------
  142. // Purpose: Draw the weapon's crosshair
  143. //-----------------------------------------------------------------------------
  144. void CWeaponPortalBase::DrawCrosshair()
  145. {
  146. C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
  147. if ( !player )
  148. return;
  149. Color clr = gHUD.m_clrNormal;
  150. CHudCrosshair *crosshair = GET_HUDELEMENT( CHudCrosshair );
  151. if ( !crosshair )
  152. return;
  153. // Check to see if the player is in VGUI mode...
  154. if (player->IsInVGuiInputMode())
  155. {
  156. CHudTexture *pArrow = gHUD.GetIcon( "arrow" );
  157. crosshair->SetCrosshair( pArrow, gHUD.m_clrNormal );
  158. return;
  159. }
  160. // Find out if this weapon's auto-aimed onto a target
  161. bool bOnTarget = ( m_iState == WEAPON_IS_ONTARGET );
  162. if ( player->GetFOV() >= 90 )
  163. {
  164. // normal crosshairs
  165. if ( bOnTarget && GetWpnData().iconAutoaim )
  166. {
  167. clr[3] = 255;
  168. crosshair->SetCrosshair( GetWpnData().iconAutoaim, clr );
  169. }
  170. else if ( GetWpnData().iconCrosshair )
  171. {
  172. clr[3] = 255;
  173. crosshair->SetCrosshair( GetWpnData().iconCrosshair, clr );
  174. }
  175. else
  176. {
  177. crosshair->ResetCrosshair();
  178. }
  179. }
  180. else
  181. {
  182. Color white( 255, 255, 255, 255 );
  183. // zoomed crosshairs
  184. if (bOnTarget && GetWpnData().iconZoomedAutoaim)
  185. crosshair->SetCrosshair(GetWpnData().iconZoomedAutoaim, white);
  186. else if ( GetWpnData().iconZoomedCrosshair )
  187. crosshair->SetCrosshair( GetWpnData().iconZoomedCrosshair, white );
  188. else
  189. crosshair->ResetCrosshair();
  190. }
  191. }
  192. void CWeaponPortalBase::DoAnimationEvents( CStudioHdr *pStudioHdr )
  193. {
  194. // HACK: Because this model renders view and world models in the same frame
  195. // it's using the wrong studio model when checking the sequences.
  196. C_BasePlayer *pPlayer = UTIL_PlayerByIndex( 1 );
  197. if ( pPlayer && pPlayer->GetActiveWeapon() == this )
  198. {
  199. C_BaseViewModel *pViewModel = pPlayer->GetViewModel();
  200. if ( pViewModel )
  201. {
  202. pStudioHdr = pViewModel->GetModelPtr();
  203. }
  204. }
  205. if ( pStudioHdr )
  206. {
  207. BaseClass::DoAnimationEvents( pStudioHdr );
  208. }
  209. }
  210. void CWeaponPortalBase::GetRenderBounds( Vector& theMins, Vector& theMaxs )
  211. {
  212. if ( IsRagdoll() )
  213. {
  214. m_pRagdoll->GetRagdollBounds( theMins, theMaxs );
  215. }
  216. else if ( GetModel() )
  217. {
  218. CStudioHdr *pStudioHdr = NULL;
  219. // HACK: Because this model renders view and world models in the same frame
  220. // it's using the wrong studio model when checking the sequences.
  221. C_BasePlayer *pPlayer = UTIL_PlayerByIndex( 1 );
  222. if ( pPlayer && pPlayer->GetActiveWeapon() == this )
  223. {
  224. C_BaseViewModel *pViewModel = pPlayer->GetViewModel();
  225. if ( pViewModel )
  226. {
  227. pStudioHdr = pViewModel->GetModelPtr();
  228. }
  229. }
  230. else
  231. {
  232. pStudioHdr = GetModelPtr();
  233. }
  234. if ( !pStudioHdr || !pStudioHdr->SequencesAvailable() || GetSequence() == -1 )
  235. {
  236. theMins = vec3_origin;
  237. theMaxs = vec3_origin;
  238. return;
  239. }
  240. if (!VectorCompare( vec3_origin, pStudioHdr->view_bbmin() ) || !VectorCompare( vec3_origin, pStudioHdr->view_bbmax() ))
  241. {
  242. // clipping bounding box
  243. VectorCopy ( pStudioHdr->view_bbmin(), theMins);
  244. VectorCopy ( pStudioHdr->view_bbmax(), theMaxs);
  245. }
  246. else
  247. {
  248. // movement bounding box
  249. VectorCopy ( pStudioHdr->hull_min(), theMins);
  250. VectorCopy ( pStudioHdr->hull_max(), theMaxs);
  251. }
  252. mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( GetSequence() );
  253. VectorMin( seqdesc.bbmin, theMins, theMins );
  254. VectorMax( seqdesc.bbmax, theMaxs, theMaxs );
  255. }
  256. else
  257. {
  258. theMins = vec3_origin;
  259. theMaxs = vec3_origin;
  260. }
  261. }
  262. #else
  263. void CWeaponPortalBase::Spawn()
  264. {
  265. BaseClass::Spawn();
  266. // Set this here to allow players to shoot dropped weapons
  267. SetCollisionGroup( COLLISION_GROUP_WEAPON );
  268. // Use less bloat for the collision box for this weapon. (bug 43800)
  269. CollisionProp()->UseTriggerBounds( true, 20 );
  270. }
  271. void CWeaponPortalBase:: Materialize( void )
  272. {
  273. if ( IsEffectActive( EF_NODRAW ) )
  274. {
  275. // changing from invisible state to visible.
  276. EmitSound( "AlyxEmp.Charge" );
  277. RemoveEffects( EF_NODRAW );
  278. DoMuzzleFlash();
  279. }
  280. if ( HasSpawnFlags( SF_NORESPAWN ) == false )
  281. {
  282. VPhysicsInitNormal( SOLID_BBOX, GetSolidFlags() | FSOLID_TRIGGER, false );
  283. SetMoveType( MOVETYPE_VPHYSICS );
  284. //PortalRules()->AddLevelDesignerPlacedObject( this );
  285. }
  286. if ( HasSpawnFlags( SF_NORESPAWN ) == false )
  287. {
  288. if ( GetOriginalSpawnOrigin() == vec3_origin )
  289. {
  290. m_vOriginalSpawnOrigin = GetAbsOrigin();
  291. m_vOriginalSpawnAngles = GetAbsAngles();
  292. }
  293. }
  294. SetPickupTouch();
  295. SetThink (NULL);
  296. }
  297. #endif
  298. const CPortalSWeaponInfo &CWeaponPortalBase::GetPortalWpnData() const
  299. {
  300. const FileWeaponInfo_t *pWeaponInfo = &GetWpnData();
  301. const CPortalSWeaponInfo *pPortalInfo;
  302. #ifdef _DEBUG
  303. pPortalInfo = dynamic_cast< const CPortalSWeaponInfo* >( pWeaponInfo );
  304. Assert( pPortalInfo );
  305. #else
  306. pPortalInfo = static_cast< const CPortalSWeaponInfo* >( pWeaponInfo );
  307. #endif
  308. return *pPortalInfo;
  309. }
  310. void CWeaponPortalBase::FireBullets( const FireBulletsInfo_t &info )
  311. {
  312. FireBulletsInfo_t modinfo = info;
  313. modinfo.m_iPlayerDamage = GetPortalWpnData().m_iPlayerDamage;
  314. BaseClass::FireBullets( modinfo );
  315. }
  316. #if defined( CLIENT_DLL )
  317. #include "c_te_effect_dispatch.h"
  318. #define NUM_MUZZLE_FLASH_TYPES 4
  319. bool CWeaponPortalBase::OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options )
  320. {
  321. return BaseClass::OnFireEvent( pViewModel, origin, angles, event, options );
  322. }
  323. void UTIL_ClipPunchAngleOffset( QAngle &in, const QAngle &punch, const QAngle &clip )
  324. {
  325. QAngle final = in + punch;
  326. //Clip each component
  327. for ( int i = 0; i < 3; i++ )
  328. {
  329. if ( final[i] > clip[i] )
  330. {
  331. final[i] = clip[i];
  332. }
  333. else if ( final[i] < -clip[i] )
  334. {
  335. final[i] = -clip[i];
  336. }
  337. //Return the result
  338. in[i] = final[i] - punch[i];
  339. }
  340. }
  341. #endif