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
442 lines
10 KiB
//========= Copyright 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" |
|
|
|
#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( weapon_portal_base, CWeaponPortalBase ); |
|
|
|
|
|
#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 false; |
|
} |
|
|
|
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(); |
|
} |
|
|
|
int CWeaponPortalBase::DrawModel( int flags ) |
|
{ |
|
if ( !m_bReadyToDraw ) |
|
return 0; |
|
|
|
if ( GetOwner() && (GetOwner() == C_BasePlayer::GetLocalPlayer()) && !g_pPortalRender->IsRenderingPortal() && !C_BasePlayer::ShouldDrawLocalPlayer() ) |
|
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 ); |
|
|
|
if( bChangeModelBack ) |
|
SetModelIndex( iOriginalIndex ); |
|
|
|
return iRetVal; |
|
} |
|
|
|
bool CWeaponPortalBase::ShouldDraw( void ) |
|
{ |
|
if ( !GetOwner() || GetOwner() != C_BasePlayer::GetLocalPlayer() ) |
|
return true; |
|
|
|
if ( !IsActiveByLocalPlayer() ) |
|
return false; |
|
|
|
//if ( GetOwner() && GetOwner() == C_BasePlayer::GetLocalPlayer() && materials->GetRenderTarget() == 0 ) |
|
// return false; |
|
|
|
return true; |
|
} |
|
|
|
bool CWeaponPortalBase::ShouldPredict() |
|
{ |
|
if ( GetOwner() && GetOwner() == C_BasePlayer::GetLocalPlayer() ) |
|
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 = gHUD.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 = gHUD.GetIcon( "arrow" ); |
|
|
|
crosshair->SetCrosshair( pArrow, gHUD.m_clrNormal ); |
|
return; |
|
} |
|
|
|
// Find out if this weapon's auto-aimed onto a target |
|
bool bOnTarget = ( m_iState == WEAPON_IS_ONTARGET ); |
|
|
|
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_iPlayerDamage = 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 |
|
|
|
|