sqwarmed/sdk_src/game/client/c_basecombatweapon.cpp

546 lines
16 KiB
C++

//========= Copyright © 1996-2005, 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:
//-----------------------------------------------------------------------------
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 && !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;
}
}
}
}
static inline bool ShouldDrawLocalPlayer( C_BasePlayer *pl )
{
Assert( pl );
return pl->ShouldDrawLocalPlayer();
}
//-----------------------------------------------------------------------------
// 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 ( C_BasePlayer::IsLocalPlayer( GetOwner() ) )
{
m_bJustRestored = true;
}
}
int C_BaseCombatWeapon::GetWorldModelIndex( void )
{
return m_iWorldModelIndex;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : bnewentity -
//-----------------------------------------------------------------------------
void C_BaseCombatWeapon::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
// If it's being carried by the *local* player, on the first update,
// find the registered weapon for this ID
C_BaseCombatCharacter *pOwner = GetOwner();
C_BasePlayer *pPlayer = ToBasePlayer( pOwner );
// check if weapon is carried by local player
bool bIsLocalPlayer = C_BasePlayer::IsLocalPlayer( pPlayer );
if ( bIsLocalPlayer )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD( C_BasePlayer::GetSplitScreenSlotForPlayer( pPlayer ) );
// 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" );
}
}
}
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())
return SHADOWS_NONE;
return (m_iState != WEAPON_IS_CARRIED_BY_PLAYER) ? SHADOWS_RENDER_TO_TEXTURE : SHADOWS_NONE;
}
//-----------------------------------------------------------------------------
// 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 ( GetClientMode()->ShouldDrawCrosshair() )
{
DrawCrosshair();
}
// ammo drawing has been moved into hud_ammo.cpp
}
//-----------------------------------------------------------------------------
// Purpose: Draw the weapon's crosshair
//-----------------------------------------------------------------------------
void C_BaseCombatWeapon::DrawCrosshair()
{
#ifndef INFESTED_DLL
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
if ( !player )
return;
Color clr = GetHud().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 *crosshair = GET_HUDELEMENT( CHudCrosshair );
if ( !crosshair )
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();
}
#endif
}
//-----------------------------------------------------------------------------
// 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 ( C_BasePlayer::IsLocalPlayer( GetOwner() ) );
}
//-----------------------------------------------------------------------------
// 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();
}
C_BasePlayer *player = ToBasePlayer( pEnt );
bool bUseViewModel = false;
if ( C_BasePlayer::IsLocalPlayer( pEnt ) )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT( pEnt );
bUseViewModel = !player->ShouldDrawLocalPlayer();
}
QAngle vDummy;
if ( IsActiveByLocalPlayer() && bUseViewModel )
{
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;
// 3rd person mode
if ( pLocalPlayer->ShouldDrawLocalPlayer() )
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;
}
//----------------------------------------------------------------------------
// Hooks into the fast path render system
//----------------------------------------------------------------------------
IClientModelRenderable* C_BaseCombatWeapon::GetClientModelRenderable()
{
if ( !m_bReadyToDraw )
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 NULL;
}
if ( !BaseClass::GetClientModelRenderable() )
return NULL;
EnsureCorrectRenderingModel();
return this;
}
//-----------------------------------------------------------------------------
// 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, const RenderableInstance_t &instance )
{
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;
}
// See comment below
EnsureCorrectRenderingModel();
return BaseClass::DrawModel( flags, instance );
}
// If the local player is visible (thirdperson mode, tf2 taunts, etc., then make sure that we are using the
// w_ (world) model not the v_ (view) model or else the model can flicker, etc.
// Otherwise, if we're not the local player, always use the world model
void C_BaseCombatWeapon::EnsureCorrectRenderingModel()
{
C_BasePlayer *localplayer = C_BasePlayer::GetLocalPlayer();
if ( localplayer &&
localplayer == GetOwner() &&
!localplayer->ShouldDrawLocalPlayer() )
{
return;
}
// BRJ 10/14/02
// FIXME: Remove when Yahn's client-side prediction is done
// It's a hacky workaround for the model indices fighting
// (GetRenderBounds uses the model index, which is for the view model)
SetModelIndex( GetWorldModelIndex() );
// Validate our current sequence just in case ( in theory the view and weapon models should have the same sequences for sequences that overlap at least )
CStudioHdr *pStudioHdr = GetModelPtr();
if ( pStudioHdr &&
GetSequence() >= pStudioHdr->GetNumSeq() )
{
SetSequence( 0 );
}
}
//-----------------------------------------------------------------------------
// 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 );
}
}