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

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "in_buttons.h"
#include "takedamageinfo.h"
#include "ammodef.h"
#include "portal_gamerules.h"
#ifdef CLIENT_DLL
extern IVModelInfoClient* modelinfo;
#else
extern IVModelInfo* modelinfo;
#endif
#if defined( CLIENT_DLL )
#include "vgui/ISurface.h"
#include "vgui_controls/controls.h"
#include "c_portal_player.h"
#include "hud_crosshair.h"
#include "portalrender.h"
#include "vgui_int.h"
#include "model_types.h"
#else
#include "portal_player.h"
#include "vphysics/constraints.h"
#endif
#include "weapon_portalbase.h"
// ----------------------------------------------------------------------------- //
// Global functions.
// ----------------------------------------------------------------------------- //
bool IsAmmoType( int iAmmoType, const char *pAmmoName )
{
return GetAmmoDef()->Index( pAmmoName ) == iAmmoType;
}
static const char * s_WeaponAliasInfo[] =
{
"none", // WEAPON_NONE = 0,
//Melee
"shotgun", //WEAPON_AMERKNIFE,
NULL, // end of list marker
};
// ----------------------------------------------------------------------------- //
// CWeaponPortalBase tables.
// ----------------------------------------------------------------------------- //
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponPortalBase, DT_WeaponPortalBase )
BEGIN_NETWORK_TABLE( CWeaponPortalBase, DT_WeaponPortalBase )
#ifdef CLIENT_DLL
#else
// world weapon models have no aminations
// SendPropExclude( "DT_AnimTimeMustBeFirst", "m_flAnimTime" ),
// SendPropExclude( "DT_BaseAnimating", "m_nSequence" ),
// SendPropExclude( "DT_LocalActiveWeaponData", "m_flTimeWeaponIdle" ),
#endif
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CWeaponPortalBase )
END_PREDICTION_DATA()
LINK_ENTITY_TO_CLASS_ALIASED( weapon_portal_base, WeaponPortalBase );
#ifdef GAME_DLL
BEGIN_DATADESC( CWeaponPortalBase )
END_DATADESC()
#endif
// ----------------------------------------------------------------------------- //
// CWeaponPortalBase implementation.
// ----------------------------------------------------------------------------- //
CWeaponPortalBase::CWeaponPortalBase()
{
SetPredictionEligible( true );
AddSolidFlags( FSOLID_TRIGGER ); // Nothing collides with these but it gets touches.
m_flNextResetCheckTime = 0.0f;
}
bool CWeaponPortalBase::IsPredicted() const
{
return g_pGameRules->IsMultiplayer();
}
void CWeaponPortalBase::WeaponSound( WeaponSound_t sound_type, float soundtime /* = 0.0f */ )
{
#ifdef CLIENT_DLL
// If we have some sounds from the weapon classname.txt file, play a random one of them
const char *shootsound = GetWpnData().aShootSounds[ sound_type ];
if ( !shootsound || !shootsound[0] )
return;
CBroadcastRecipientFilter filter; // this is client side only
if ( !te->CanPredict() )
return;
CBaseEntity::EmitSound( filter, GetPlayerOwner()->entindex(), shootsound, &GetPlayerOwner()->GetAbsOrigin() );
#else
BaseClass::WeaponSound( sound_type, soundtime );
#endif
}
CBasePlayer* CWeaponPortalBase::GetPlayerOwner() const
{
return dynamic_cast< CBasePlayer* >( GetOwner() );
}
CPortal_Player* CWeaponPortalBase::GetPortalPlayerOwner() const
{
return dynamic_cast< CPortal_Player* >( GetOwner() );
}
#ifdef CLIENT_DLL
void CWeaponPortalBase::OnDataChanged( DataUpdateType_t type )
{
BaseClass::OnDataChanged( type );
if ( GetPredictable() && !ShouldPredict() )
ShutdownPredictable();
}
// opt out of the model fast path for now. Since this model is "drawn" when in first person
// and not looking through a portal and drawing is aborted in DrawModel() the fast path can
// skip this and cause an extra copy of this entity to be visible
IClientModelRenderable* CWeaponPortalBase::GetClientModelRenderable()
{
// NOTE: This should work but doesn't. It makes the object invisible in the portal pass
// I suspect the IsRenderingPortal() test isn't getting re-entered while building the list for the frame
// but I haven't tracked it down. For now I'll just have weapons opt out of the fast path and render
// correctly at lower performance.
#if 0
C_BasePlayer *pOwner = ToBasePlayer( GetOwner() );
if ( pOwner && C_BasePlayer::IsLocalPlayer( pOwner ) )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT( pOwner );
if ( !g_pPortalRender->IsRenderingPortal() && !pOwner->ShouldDrawLocalPlayer() )
return 0;
}
return this;
#else
return NULL;
#endif
}
int CWeaponPortalBase::DrawModel( int flags, const RenderableInstance_t &instance )
{
if ( !m_bReadyToDraw )
return 0;
C_BasePlayer *pOwner = ToBasePlayer( GetOwner() );
if ( pOwner && C_BasePlayer::IsLocalPlayer( pOwner ) )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT( pOwner );
if ( !g_pPortalRender->IsRenderingPortal() && !pOwner->ShouldDrawLocalPlayer() && !VGui_IsSplitScreen() )
return 0;
}
//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
int iOriginalIndex = GetModelIndex();
bool bChangeModelBack = false;
int iWorldModelIndex = GetWorldModelIndex();
if( iOriginalIndex != iWorldModelIndex )
{
SetModelIndex( iWorldModelIndex );
bChangeModelBack = true;
}
int iRetVal = BaseClass::DrawModel( flags, instance );
if( bChangeModelBack )
SetModelIndex( iOriginalIndex );
return iRetVal;
}
bool CWeaponPortalBase::ShouldPredict()
{
if ( C_BasePlayer::IsLocalPlayer( GetOwner() ) )
return true;
return BaseClass::ShouldPredict();
}
//-----------------------------------------------------------------------------
// Purpose: Draw the weapon's crosshair
//-----------------------------------------------------------------------------
void CWeaponPortalBase::DrawCrosshair()
{
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
if ( !player )
return;
Color clr = GetHud().m_clrNormal;
CHudCrosshair *crosshair = GET_HUDELEMENT( CHudCrosshair );
if ( !crosshair )
return;
// Check to see if the player is in VGUI mode...
if (player->IsInVGuiInputMode())
{
CHudTexture *pArrow = HudIcons().GetIcon( "arrow" );
crosshair->SetCrosshair( pArrow, GetHud().m_clrNormal );
return;
}
// Find out if this weapon's auto-aimed onto a target
bool bOnTarget = ( m_iState == WEAPON_IS_ACTIVE ) && player->m_fOnTarget;
if ( player->GetFOV() >= 90 )
{
// normal crosshairs
if ( bOnTarget && GetWpnData().iconAutoaim )
{
clr[3] = 255;
crosshair->SetCrosshair( GetWpnData().iconAutoaim, clr );
}
else if ( GetWpnData().iconCrosshair )
{
clr[3] = 255;
crosshair->SetCrosshair( GetWpnData().iconCrosshair, clr );
}
else
{
crosshair->ResetCrosshair();
}
}
else
{
Color white( 255, 255, 255, 255 );
// zoomed crosshairs
if (bOnTarget && GetWpnData().iconZoomedAutoaim)
crosshair->SetCrosshair(GetWpnData().iconZoomedAutoaim, white);
else if ( GetWpnData().iconZoomedCrosshair )
crosshair->SetCrosshair( GetWpnData().iconZoomedCrosshair, white );
else
crosshair->ResetCrosshair();
}
}
void CWeaponPortalBase::DoAnimationEvents( CStudioHdr *pStudioHdr )
{
// HACK: Because this model renders view and world models in the same frame
// it's using the wrong studio model when checking the sequences.
C_BasePlayer *pPlayer = UTIL_PlayerByIndex( 1 );
if ( pPlayer && pPlayer->GetActiveWeapon() == this )
{
C_BaseViewModel *pViewModel = pPlayer->GetViewModel();
if ( pViewModel )
{
pStudioHdr = pViewModel->GetModelPtr();
}
}
if ( pStudioHdr )
{
BaseClass::DoAnimationEvents( pStudioHdr );
}
}
void CWeaponPortalBase::GetRenderBounds( Vector& theMins, Vector& theMaxs )
{
if ( IsRagdoll() )
{
m_pRagdoll->GetRagdollBounds( theMins, theMaxs );
}
else if ( GetModel() )
{
CStudioHdr *pStudioHdr = NULL;
// HACK: Because this model renders view and world models in the same frame
// it's using the wrong studio model when checking the sequences.
C_BasePlayer *pPlayer = UTIL_PlayerByIndex( 1 );
if ( pPlayer && pPlayer->GetActiveWeapon() == this )
{
C_BaseViewModel *pViewModel = pPlayer->GetViewModel();
if ( pViewModel )
{
pStudioHdr = pViewModel->GetModelPtr();
}
}
else
{
pStudioHdr = GetModelPtr();
}
if ( !pStudioHdr || !pStudioHdr->SequencesAvailable() || GetSequence() == -1 )
{
theMins = vec3_origin;
theMaxs = vec3_origin;
return;
}
if (!VectorCompare( vec3_origin, pStudioHdr->view_bbmin() ) || !VectorCompare( vec3_origin, pStudioHdr->view_bbmax() ))
{
// clipping bounding box
VectorCopy ( pStudioHdr->view_bbmin(), theMins);
VectorCopy ( pStudioHdr->view_bbmax(), theMaxs);
}
else
{
// movement bounding box
VectorCopy ( pStudioHdr->hull_min(), theMins);
VectorCopy ( pStudioHdr->hull_max(), theMaxs);
}
mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( GetSequence() );
VectorMin( seqdesc.bbmin, theMins, theMins );
VectorMax( seqdesc.bbmax, theMaxs, theMaxs );
}
else
{
theMins = vec3_origin;
theMaxs = vec3_origin;
}
}
#else
void CWeaponPortalBase::Spawn()
{
BaseClass::Spawn();
// Set this here to allow players to shoot dropped weapons
SetCollisionGroup( COLLISION_GROUP_WEAPON );
// Use less bloat for the collision box for this weapon. (bug 43800)
CollisionProp()->UseTriggerBounds( true, 20 );
}
void CWeaponPortalBase:: Materialize( void )
{
if ( IsEffectActive( EF_NODRAW ) )
{
// changing from invisible state to visible.
EmitSound( "AlyxEmp.Charge" );
RemoveEffects( EF_NODRAW );
DoMuzzleFlash();
}
if ( HasSpawnFlags( SF_NORESPAWN ) == false )
{
VPhysicsInitNormal( SOLID_BBOX, GetSolidFlags() | FSOLID_TRIGGER, false );
SetMoveType( MOVETYPE_VPHYSICS );
//PortalRules()->AddLevelDesignerPlacedObject( this );
}
if ( HasSpawnFlags( SF_NORESPAWN ) == false )
{
if ( GetOriginalSpawnOrigin() == vec3_origin )
{
m_vOriginalSpawnOrigin = GetAbsOrigin();
m_vOriginalSpawnAngles = GetAbsAngles();
}
}
SetPickupTouch();
SetThink (NULL);
}
#endif
const CPortalSWeaponInfo &CWeaponPortalBase::GetPortalWpnData() const
{
const FileWeaponInfo_t *pWeaponInfo = &GetWpnData();
const CPortalSWeaponInfo *pPortalInfo;
#ifdef _DEBUG
pPortalInfo = dynamic_cast< const CPortalSWeaponInfo* >( pWeaponInfo );
Assert( pPortalInfo );
#else
pPortalInfo = static_cast< const CPortalSWeaponInfo* >( pWeaponInfo );
#endif
return *pPortalInfo;
}
void CWeaponPortalBase::FireBullets( const FireBulletsInfo_t &info )
{
FireBulletsInfo_t modinfo = info;
modinfo.m_flPlayerDamage = GetPortalWpnData().m_iPlayerDamage;
BaseClass::FireBullets( modinfo );
}
#if defined( CLIENT_DLL )
#include "c_te_effect_dispatch.h"
#define NUM_MUZZLE_FLASH_TYPES 4
bool CWeaponPortalBase::OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options )
{
return BaseClass::OnFireEvent( pViewModel, origin, angles, event, options );
}
void UTIL_ClipPunchAngleOffset( QAngle &in, const QAngle &punch, const QAngle &clip )
{
QAngle final = in + punch;
//Clip each component
for ( int i = 0; i < 3; i++ )
{
if ( final[i] > clip[i] )
{
final[i] = clip[i];
}
else if ( final[i] < -clip[i] )
{
final[i] = -clip[i];
}
//Return the result
in[i] = final[i] - punch[i];
}
}
#endif