|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Client side implementation of CBaseCombatWeapon.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "history_resource.h"
#include "iclientmode.h"
#include "iinput.h"
#include "weapon_selection.h"
#include "hud_crosshair.h"
#include "engine/ivmodelinfo.h"
#include "tier0/vprof.h"
#include "hltvcamera.h"
#include "tier1/KeyValues.h"
#include "toolframework/itoolframework.h"
#include "toolframework_client.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose: Gets the local client's active weapon, if any.
//-----------------------------------------------------------------------------
C_BaseCombatWeapon *GetActiveWeapon( void ) { C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
if ( !player ) return NULL;
return player->GetActiveWeapon(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_BaseCombatWeapon::SetDormant( bool bDormant ) { // If I'm going from active to dormant and I'm carried by another player, holster me.
if ( !IsDormant() && bDormant && GetOwner() && !IsCarriedByLocalPlayer() ) { Holster( NULL ); }
BaseClass::SetDormant( bDormant ); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_BaseCombatWeapon::NotifyShouldTransmit( ShouldTransmitState_t state ) { BaseClass::NotifyShouldTransmit(state);
if (state == SHOULDTRANSMIT_END) { if (m_iState == WEAPON_IS_ACTIVE) { m_iState = WEAPON_IS_CARRIED_BY_PLAYER; } } else if( state == SHOULDTRANSMIT_START ) { if( m_iState == WEAPON_IS_CARRIED_BY_PLAYER ) { if( GetOwner() && GetOwner()->GetActiveWeapon() == this ) { // Restore the Activeness of the weapon if we client-twiddled it off in the first case above.
m_iState = WEAPON_IS_ACTIVE; } } } }
//-----------------------------------------------------------------------------
// Purpose: To wrap PORTAL mod specific functionality into one place
//-----------------------------------------------------------------------------
static inline bool ShouldDrawLocalPlayerViewModel( void ) { #if defined( PORTAL )
return false; #else
return !C_BasePlayer::ShouldDrawLocalPlayer(); #endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_BaseCombatWeapon::OnRestore() { BaseClass::OnRestore();
// if the player is holding this weapon,
// mark it as just restored so it won't show as a new pickup
if (GetOwner() == C_BasePlayer::GetLocalPlayer()) { m_bJustRestored = true; } }
int C_BaseCombatWeapon::GetWorldModelIndex( void ) { if ( GameRules() ) { const char *pBaseName = modelinfo->GetModelName( modelinfo->GetModel( m_iWorldModelIndex ) ); const char *pTranslatedName = GameRules()->TranslateEffectForVisionFilter( "weapons", pBaseName );
if ( pTranslatedName != pBaseName ) { return modelinfo->GetModelIndex( pTranslatedName ); } }
return m_iWorldModelIndex; }
//-----------------------------------------------------------------------------
// Purpose:
// Input : bnewentity -
//-----------------------------------------------------------------------------
void C_BaseCombatWeapon::OnDataChanged( DataUpdateType_t updateType ) { BaseClass::OnDataChanged(updateType);
CHandle< C_BaseCombatWeapon > handle = this;
// If it's being carried by the *local* player, on the first update,
// find the registered weapon for this ID
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); C_BaseCombatCharacter *pOwner = GetOwner();
// check if weapon is carried by local player
bool bIsLocalPlayer = pPlayer && pPlayer == pOwner; if ( bIsLocalPlayer && ShouldDrawLocalPlayerViewModel() ) // TODO: figure out the purpose of the ShouldDrawLocalPlayer() test.
{ // If I was just picked up, or created & immediately carried, add myself to this client's list of weapons
if ( (m_iState != WEAPON_NOT_CARRIED ) && (m_iOldState == WEAPON_NOT_CARRIED) ) { // Tell the HUD this weapon's been picked up
if ( ShouldDrawPickup() ) { CBaseHudWeaponSelection *pHudSelection = GetHudWeaponSelection(); if ( pHudSelection ) { pHudSelection->OnWeaponPickup( this ); }
pPlayer->EmitSound( "Player.PickupWeapon" ); } } } else // weapon carried by other player or not at all
{ int overrideModelIndex = CalcOverrideModelIndex(); if( overrideModelIndex != -1 && overrideModelIndex != GetModelIndex() ) { SetModelIndex( overrideModelIndex ); } }
if ( updateType == DATA_UPDATE_CREATED ) { UpdateVisibility(); }
m_iOldState = m_iState;
m_bJustRestored = false; }
//-----------------------------------------------------------------------------
// Is anyone carrying it?
//-----------------------------------------------------------------------------
bool C_BaseCombatWeapon::IsBeingCarried() const { return ( m_hOwner.Get() != NULL ); }
//-----------------------------------------------------------------------------
// Is the carrier alive?
//-----------------------------------------------------------------------------
bool C_BaseCombatWeapon::IsCarrierAlive() const { if ( !m_hOwner.Get() ) return false;
return m_hOwner.Get()->GetHealth() > 0; }
//-----------------------------------------------------------------------------
// Should this object cast shadows?
//-----------------------------------------------------------------------------
ShadowType_t C_BaseCombatWeapon::ShadowCastType() { if ( IsEffectActive( /*EF_NODRAW |*/ EF_NOSHADOW ) ) return SHADOWS_NONE;
if (!IsBeingCarried()) return SHADOWS_RENDER_TO_TEXTURE;
if (IsCarriedByLocalPlayer() && !C_BasePlayer::ShouldDrawLocalPlayer()) return SHADOWS_NONE;
return SHADOWS_RENDER_TO_TEXTURE; }
//-----------------------------------------------------------------------------
// Purpose: This weapon is the active weapon, and it should now draw anything
// it wants to. This gets called every frame.
//-----------------------------------------------------------------------------
void C_BaseCombatWeapon::Redraw() { if ( g_pClientMode->ShouldDrawCrosshair() ) { DrawCrosshair(); }
// ammo drawing has been moved into hud_ammo.cpp
}
//-----------------------------------------------------------------------------
// Purpose: Draw the weapon's crosshair
//-----------------------------------------------------------------------------
void C_BaseCombatWeapon::DrawCrosshair() { C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); if ( !player ) return;
Color clr = gHUD.m_clrNormal; /*
// TEST: if the thing under your crosshair is on a different team, light the crosshair with a different color.
Vector vShootPos, vShootAngles; GetShootPosition( vShootPos, vShootAngles );
Vector vForward; AngleVectors( vShootAngles, &vForward ); // Change the color depending on if we're looking at a friend or an enemy.
CPartitionFilterListMask filter( PARTITION_ALL_CLIENT_EDICTS ); trace_t tr; traceline->TraceLine( vShootPos, vShootPos + vForward * 10000, COLLISION_GROUP_NONE, MASK_SHOT, &tr, true, ~0, &filter );
if ( tr.index != 0 && tr.index != INVALID_CLIENTENTITY_HANDLE ) { C_BaseEntity *pEnt = ClientEntityList().GetBaseEntityFromHandle( tr.index ); if ( pEnt ) { if ( pEnt->GetTeamNumber() != player->GetTeamNumber() ) { g = b = 0; } } } */
CHudCrosshair *pCrosshair = GET_HUDELEMENT( CHudCrosshair ); if ( !pCrosshair ) 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;
pCrosshair->SetCrosshair( GetWpnData().iconAutoaim, clr ); } else if ( GetWpnData().iconCrosshair ) { clr[3] = 255; pCrosshair->SetCrosshair( GetWpnData().iconCrosshair, clr ); } else { pCrosshair->ResetCrosshair(); } } else { Color white( 255, 255, 255, 255 );
// zoomed crosshairs
if (bOnTarget && GetWpnData().iconZoomedAutoaim) pCrosshair->SetCrosshair(GetWpnData().iconZoomedAutoaim, white); else if ( GetWpnData().iconZoomedCrosshair ) pCrosshair->SetCrosshair( GetWpnData().iconZoomedCrosshair, white ); else pCrosshair->ResetCrosshair(); } }
//-----------------------------------------------------------------------------
// Purpose: This weapon is the active weapon, and the viewmodel for it was just drawn.
//-----------------------------------------------------------------------------
void C_BaseCombatWeapon::ViewModelDrawn( C_BaseViewModel *pViewModel ) { }
//-----------------------------------------------------------------------------
// Purpose: Returns true if this client's carrying this weapon
//-----------------------------------------------------------------------------
bool C_BaseCombatWeapon::IsCarriedByLocalPlayer( void ) { if ( !GetOwner() ) return false;
return ( GetOwner() == C_BasePlayer::GetLocalPlayer() ); }
//-----------------------------------------------------------------------------
// Purpose: Returns true if this client is carrying this weapon and is
// using the view models
//-----------------------------------------------------------------------------
bool C_BaseCombatWeapon::ShouldDrawUsingViewModel( void ) { return IsCarriedByLocalPlayer() && !C_BasePlayer::ShouldDrawLocalPlayer(); }
//-----------------------------------------------------------------------------
// Purpose: Returns true if this weapon is the local client's currently wielded weapon
//-----------------------------------------------------------------------------
bool C_BaseCombatWeapon::IsActiveByLocalPlayer( void ) { if ( IsCarriedByLocalPlayer() ) { return (m_iState == WEAPON_IS_ACTIVE); }
return false; }
bool C_BaseCombatWeapon::GetShootPosition( Vector &vOrigin, QAngle &vAngles ) { // Get the entity because the weapon doesn't have the right angles.
C_BaseCombatCharacter *pEnt = ToBaseCombatCharacter( GetOwner() ); if ( pEnt ) { if ( pEnt == C_BasePlayer::GetLocalPlayer() ) { vAngles = pEnt->EyeAngles(); } else { vAngles = pEnt->GetRenderAngles(); } } else { vAngles.Init(); }
QAngle vDummy; if ( IsActiveByLocalPlayer() && ShouldDrawLocalPlayerViewModel() ) { C_BasePlayer *player = ToBasePlayer( pEnt ); C_BaseViewModel *vm = player ? player->GetViewModel( 0 ) : NULL; if ( vm ) { int iAttachment = vm->LookupAttachment( "muzzle" ); if ( vm->GetAttachment( iAttachment, vOrigin, vDummy ) ) { return true; } } } else { // Thirdperson
int iAttachment = LookupAttachment( "muzzle" ); if ( GetAttachment( iAttachment, vOrigin, vDummy ) ) { return true; } }
vOrigin = GetRenderOrigin(); return false; }
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool C_BaseCombatWeapon::ShouldDraw( void ) { if ( m_iWorldModelIndex == 0 ) return false;
// FIXME: All weapons with owners are set to transmit in CBaseCombatWeapon::UpdateTransmitState,
// even if they have EF_NODRAW set, so we have to check this here. Ideally they would never
// transmit except for the weapons owned by the local player.
if ( IsEffectActive( EF_NODRAW ) ) return false;
C_BaseCombatCharacter *pOwner = GetOwner();
// weapon has no owner, always draw it
if ( !pOwner ) return true;
bool bIsActive = ( m_iState == WEAPON_IS_ACTIVE );
C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
// carried by local player?
if ( pOwner == pLocalPlayer ) { // Only ever show the active weapon
if ( !bIsActive ) return false;
if ( !pOwner->ShouldDraw() ) { // Our owner is invisible.
// This also tests whether the player is zoomed in, in which case you don't want to draw the weapon.
return false; }
// 3rd person mode?
if ( !ShouldDrawLocalPlayerViewModel() ) return true;
// don't draw active weapon if not in some kind of 3rd person mode, the viewmodel will do that
return false; }
// If it's a player, then only show active weapons
if ( pOwner->IsPlayer() ) { // Show it if it's active...
return bIsActive; }
// FIXME: We may want to only show active weapons on NPCs
// These are carried by AIs; always show them
return true; }
//-----------------------------------------------------------------------------
// Purpose: Return true if a weapon-pickup icon should be displayed when this weapon is received
//-----------------------------------------------------------------------------
bool C_BaseCombatWeapon::ShouldDrawPickup( void ) { if ( GetWeaponFlags() & ITEM_FLAG_NOITEMPICKUP ) return false;
if ( m_bJustRestored ) return false;
return true; } //-----------------------------------------------------------------------------
// Purpose: Render the weapon. Draw the Viewmodel if the weapon's being carried
// by this player, otherwise draw the worldmodel.
//-----------------------------------------------------------------------------
int C_BaseCombatWeapon::DrawModel( int flags ) { VPROF_BUDGET( "C_BaseCombatWeapon::DrawModel", VPROF_BUDGETGROUP_MODEL_RENDERING ); if ( !m_bReadyToDraw ) return 0;
if ( !IsVisible() ) return 0;
// check if local player chases owner of this weapon in first person
C_BasePlayer *localplayer = C_BasePlayer::GetLocalPlayer();
if ( localplayer && localplayer->IsObserver() && GetOwner() ) { // don't draw weapon if chasing this guy as spectator
// we don't check that in ShouldDraw() since this may change
// without notification
if ( localplayer->GetObserverMode() == OBS_MODE_IN_EYE && localplayer->GetObserverTarget() == GetOwner() ) return false; }
return BaseClass::DrawModel( flags ); }
//-----------------------------------------------------------------------------
// Allows the client-side entity to override what the network tells it to use for
// a model. This is used for third person mode, specifically in HL2 where the
// the weapon timings are on the view model and not the world model. That means the
// server needs to use the view model, but the client wants to use the world model.
//-----------------------------------------------------------------------------
int C_BaseCombatWeapon::CalcOverrideModelIndex() { C_BasePlayer *localplayer = C_BasePlayer::GetLocalPlayer(); if ( localplayer && localplayer == GetOwner() && ShouldDrawLocalPlayerViewModel() ) { return BaseClass::CalcOverrideModelIndex(); } else { return GetWorldModelIndex(); } }
//-----------------------------------------------------------------------------
// tool recording
//-----------------------------------------------------------------------------
void C_BaseCombatWeapon::GetToolRecordingState( KeyValues *msg ) { if ( !ToolsEnabled() ) return;
int nModelIndex = GetModelIndex(); int nWorldModelIndex = GetWorldModelIndex(); if ( nModelIndex != nWorldModelIndex ) { SetModelIndex( nWorldModelIndex ); }
BaseClass::GetToolRecordingState( msg );
if ( m_iState == WEAPON_NOT_CARRIED ) { BaseEntityRecordingState_t *pBaseEntity = (BaseEntityRecordingState_t*)msg->GetPtr( "baseentity" ); pBaseEntity->m_nOwner = -1; } else { msg->SetInt( "worldmodel", 1 ); if ( m_iState == WEAPON_IS_ACTIVE ) { BaseEntityRecordingState_t *pBaseEntity = (BaseEntityRecordingState_t*)msg->GetPtr( "baseentity" ); pBaseEntity->m_bVisible = true; } }
if ( nModelIndex != nWorldModelIndex ) { SetModelIndex( nModelIndex ); } }
|