|
|
//========= 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
|