Counter Strike : Global Offensive Source Code
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.

461 lines
12 KiB

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