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.
1416 lines
36 KiB
1416 lines
36 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#include "cbase.h" |
|
#include "in_buttons.h" |
|
#include "takedamageinfo.h" |
|
#include "weapon_dodbase.h" |
|
#include "ammodef.h" |
|
#include "dod_gamerules.h" |
|
|
|
#ifdef CLIENT_DLL |
|
extern IVModelInfoClient* modelinfo; |
|
#else |
|
extern IVModelInfo* modelinfo; |
|
#include "ilagcompensationmanager.h" |
|
#endif |
|
|
|
|
|
#if defined( CLIENT_DLL ) |
|
|
|
#include "vgui/ISurface.h" |
|
#include "vgui_controls/Controls.h" |
|
#include "c_dod_player.h" |
|
#include "hud_crosshair.h" |
|
#include "SoundEmitterSystem/isoundemittersystembase.h" |
|
|
|
#else |
|
|
|
#include "dod_player.h" |
|
|
|
#endif |
|
|
|
#include "effect_dispatch_data.h" |
|
|
|
|
|
// ----------------------------------------------------------------------------- // |
|
// Global functions. |
|
// ----------------------------------------------------------------------------- // |
|
|
|
bool IsAmmoType( int iAmmoType, const char *pAmmoName ) |
|
{ |
|
return GetAmmoDef()->Index( pAmmoName ) == iAmmoType; |
|
} |
|
|
|
//-------------------------------------------------------------------------------------------------------- |
|
// |
|
// Given a weapon ID, return its alias |
|
// |
|
const char *WeaponIDToAlias( int id ) |
|
{ |
|
if ( (id >= WEAPON_MAX) || (id < 0) ) |
|
return NULL; |
|
|
|
return s_WeaponAliasInfo[id]; |
|
} |
|
|
|
// ----------------------------------------------------------------------------- // |
|
// CWeaponDODBase tables. |
|
// ----------------------------------------------------------------------------- // |
|
|
|
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponDODBase, DT_WeaponDODBase ) |
|
|
|
BEGIN_NETWORK_TABLE( CWeaponDODBase, DT_WeaponDODBase ) |
|
#ifdef CLIENT_DLL |
|
RecvPropInt( RECVINFO(m_iReloadModelIndex) ), |
|
RecvPropVector( RECVINFO( m_vInitialDropVelocity ) ), |
|
RecvPropTime( RECVINFO( m_flSmackTime ) ) |
|
#else |
|
SendPropVector( SENDINFO( m_vInitialDropVelocity ), |
|
20, // nbits |
|
0, // flags |
|
-3000, // low value |
|
3000 // high value |
|
), |
|
SendPropModelIndex( SENDINFO(m_iReloadModelIndex) ), |
|
SendPropTime( SENDINFO( m_flSmackTime ) ) |
|
#endif |
|
END_NETWORK_TABLE() |
|
|
|
LINK_ENTITY_TO_CLASS( weapon_dod_base, CWeaponDODBase ); |
|
|
|
|
|
#ifdef GAME_DLL |
|
|
|
BEGIN_DATADESC( CWeaponDODBase ) |
|
|
|
DEFINE_FUNCTION( FallThink ), |
|
DEFINE_FUNCTION( Die ), |
|
|
|
DEFINE_FUNCTION( Smack ) |
|
|
|
END_DATADESC() |
|
|
|
#else |
|
BEGIN_PREDICTION_DATA( CWeaponDODBase ) |
|
DEFINE_PRED_FIELD( m_flSmackTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), // for rifle melee attacks |
|
DEFINE_FIELD( m_bInAttack, FIELD_BOOLEAN ) |
|
END_PREDICTION_DATA() |
|
#endif |
|
|
|
Vector head_hull_mins( -16, -16, -18 ); |
|
Vector head_hull_maxs( 16, 16, 18 ); |
|
|
|
void FindHullIntersection( const Vector &vecSrc, trace_t &tr, const Vector &mins, const Vector &maxs, CBaseEntity *pEntity ) |
|
{ |
|
int i, j, k; |
|
float distance; |
|
Vector minmaxs[2] = {mins, maxs}; |
|
trace_t tmpTrace; |
|
Vector vecHullEnd = tr.endpos; |
|
Vector vecEnd; |
|
|
|
CTraceFilterSimple filter( pEntity, COLLISION_GROUP_NONE ); |
|
|
|
distance = 1e6f; |
|
|
|
vecHullEnd = vecSrc + ((vecHullEnd - vecSrc)*2); |
|
UTIL_TraceLine( vecSrc, vecHullEnd, MASK_SOLID, &filter, &tmpTrace ); |
|
if ( tmpTrace.fraction < 1.0 ) |
|
{ |
|
tr = tmpTrace; |
|
return; |
|
} |
|
|
|
for ( i = 0; i < 2; i++ ) |
|
{ |
|
for ( j = 0; j < 2; j++ ) |
|
{ |
|
for ( k = 0; k < 2; k++ ) |
|
{ |
|
vecEnd.x = vecHullEnd.x + minmaxs[i][0]; |
|
vecEnd.y = vecHullEnd.y + minmaxs[j][1]; |
|
vecEnd.z = vecHullEnd.z + minmaxs[k][2]; |
|
|
|
UTIL_TraceLine( vecSrc, vecEnd, MASK_SOLID, &filter, &tmpTrace ); |
|
if ( tmpTrace.fraction < 1.0 ) |
|
{ |
|
float thisDistance = (tmpTrace.endpos - vecSrc).Length(); |
|
if ( thisDistance < distance ) |
|
{ |
|
tr = tmpTrace; |
|
distance = thisDistance; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
// ----------------------------------------------------------------------------- // |
|
// CWeaponDODBase implementation. |
|
// ----------------------------------------------------------------------------- // |
|
CWeaponDODBase::CWeaponDODBase() |
|
{ |
|
SetPredictionEligible( true ); |
|
m_bInAttack = false; |
|
m_iAltFireHint = 0; |
|
AddSolidFlags( FSOLID_TRIGGER ); // Nothing collides with these but it gets touches. |
|
|
|
m_flNextPrimaryAttack = 0; |
|
} |
|
|
|
|
|
bool CWeaponDODBase::IsPredicted() const |
|
{ |
|
return true; |
|
} |
|
|
|
bool CWeaponDODBase::PlayEmptySound() |
|
{ |
|
CPASAttenuationFilter filter( this ); |
|
filter.UsePredictionRules(); |
|
EmitSound( filter, entindex(), "Default.ClipEmpty_Rifle" ); |
|
|
|
return false; |
|
} |
|
|
|
|
|
CBasePlayer* CWeaponDODBase::GetPlayerOwner() const |
|
{ |
|
return dynamic_cast< CBasePlayer* >( GetOwner() ); |
|
} |
|
|
|
CDODPlayer* CWeaponDODBase::GetDODPlayerOwner() const |
|
{ |
|
return dynamic_cast< CDODPlayer* >( GetOwner() ); |
|
} |
|
|
|
bool CWeaponDODBase::SendWeaponAnim( int iActivity ) |
|
{ |
|
return BaseClass::SendWeaponAnim( iActivity ); |
|
} |
|
|
|
bool CWeaponDODBase::CanAttack( void ) |
|
{ |
|
CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() ); |
|
|
|
if ( pPlayer ) |
|
{ |
|
return pPlayer->CanAttack(); |
|
} |
|
|
|
return false; |
|
} |
|
|
|
bool CWeaponDODBase::ShouldAutoReload( void ) |
|
{ |
|
CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() ); |
|
|
|
if ( pPlayer ) |
|
{ |
|
return pPlayer->ShouldAutoReload(); |
|
} |
|
|
|
return false; |
|
} |
|
|
|
void CWeaponDODBase::ItemPostFrame() |
|
{ |
|
if ( m_flSmackTime > 0 && gpGlobals->curtime > m_flSmackTime ) |
|
{ |
|
Smack(); |
|
m_flSmackTime = -1; |
|
} |
|
|
|
CBasePlayer *pPlayer = GetPlayerOwner(); |
|
|
|
if ( !pPlayer ) |
|
return; |
|
|
|
#ifdef _DEBUG |
|
CDODGameRules *mp = DODGameRules(); |
|
#endif |
|
|
|
assert( mp ); |
|
|
|
if ((m_bInReload) && (pPlayer->m_flNextAttack <= gpGlobals->curtime)) |
|
{ |
|
// complete the reload. |
|
int j = MIN( GetMaxClip1() - m_iClip1, pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) ); |
|
|
|
// Add them to the clip |
|
m_iClip1 += j; |
|
pPlayer->RemoveAmmo( j, m_iPrimaryAmmoType ); |
|
|
|
m_bInReload = false; |
|
|
|
FinishReload(); |
|
} |
|
|
|
if ((pPlayer->m_nButtons & IN_ATTACK2) && (m_flNextSecondaryAttack <= gpGlobals->curtime)) |
|
{ |
|
if ( m_iClip2 != -1 && !pPlayer->GetAmmoCount( GetSecondaryAmmoType() ) ) |
|
{ |
|
m_bFireOnEmpty = TRUE; |
|
} |
|
|
|
SecondaryAttack(); |
|
|
|
pPlayer->m_nButtons &= ~IN_ATTACK2; |
|
} |
|
else if ((pPlayer->m_nButtons & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime ) && !m_bInAttack ) |
|
{ |
|
if ( (m_iClip1 == 0/* && pszAmmo1()*/) || (GetMaxClip1() == -1 && !pPlayer->GetAmmoCount( GetPrimaryAmmoType() ) ) ) |
|
{ |
|
m_bFireOnEmpty = TRUE; |
|
} |
|
|
|
if( CanAttack() ) |
|
PrimaryAttack(); |
|
} |
|
else if ( pPlayer->m_nButtons & IN_RELOAD && GetMaxClip1() != WEAPON_NOCLIP && !m_bInReload && m_flNextPrimaryAttack < gpGlobals->curtime) |
|
{ |
|
// reload when reload is pressed, or if no buttons are down and weapon is empty. |
|
Reload(); |
|
} |
|
else if ( !(pPlayer->m_nButtons & (IN_ATTACK|IN_ATTACK2) ) ) |
|
{ |
|
// no fire buttons down |
|
|
|
m_bFireOnEmpty = false; |
|
|
|
m_bInAttack = false; //reset semi-auto |
|
|
|
if ( !IsUseable() && m_flNextPrimaryAttack < gpGlobals->curtime ) |
|
{ |
|
// Intentionally blank -- used to switch weapons here |
|
} |
|
else if( ShouldAutoReload() ) |
|
{ |
|
// weapon is useable. Reload if empty and weapon has waited as long as it has to after firing |
|
if ( m_iClip1 == 0 && !(GetWeaponFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < gpGlobals->curtime ) |
|
{ |
|
Reload(); |
|
return; |
|
} |
|
} |
|
|
|
WeaponIdle( ); |
|
return; |
|
} |
|
} |
|
|
|
void CWeaponDODBase::WeaponIdle() |
|
{ |
|
if (m_flTimeWeaponIdle > gpGlobals->curtime) |
|
return; |
|
|
|
SendWeaponAnim( GetIdleActivity() ); |
|
|
|
m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration(); |
|
} |
|
|
|
Activity CWeaponDODBase::GetIdleActivity( void ) |
|
{ |
|
return ACT_VM_IDLE; |
|
} |
|
|
|
const CDODWeaponInfo &CWeaponDODBase::GetDODWpnData() const |
|
{ |
|
const FileWeaponInfo_t *pWeaponInfo = &GetWpnData(); |
|
const CDODWeaponInfo *pDODInfo; |
|
|
|
#ifdef _DEBUG |
|
pDODInfo = dynamic_cast< const CDODWeaponInfo* >( pWeaponInfo ); |
|
Assert( pDODInfo ); |
|
#else |
|
pDODInfo = static_cast< const CDODWeaponInfo* >( pWeaponInfo ); |
|
#endif |
|
|
|
return *pDODInfo; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
const char *CWeaponDODBase::GetViewModel( int /*viewmodelindex = 0 -- this is ignored in the base class here*/ ) const |
|
{ |
|
if ( GetPlayerOwner() == NULL ) |
|
{ |
|
return BaseClass::GetViewModel(); |
|
} |
|
|
|
return GetWpnData().szViewModel; |
|
} |
|
|
|
void CWeaponDODBase::Precache( void ) |
|
{ |
|
// precache base first, it loads weapon scripts |
|
BaseClass::Precache(); |
|
|
|
PrecacheScriptSound( "Default.ClipEmpty_Rifle" ); |
|
|
|
PrecacheParticleSystem( "muzzle_pistols" ); |
|
PrecacheParticleSystem( "muzzle_fullyautomatic" ); |
|
PrecacheParticleSystem( "muzzle_rifles" ); |
|
PrecacheParticleSystem( "muzzle_rockets" ); |
|
PrecacheParticleSystem( "muzzle_mg42" ); |
|
|
|
PrecacheParticleSystem( "view_muzzle_pistols" ); |
|
PrecacheParticleSystem( "view_muzzle_fullyautomatic" ); |
|
PrecacheParticleSystem( "view_muzzle_rifles" ); |
|
PrecacheParticleSystem( "view_muzzle_rockets" ); |
|
PrecacheParticleSystem( "view_muzzle_mg42" ); |
|
|
|
const CDODWeaponInfo &info = GetDODWpnData(); |
|
|
|
int iWpnNameLen = Q_strlen(info.m_szReloadModel); |
|
|
|
#ifdef DEBUG |
|
// Make sure that if we declare an alt weapon, that we have criteria to show it |
|
// and vice-versa |
|
//Assert( ((info.m_iAltWpnCriteria & (ALTWPN_CRITERIA_RELOADING | ALTWPN_CRITERIA_FIRING)) > 0 ) == |
|
// (iWpnNameLen > 0) ); |
|
#endif |
|
|
|
if( iWpnNameLen > 0 ) |
|
m_iReloadModelIndex = CBaseEntity::PrecacheModel( info.m_szReloadModel ); |
|
} |
|
|
|
bool CWeaponDODBase::DefaultDeploy( char *szViewModel, char *szWeaponModel, int iActivity, char *szAnimExt ) |
|
{ |
|
CBasePlayer *pOwner = GetPlayerOwner(); |
|
if ( !pOwner ) |
|
{ |
|
return false; |
|
} |
|
|
|
pOwner->SetAnimationExtension( szAnimExt ); |
|
|
|
SetViewModel(); |
|
SendWeaponAnim( iActivity ); |
|
|
|
pOwner->SetNextAttack( gpGlobals->curtime + SequenceDuration() ); |
|
m_flNextPrimaryAttack = MAX( m_flNextPrimaryAttack, gpGlobals->curtime ); |
|
m_flNextSecondaryAttack = gpGlobals->curtime; |
|
|
|
SetWeaponVisible( true ); |
|
SetWeaponModelIndex( szWeaponModel ); |
|
|
|
CBaseViewModel *vm = pOwner->GetViewModel( m_nViewModelIndex ); |
|
|
|
Assert( vm ); |
|
|
|
if( vm ) |
|
{ |
|
//set sleeves to proper team |
|
switch( pOwner->GetTeamNumber() ) |
|
{ |
|
case TEAM_ALLIES: |
|
vm->m_nSkin = SLEEVE_ALLIES; |
|
break; |
|
case TEAM_AXIS: |
|
vm->m_nSkin = SLEEVE_AXIS; |
|
break; |
|
default: |
|
Assert( !"TEAM_UNASSIGNED or spectator getting a view model assigned" ); |
|
break; |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
void CWeaponDODBase::SetWeaponModelIndex( const char *pName ) |
|
{ |
|
m_iWorldModelIndex = modelinfo->GetModelIndex( pName ); |
|
} |
|
|
|
bool CWeaponDODBase::CanBeSelected( void ) |
|
{ |
|
if ( !VisibleInWeaponSelection() ) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
bool CWeaponDODBase::CanDeploy( void ) |
|
{ |
|
return BaseClass::CanDeploy(); |
|
} |
|
|
|
bool CWeaponDODBase::CanHolster( void ) |
|
{ |
|
return BaseClass::CanHolster(); |
|
} |
|
|
|
void CWeaponDODBase::Drop( const Vector &vecVelocity ) |
|
{ |
|
#ifndef CLIENT_DLL |
|
if ( m_iAltFireHint ) |
|
{ |
|
CDODPlayer *pPlayer = GetDODPlayerOwner(); |
|
if ( pPlayer ) |
|
{ |
|
pPlayer->StopHintTimer( m_iAltFireHint ); |
|
} |
|
} |
|
#endif |
|
|
|
// cancel any reload in progress |
|
m_bInReload = false; |
|
|
|
m_flSmackTime = -1; |
|
|
|
m_vInitialDropVelocity = vecVelocity; |
|
|
|
BaseClass::Drop( m_vInitialDropVelocity ); |
|
} |
|
|
|
bool CWeaponDODBase::Holster( CBaseCombatWeapon *pSwitchingTo ) |
|
{ |
|
#ifndef CLIENT_DLL |
|
CDODPlayer *pPlayer = GetDODPlayerOwner(); |
|
|
|
if ( pPlayer ) |
|
{ |
|
pPlayer->SetFOV( pPlayer, 0 ); // reset the default FOV. |
|
|
|
if ( m_iAltFireHint ) |
|
{ |
|
pPlayer->StopHintTimer( m_iAltFireHint ); |
|
} |
|
} |
|
#endif |
|
|
|
m_bInReload = false; |
|
|
|
m_flSmackTime = -1; |
|
|
|
return BaseClass::Holster( pSwitchingTo ); |
|
} |
|
|
|
bool CWeaponDODBase::Deploy() |
|
{ |
|
#ifndef CLIENT_DLL |
|
CDODPlayer *pPlayer = GetDODPlayerOwner(); |
|
|
|
if ( pPlayer ) |
|
{ |
|
pPlayer->SetFOV( pPlayer, 0 ); |
|
|
|
if ( m_iAltFireHint ) |
|
{ |
|
pPlayer->StartHintTimer( m_iAltFireHint ); |
|
} |
|
} |
|
#endif |
|
|
|
return BaseClass::Deploy(); |
|
} |
|
|
|
#ifdef CLIENT_DLL |
|
|
|
void CWeaponDODBase::PostDataUpdate( DataUpdateType_t updateType ) |
|
{ |
|
// We need to do this before the C_BaseAnimating code starts to drive |
|
// clientside animation sequences on this model, which will be using bad sequences for the world model. |
|
int iDesiredModelIndex = 0; |
|
C_BasePlayer *localplayer = C_BasePlayer::GetLocalPlayer(); |
|
if ( localplayer && localplayer == GetOwner() && !C_BasePlayer::ShouldDrawLocalPlayer() ) // FIXME: use localplayer->ShouldDrawThisPlayer() instead. |
|
{ |
|
iDesiredModelIndex = m_iViewModelIndex; |
|
} |
|
else |
|
{ |
|
iDesiredModelIndex = GetWorldModelIndex(); |
|
|
|
// Our world models never animate |
|
SetSequence( 0 ); |
|
} |
|
|
|
if ( GetModelIndex() != iDesiredModelIndex ) |
|
{ |
|
SetModelIndex( iDesiredModelIndex ); |
|
} |
|
|
|
BaseClass::PostDataUpdate( updateType ); |
|
} |
|
|
|
void CWeaponDODBase::OnDataChanged( DataUpdateType_t type ) |
|
{ |
|
if ( m_iState == WEAPON_NOT_CARRIED && m_iOldState != WEAPON_NOT_CARRIED ) |
|
{ |
|
// we are being notified of the weapon being dropped |
|
// add an interpolation history so the movement is smoother |
|
|
|
// Now stick our initial velocity into the interpolation history |
|
CInterpolatedVar< Vector > &interpolator = GetOriginInterpolator(); |
|
|
|
interpolator.ClearHistory(); |
|
float changeTime = GetLastChangeTime( LATCH_SIMULATION_VAR ); |
|
|
|
// Add a sample 1 second back. |
|
Vector vCurOrigin = GetLocalOrigin() - m_vInitialDropVelocity; |
|
interpolator.AddToHead( changeTime - 1.0, &vCurOrigin, false ); |
|
|
|
// Add the current sample. |
|
vCurOrigin = GetLocalOrigin(); |
|
interpolator.AddToHead( changeTime, &vCurOrigin, false ); |
|
|
|
Vector estVel; |
|
EstimateAbsVelocity( estVel ); |
|
|
|
/*Msg( "estimated velocity ( %.1f %.1f %.1f ) initial velocity ( %.1f %.1f %.1f )\n", |
|
estVel.x, |
|
estVel.y, |
|
estVel.z, |
|
m_vInitialDropVelocity.m_Value.x, |
|
m_vInitialDropVelocity.m_Value.y, |
|
m_vInitialDropVelocity.m_Value.z );*/ |
|
|
|
OnWeaponDropped(); |
|
} |
|
|
|
BaseClass::OnDataChanged( type ); |
|
|
|
if ( GetPredictable() && !ShouldPredict() ) |
|
ShutdownPredictable(); |
|
} |
|
|
|
int CWeaponDODBase::GetWorldModelIndex( void ) |
|
{ |
|
if( m_bUseAltWeaponModel && GetOwner() != NULL ) |
|
return m_iReloadModelIndex; |
|
else |
|
return m_iWorldModelIndex; |
|
} |
|
|
|
bool CWeaponDODBase::ShouldPredict() |
|
{ |
|
if ( GetOwner() && GetOwner() == C_BasePlayer::GetLocalPlayer() ) |
|
return true; |
|
|
|
return BaseClass::ShouldPredict(); |
|
} |
|
|
|
void CWeaponDODBase::ProcessMuzzleFlashEvent() |
|
{ |
|
CDODPlayer *pPlayer = GetDODPlayerOwner(); |
|
if ( pPlayer ) |
|
pPlayer->ProcessMuzzleFlashEvent(); |
|
|
|
BaseClass::ProcessMuzzleFlashEvent(); |
|
} |
|
#else |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Get the accuracy derived from weapon and player, and return it |
|
//----------------------------------------------------------------------------- |
|
const Vector& CWeaponDODBase::GetBulletSpread() |
|
{ |
|
static Vector cone = VECTOR_CONE_8DEGREES; |
|
return cone; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CWeaponDODBase::ItemBusyFrame() |
|
{ |
|
if( ShouldAutoReload() && !m_bInReload ) |
|
{ |
|
// weapon is useable. Reload if empty and weapon has waited as long as it has to after firing |
|
if ( m_iClip1 == 0 && !(GetWeaponFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < gpGlobals->curtime ) |
|
{ |
|
Reload(); |
|
} |
|
} |
|
|
|
BaseClass::ItemBusyFrame(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Match the anim speed to the weapon speed while crouching |
|
//----------------------------------------------------------------------------- |
|
float CWeaponDODBase::GetDefaultAnimSpeed() |
|
{ |
|
return 1.0; |
|
} |
|
|
|
bool CWeaponDODBase::ShouldRemoveOnRoundRestart() |
|
{ |
|
if ( GetPlayerOwner() ) |
|
return false; |
|
else |
|
return true; |
|
} |
|
|
|
|
|
//========================================================= |
|
// Materialize - make a CWeaponDODBase visible and tangible |
|
//========================================================= |
|
void CWeaponDODBase::Materialize() |
|
{ |
|
if ( IsEffectActive( EF_NODRAW ) ) |
|
{ |
|
RemoveEffects( EF_NODRAW ); |
|
DoMuzzleFlash(); |
|
} |
|
|
|
AddSolidFlags( FSOLID_TRIGGER ); |
|
|
|
SetThink (&CWeaponDODBase::SUB_Remove); |
|
SetNextThink( gpGlobals->curtime + 1 ); |
|
} |
|
|
|
//========================================================= |
|
// AttemptToMaterialize - the item is trying to rematerialize, |
|
// should it do so now or wait longer? |
|
//========================================================= |
|
void CWeaponDODBase::AttemptToMaterialize() |
|
{ |
|
float time = g_pGameRules->FlWeaponTryRespawn( this ); |
|
|
|
if ( time == 0 ) |
|
{ |
|
Materialize(); |
|
return; |
|
} |
|
|
|
SetNextThink( gpGlobals->curtime + time ); |
|
} |
|
|
|
//========================================================= |
|
// CheckRespawn - a player is taking this weapon, should |
|
// it respawn? |
|
//========================================================= |
|
void CWeaponDODBase::CheckRespawn() |
|
{ |
|
//GOOSEMAN : Do not respawn weapons! |
|
return; |
|
} |
|
|
|
|
|
//========================================================= |
|
// Respawn- this item is already in the world, but it is |
|
// invisible and intangible. Make it visible and tangible. |
|
//========================================================= |
|
CBaseEntity* CWeaponDODBase::Respawn() |
|
{ |
|
// make a copy of this weapon that is invisible and inaccessible to players (no touch function). The weapon spawn/respawn code |
|
// will decide when to make the weapon visible and touchable. |
|
CBaseEntity *pNewWeapon = CBaseEntity::Create( GetClassname(), g_pGameRules->VecWeaponRespawnSpot( this ), GetAbsAngles(), GetOwner() ); |
|
|
|
if ( pNewWeapon ) |
|
{ |
|
pNewWeapon->AddEffects( EF_NODRAW );// invisible for now |
|
pNewWeapon->SetTouch( NULL );// no touch |
|
pNewWeapon->SetThink( &CWeaponDODBase::AttemptToMaterialize ); |
|
|
|
UTIL_DropToFloor( this, MASK_SOLID ); |
|
|
|
// not a typo! We want to know when the weapon the player just picked up should respawn! This new entity we created is the replacement, |
|
// but when it should respawn is based on conditions belonging to the weapon that was taken. |
|
pNewWeapon->SetNextThink( gpGlobals->curtime + g_pGameRules->FlWeaponRespawnTime( this ) ); |
|
} |
|
else |
|
{ |
|
Msg( "Respawn failed to create %s!\n", GetClassname() ); |
|
} |
|
|
|
return pNewWeapon; |
|
} |
|
|
|
bool CWeaponDODBase::Reload() |
|
{ |
|
return BaseClass::Reload(); |
|
} |
|
|
|
void CWeaponDODBase::Spawn() |
|
{ |
|
BaseClass::Spawn(); |
|
|
|
// Set this here to allow players to shoot dropped weapons |
|
SetCollisionGroup( COLLISION_GROUP_WEAPON ); |
|
|
|
SetExtraAmmoCount(0); //Start with no additional ammo |
|
|
|
CollisionProp()->UseTriggerBounds( true, 10.0f ); |
|
} |
|
|
|
void CWeaponDODBase::SetDieThink( bool bDie ) |
|
{ |
|
if( bDie ) |
|
SetContextThink( &CWeaponDODBase::Die, gpGlobals->curtime + 45.0f, "DieContext" ); |
|
else |
|
SetContextThink( NULL, gpGlobals->curtime, "DieContext" ); |
|
} |
|
|
|
void CWeaponDODBase::Die( void ) |
|
{ |
|
UTIL_Remove( this ); |
|
} |
|
|
|
#endif |
|
|
|
void CWeaponDODBase::OnPickedUp( CBaseCombatCharacter *pNewOwner ) |
|
{ |
|
BaseClass::OnPickedUp( pNewOwner ); |
|
|
|
#if !defined( CLIENT_DLL ) |
|
SetDieThink( false ); |
|
#endif |
|
} |
|
|
|
bool CWeaponDODBase::DefaultReload( int iClipSize1, int iClipSize2, int iActivity ) |
|
{ |
|
CBaseCombatCharacter *pOwner = GetOwner(); |
|
if (!pOwner) |
|
return false; |
|
|
|
// If I don't have any spare ammo, I can't reload |
|
if ( pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0 ) |
|
return false; |
|
|
|
bool bReload = false; |
|
|
|
// If you don't have clips, then don't try to reload them. |
|
if ( UsesClipsForAmmo1() ) |
|
{ |
|
// need to reload primary clip? |
|
int primary = min(iClipSize1 - m_iClip1, pOwner->GetAmmoCount(m_iPrimaryAmmoType)); |
|
if ( primary != 0 ) |
|
{ |
|
bReload = true; |
|
} |
|
} |
|
|
|
if ( UsesClipsForAmmo2() ) |
|
{ |
|
// need to reload secondary clip? |
|
int secondary = min(iClipSize2 - m_iClip2, pOwner->GetAmmoCount(m_iSecondaryAmmoType)); |
|
if ( secondary != 0 ) |
|
{ |
|
bReload = true; |
|
} |
|
} |
|
|
|
if ( !bReload ) |
|
return false; |
|
|
|
CDODPlayer *pPlayer = GetDODPlayerOwner(); |
|
if ( pPlayer ) |
|
{ |
|
#ifdef CLIENT_DLL |
|
PlayWorldReloadSound( pPlayer ); |
|
#else |
|
pPlayer->DoAnimationEvent( PLAYERANIMEVENT_RELOAD ); |
|
#endif |
|
} |
|
|
|
SendWeaponAnim( iActivity ); |
|
|
|
// Play the player's reload animation |
|
if ( pOwner->IsPlayer() ) |
|
{ |
|
( ( CBasePlayer * )pOwner)->SetAnimation( PLAYER_RELOAD ); |
|
} |
|
|
|
float flSequenceEndTime = gpGlobals->curtime + SequenceDuration(); |
|
pOwner->SetNextAttack( flSequenceEndTime ); |
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = flSequenceEndTime; |
|
|
|
m_bInReload = true; |
|
|
|
return true; |
|
} |
|
|
|
#ifdef CLIENT_DLL |
|
void CWeaponDODBase::PlayWorldReloadSound( CDODPlayer *pPlayer ) |
|
{ |
|
Assert( pPlayer ); |
|
|
|
const char *shootsound = GetShootSound( RELOAD ); |
|
if ( !shootsound || !shootsound[0] ) |
|
return; |
|
|
|
CSoundParameters params; |
|
|
|
if ( !GetParametersForSound( shootsound, params, NULL ) ) |
|
return; |
|
|
|
// Play weapon sound from the owner |
|
CPASAttenuationFilter filter( pPlayer, params.soundlevel ); |
|
filter.RemoveRecipient( pPlayer ); // no local player, that is done in the model |
|
|
|
EmitSound( filter, pPlayer->entindex(), shootsound, NULL, 0.0 ); |
|
} |
|
#endif |
|
|
|
bool CWeaponDODBase::IsUseable() |
|
{ |
|
CBasePlayer *pPlayer = GetPlayerOwner(); |
|
|
|
if ( Clip1() <= 0 ) |
|
{ |
|
if ( pPlayer->GetAmmoCount( GetPrimaryAmmoType() ) <= 0 && GetMaxClip1() != -1 ) |
|
{ |
|
// clip is empty (or nonexistant) and the player has no more ammo of this type. |
|
return false; |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
#ifndef CLIENT_DLL |
|
ConVar dod_meleeattackforcescale( "dod_meleeattackforcescale", "8.0", FCVAR_CHEAT | FCVAR_GAMEDLL ); |
|
#endif |
|
|
|
void CWeaponDODBase::RifleButt( void ) |
|
{ |
|
//MeleeAttack( 60, MELEE_DMG_BUTTSTOCK | MELEE_DMG_SECONDARYATTACK, 0.2f, 0.9f ); |
|
} |
|
|
|
void CWeaponDODBase::Bayonet( void ) |
|
{ |
|
//MeleeAttack( 60, MELEE_DMG_BAYONET | MELEE_DMG_SECONDARYATTACK, 0.2f, 0.9f ); |
|
} |
|
|
|
void CWeaponDODBase::Punch( void ) |
|
{ |
|
MeleeAttack( 60, MELEE_DMG_FIST | MELEE_DMG_SECONDARYATTACK, 0.2f, 0.4f ); |
|
} |
|
|
|
//-------------------------------------------- |
|
// iDamageAmount - how much damage to give |
|
// iDamageType - DMG_ bits |
|
// flDmgDelay - delay between attack and the giving of damage, usually timed to animation |
|
// flAttackDelay - time until we can next attack |
|
//-------------------------------------------- |
|
CBaseEntity *CWeaponDODBase::MeleeAttack( int iDamageAmount, int iDamageType, float flDmgDelay, float flAttackDelay ) |
|
{ |
|
if ( !CanAttack() ) |
|
return NULL; |
|
|
|
CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() ); |
|
|
|
#if !defined (CLIENT_DLL) |
|
// Move other players back to history positions based on local player's lag |
|
lagcompensation->StartLagCompensation( pPlayer, pPlayer->GetCurrentCommand() ); |
|
#endif |
|
|
|
Vector vForward, vRight, vUp; |
|
AngleVectors( pPlayer->EyeAngles(), &vForward, &vRight, &vUp ); |
|
Vector vecSrc = pPlayer->Weapon_ShootPosition(); |
|
Vector vecEnd = vecSrc + vForward * 48; |
|
|
|
CTraceFilterSimple filter( pPlayer, COLLISION_GROUP_NONE ); |
|
|
|
int iTraceMask = MASK_SOLID | CONTENTS_HITBOX | CONTENTS_DEBRIS; |
|
|
|
trace_t tr; |
|
UTIL_TraceLine( vecSrc, vecEnd, iTraceMask, &filter, &tr ); |
|
|
|
const float rayExtension = 40.0f; |
|
UTIL_ClipTraceToPlayers( vecSrc, vecEnd + vForward * rayExtension, iTraceMask, &filter, &tr ); |
|
|
|
// If the exact forward trace did not hit, try a larger swept box |
|
if ( tr.fraction >= 1.0 ) |
|
{ |
|
Vector head_hull_mins( -16, -16, -18 ); |
|
Vector head_hull_maxs( 16, 16, 18 ); |
|
|
|
UTIL_TraceHull( vecSrc, vecEnd, head_hull_mins, head_hull_maxs, MASK_SOLID, &filter, &tr ); |
|
if ( tr.fraction < 1.0 ) |
|
{ |
|
// Calculate the point of intersection of the line (or hull) and the object we hit |
|
// This is and approximation of the "best" intersection |
|
CBaseEntity *pHit = tr.m_pEnt; |
|
if ( !pHit || pHit->IsBSPModel() ) |
|
FindHullIntersection( vecSrc, tr, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, pPlayer ); |
|
vecEnd = tr.endpos; // This is the point on the actual surface (the hull could have hit space) |
|
|
|
// Make sure it is in front of us |
|
Vector vecToEnd = vecEnd - vecSrc; |
|
VectorNormalize( vecToEnd ); |
|
|
|
// if zero length, always hit |
|
if ( vecToEnd.Length() > 0 ) |
|
{ |
|
float dot = DotProduct( vForward, vecToEnd ); |
|
|
|
// sanity that our hit is within range |
|
if ( abs(dot) < 0.95 ) |
|
{ |
|
// fake that we actually missed |
|
tr.fraction = 1.0; |
|
} |
|
} |
|
} |
|
} |
|
|
|
WeaponSound( MELEE_MISS ); |
|
|
|
bool bDidHit = ( tr.fraction < 1.0f ); |
|
|
|
if ( bDidHit ) //if the swing hit |
|
{ |
|
// delay the decal a bit |
|
m_trHit = tr; |
|
|
|
// Store the ent in an EHANDLE, just in case it goes away by the time we get into our think function. |
|
m_pTraceHitEnt = tr.m_pEnt; |
|
|
|
m_iSmackDamage = iDamageAmount; |
|
m_iSmackDamageType = iDamageType; |
|
|
|
m_flSmackTime = gpGlobals->curtime + flDmgDelay; |
|
} |
|
|
|
SendWeaponAnim( GetMeleeActivity() ); |
|
|
|
// player animation |
|
pPlayer->DoAnimationEvent( PLAYERANIMEVENT_SECONDARY_ATTACK ); |
|
|
|
m_flNextPrimaryAttack = gpGlobals->curtime + flAttackDelay; |
|
m_flNextSecondaryAttack = gpGlobals->curtime + flAttackDelay; |
|
m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration(); |
|
|
|
#ifndef CLIENT_DLL |
|
IGameEvent * event = gameeventmanager->CreateEvent( "dod_stats_weapon_attack" ); |
|
if ( event ) |
|
{ |
|
event->SetInt( "attacker", pPlayer->GetUserID() ); |
|
event->SetInt( "weapon", GetAltWeaponID() ); |
|
|
|
gameeventmanager->FireEvent( event ); |
|
} |
|
|
|
lagcompensation->FinishLagCompensation( pPlayer ); |
|
#endif //CLIENT_DLL |
|
|
|
return tr.m_pEnt; |
|
} |
|
|
|
//Think function to delay the impact decal until the animation is finished playing |
|
void CWeaponDODBase::Smack() |
|
{ |
|
Assert( GetPlayerOwner() ); |
|
|
|
if ( !GetPlayerOwner() ) |
|
return; |
|
|
|
CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() ); |
|
|
|
if ( !pPlayer ) |
|
return; |
|
|
|
// Check that we are still facing the victim |
|
Vector vForward, vRight, vUp; |
|
AngleVectors( pPlayer->EyeAngles(), &vForward, &vRight, &vUp ); |
|
Vector vecSrc = pPlayer->Weapon_ShootPosition(); |
|
Vector vecEnd = vecSrc + vForward * 48; |
|
|
|
CTraceFilterSimple filter( pPlayer, COLLISION_GROUP_NONE ); |
|
|
|
int iTraceMask = MASK_SOLID | CONTENTS_HITBOX | CONTENTS_DEBRIS; |
|
|
|
trace_t tr; |
|
UTIL_TraceLine( vecSrc, vecEnd, iTraceMask, &filter, &tr ); |
|
|
|
const float rayExtension = 40.0f; |
|
UTIL_ClipTraceToPlayers( vecSrc, vecEnd + vForward * rayExtension, iTraceMask, &filter, &tr ); |
|
|
|
if ( tr.fraction >= 1.0 ) |
|
{ |
|
Vector head_hull_mins( -16, -16, -18 ); |
|
Vector head_hull_maxs( 16, 16, 18 ); |
|
|
|
UTIL_TraceHull( vecSrc, vecEnd, head_hull_mins, head_hull_maxs, MASK_SOLID, &filter, &tr ); |
|
if ( tr.fraction < 1.0 ) |
|
{ |
|
// Calculate the point of intersection of the line (or hull) and the object we hit |
|
// This is and approximation of the "best" intersection |
|
CBaseEntity *pHit = tr.m_pEnt; |
|
if ( !pHit || pHit->IsBSPModel() ) |
|
FindHullIntersection( vecSrc, tr, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, pPlayer ); |
|
vecEnd = tr.endpos; // This is the point on the actual surface (the hull could have hit space) |
|
} |
|
} |
|
|
|
m_trHit = tr; |
|
|
|
if ( !m_trHit.m_pEnt || (m_trHit.surface.flags & SURF_SKY) ) |
|
return; |
|
|
|
if ( m_trHit.fraction == 1.0 ) |
|
return; |
|
|
|
CPASAttenuationFilter attenuationFilter( this ); |
|
attenuationFilter.UsePredictionRules(); |
|
|
|
if( m_trHit.m_pEnt->IsPlayer() ) |
|
{ |
|
if ( m_iSmackDamageType & MELEE_DMG_STRONGATTACK ) |
|
WeaponSound( SPECIAL1 ); |
|
else |
|
WeaponSound( MELEE_HIT ); |
|
} |
|
else |
|
WeaponSound( MELEE_HIT_WORLD ); |
|
|
|
int iDamageType = DMG_CLUB | DMG_NEVERGIB; |
|
|
|
#ifndef CLIENT_DLL |
|
//if they hit the bounding box, just assume a chest hit |
|
if( m_trHit.hitgroup == HITGROUP_GENERIC ) |
|
m_trHit.hitgroup = HITGROUP_CHEST; |
|
|
|
float flDamage = (float)m_iSmackDamage; |
|
|
|
CTakeDamageInfo info( pPlayer, pPlayer, flDamage, iDamageType ); |
|
|
|
if ( m_iSmackDamageType & MELEE_DMG_SECONDARYATTACK ) |
|
info.SetDamageCustom( MELEE_DMG_SECONDARYATTACK ); |
|
|
|
float flScale = (1.0f / flDamage) * dod_meleeattackforcescale.GetFloat(); |
|
|
|
Vector vecForceDir = vForward; |
|
|
|
CalculateMeleeDamageForce( &info, vecForceDir, m_trHit.endpos, flScale ); |
|
|
|
Assert( m_trHit.m_pEnt != GetPlayerOwner() ); |
|
|
|
m_trHit.m_pEnt->DispatchTraceAttack( info, vForward, &m_trHit ); |
|
ApplyMultiDamage(); |
|
#endif |
|
|
|
// We've gotten minidumps where this happened. |
|
if ( !GetPlayerOwner() ) |
|
return; |
|
|
|
CEffectData data; |
|
data.m_vOrigin = m_trHit.endpos; |
|
data.m_vStart = m_trHit.startpos; |
|
data.m_nSurfaceProp = m_trHit.surface.surfaceProps; |
|
data.m_nHitBox = m_trHit.hitbox; |
|
#ifdef CLIENT_DLL |
|
data.m_hEntity = m_trHit.m_pEnt->GetRefEHandle(); |
|
#else |
|
data.m_nEntIndex = m_trHit.m_pEnt->entindex(); |
|
#endif |
|
|
|
CPASFilter effectfilter( data.m_vOrigin ); |
|
|
|
#ifndef CLIENT_DLL |
|
effectfilter.RemoveRecipient( GetPlayerOwner() ); |
|
#endif |
|
|
|
data.m_vAngles = GetPlayerOwner()->GetAbsAngles(); |
|
data.m_fFlags = 0x1; //IMPACT_NODECAL; |
|
data.m_nDamageType = iDamageType; |
|
|
|
bool bHitPlayer = m_trHit.m_pEnt && m_trHit.m_pEnt->IsPlayer(); |
|
|
|
// don't do any impacts if we hit a teammate and ff is off |
|
if ( bHitPlayer && |
|
m_trHit.m_pEnt->GetTeamNumber() == GetPlayerOwner()->GetTeamNumber() && |
|
!friendlyfire.GetBool() ) |
|
return; |
|
|
|
if ( bHitPlayer ) |
|
{ |
|
te->DispatchEffect( effectfilter, 0.0, data.m_vOrigin, "Impact", data ); |
|
} |
|
else if ( m_iSmackDamageType & MELEE_DMG_EDGE ) |
|
{ |
|
data.m_nDamageType = DMG_SLASH; |
|
te->DispatchEffect( effectfilter, 0.0, data.m_vOrigin, "KnifeSlash", data ); |
|
} |
|
} |
|
|
|
#if defined( CLIENT_DLL ) |
|
|
|
float g_lateralBob = 0; |
|
float g_verticalBob = 0; |
|
|
|
static ConVar cl_bobcycle( "cl_bobcycle","0.8" ); |
|
static ConVar cl_bob( "cl_bob","0.002" ); |
|
static ConVar cl_bobup( "cl_bobup","0.5" ); |
|
|
|
// Register these cvars if needed for easy tweaking |
|
static ConVar v_iyaw_cycle( "v_iyaw_cycle", "2"/*, FCVAR_UNREGISTERED*/ ); |
|
static ConVar v_iroll_cycle( "v_iroll_cycle", "0.5"/*, FCVAR_UNREGISTERED*/ ); |
|
static ConVar v_ipitch_cycle( "v_ipitch_cycle", "1"/*, FCVAR_UNREGISTERED*/ ); |
|
static ConVar v_iyaw_level( "v_iyaw_level", "0.3"/*, FCVAR_UNREGISTERED*/ ); |
|
static ConVar v_iroll_level( "v_iroll_level", "0.1"/*, FCVAR_UNREGISTERED*/ ); |
|
static ConVar v_ipitch_level( "v_ipitch_level", "0.3"/*, FCVAR_UNREGISTERED*/ ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Output : float |
|
//----------------------------------------------------------------------------- |
|
float CWeaponDODBase::CalcViewmodelBob( void ) |
|
{ |
|
static float bobtime; |
|
static float lastbobtime; |
|
static float lastspeed; |
|
float cycle; |
|
|
|
CBasePlayer *player = ToBasePlayer( GetOwner() ); |
|
//Assert( player ); |
|
|
|
//NOTENOTE: For now, let this cycle continue when in the air, because it snaps badly without it |
|
|
|
if ( ( !gpGlobals->frametime ) || ( player == NULL ) ) |
|
{ |
|
//NOTENOTE: We don't use this return value in our case (need to restructure the calculation function setup!) |
|
return 0.0f;// just use old value |
|
} |
|
|
|
//Find the speed of the player |
|
float speed = player->GetLocalVelocity().Length2D(); |
|
float flmaxSpeedDelta = MAX( 0, (gpGlobals->curtime - lastbobtime) * 320.0f ); |
|
|
|
// don't allow too big speed changes |
|
speed = clamp( speed, lastspeed-flmaxSpeedDelta, lastspeed+flmaxSpeedDelta ); |
|
speed = clamp( speed, -320, 320 ); |
|
|
|
lastspeed = speed; |
|
|
|
//FIXME: This maximum speed value must come from the server. |
|
// MaxSpeed() is not sufficient for dealing with sprinting - jdw |
|
|
|
float bob_offset = RemapVal( speed, 0, 320, 0.0f, 1.0f ); |
|
|
|
bobtime += ( gpGlobals->curtime - lastbobtime ) * bob_offset; |
|
lastbobtime = gpGlobals->curtime; |
|
|
|
//Calculate the vertical bob |
|
cycle = bobtime - (int)(bobtime/cl_bobcycle.GetFloat())*cl_bobcycle.GetFloat(); |
|
cycle /= cl_bobcycle.GetFloat(); |
|
|
|
if ( cycle < cl_bobup.GetFloat() ) |
|
{ |
|
cycle = M_PI * cycle / cl_bobup.GetFloat(); |
|
} |
|
else |
|
{ |
|
cycle = M_PI + M_PI*(cycle-cl_bobup.GetFloat())/(1.0 - cl_bobup.GetFloat()); |
|
} |
|
|
|
g_verticalBob = speed*0.005f; |
|
g_verticalBob = g_verticalBob*0.3 + g_verticalBob*0.7*sin(cycle); |
|
|
|
g_verticalBob = clamp( g_verticalBob, -7.0f, 4.0f ); |
|
|
|
//Calculate the lateral bob |
|
cycle = bobtime - (int)(bobtime/cl_bobcycle.GetFloat()*2)*cl_bobcycle.GetFloat()*2; |
|
cycle /= cl_bobcycle.GetFloat()*2; |
|
|
|
if ( cycle < cl_bobup.GetFloat() ) |
|
{ |
|
cycle = M_PI * cycle / cl_bobup.GetFloat(); |
|
} |
|
else |
|
{ |
|
cycle = M_PI + M_PI*(cycle-cl_bobup.GetFloat())/(1.0 - cl_bobup.GetFloat()); |
|
} |
|
|
|
g_lateralBob = speed*0.005f; |
|
g_lateralBob = g_lateralBob*0.3 + g_lateralBob*0.7*sin(cycle); |
|
g_lateralBob = clamp( g_lateralBob, -7.0f, 4.0f ); |
|
|
|
//NOTENOTE: We don't use this return value in our case (need to restructure the calculation function setup!) |
|
return 0.0f; |
|
|
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : &origin - |
|
// &angles - |
|
// viewmodelindex - |
|
//----------------------------------------------------------------------------- |
|
void CWeaponDODBase::AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles ) |
|
{ |
|
Vector forward, right; |
|
AngleVectors( angles, &forward, &right, NULL ); |
|
|
|
CalcViewmodelBob(); |
|
|
|
// Apply bob, but scaled down to 40% |
|
VectorMA( origin, g_verticalBob * 0.4f, forward, origin ); |
|
|
|
// Z bob a bit more |
|
origin[2] += g_verticalBob * 0.1f; |
|
|
|
// bob the angles |
|
angles[ ROLL ] += g_verticalBob * 0.5f; |
|
angles[ PITCH ] -= g_verticalBob * 0.4f; |
|
|
|
angles[ YAW ] -= g_lateralBob * 0.3f; |
|
|
|
// VectorMA( origin, g_lateralBob * 0.2f, right, origin ); |
|
} |
|
|
|
#include "c_te_effect_dispatch.h" |
|
|
|
#define NUM_MUZZLE_FLASH_TYPES 4 |
|
|
|
bool CWeaponDODBase::OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options ) |
|
{ |
|
if( event == 5001 ) |
|
{ |
|
if ( ShouldDrawMuzzleFlash() ) |
|
{ |
|
Assert( GetOwnerEntity() == C_BasePlayer::GetLocalPlayer() ); |
|
|
|
const char *pszMuzzleFlashEffect; |
|
|
|
switch( GetDODWpnData().m_iMuzzleFlashType ) |
|
{ |
|
case DOD_MUZZLEFLASH_PISTOL: |
|
pszMuzzleFlashEffect = "view_muzzle_pistols"; |
|
break; |
|
case DOD_MUZZLEFLASH_AUTO: |
|
pszMuzzleFlashEffect = "view_muzzle_fullyautomatic"; |
|
break; |
|
case DOD_MUZZLEFLASH_RIFLE: |
|
pszMuzzleFlashEffect = "view_muzzle_rifles"; |
|
break; |
|
case DOD_MUZZLEFLASH_MG: |
|
pszMuzzleFlashEffect = "view_muzzle_miniguns"; |
|
break; |
|
case DOD_MUZZLEFLASH_ROCKET: |
|
pszMuzzleFlashEffect = "view_muzzle_rockets"; |
|
break; |
|
case DOD_MUZZLEFLASH_MG42: |
|
pszMuzzleFlashEffect = "view_muzzle_mg42"; |
|
break; |
|
default: |
|
pszMuzzleFlashEffect = NULL; |
|
break; |
|
} |
|
|
|
if ( pszMuzzleFlashEffect ) |
|
{ |
|
pViewModel->ParticleProp()->Create( pszMuzzleFlashEffect, PATTACH_POINT_FOLLOW, 1 ); |
|
} |
|
} |
|
return true; |
|
} |
|
else if( event == 6002 ) |
|
{ |
|
CEffectData data; |
|
data.m_nHitBox = atoi( options ); |
|
data.m_hEntity = GetPlayerOwner() ? GetPlayerOwner()->GetRefEHandle() : INVALID_EHANDLE_INDEX; |
|
pViewModel->GetAttachment( 2, data.m_vOrigin, data.m_vAngles ); |
|
|
|
DispatchEffect( "DOD_EjectBrass", data ); |
|
return true; |
|
} |
|
|
|
return BaseClass::OnFireEvent( pViewModel, origin, angles, event, options ); |
|
} |
|
|
|
bool CWeaponDODBase::ShouldAutoEjectBrass( void ) |
|
{ |
|
// Don't eject brass if further than N units from the local player |
|
C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); |
|
if ( !pLocalPlayer ) |
|
return true; |
|
|
|
float flMaxDistSqr = 250; |
|
flMaxDistSqr *= flMaxDistSqr; |
|
|
|
float flDistSqr = pLocalPlayer->EyePosition().DistToSqr( GetAbsOrigin() ); |
|
return ( flDistSqr < flMaxDistSqr ); |
|
} |
|
|
|
bool CWeaponDODBase::GetEjectBrassShellType( void ) |
|
{ |
|
return 1; |
|
} |
|
|
|
void CWeaponDODBase::SetUseAltModel( bool bUseAltModel ) |
|
{ |
|
m_bUseAltWeaponModel = bUseAltModel; |
|
} |
|
|
|
void CWeaponDODBase::CheckForAltWeapon( int iCurrentState ) |
|
{ |
|
int iCriteria = GetDODWpnData().m_iAltWpnCriteria; |
|
|
|
bool bUseAltModel = false; |
|
|
|
if( ( iCriteria & iCurrentState ) != 0 ) |
|
bUseAltModel = true; |
|
|
|
SetUseAltModel( bUseAltModel ); |
|
} |
|
|
|
Vector CWeaponDODBase::GetDesiredViewModelOffset( C_DODPlayer *pOwner ) |
|
{ |
|
Vector viewOffset = pOwner->GetViewOffset(); |
|
|
|
float flPercent = ( viewOffset.z - VEC_PRONE_VIEW_SCALED( pOwner ).z ) / ( VEC_VIEW_SCALED( pOwner ).z - VEC_PRONE_VIEW_SCALED( pOwner ).z ); |
|
|
|
return ( flPercent * GetDODWpnData().m_vecViewNormalOffset + |
|
( 1.0 - flPercent ) * GetDODWpnData().m_vecViewProneOffset ); |
|
} |
|
|
|
bool CWeaponDODBase::ShouldDraw( void ) |
|
{ |
|
if ( GetModel() == NULL ) |
|
{ |
|
// XXX(johns): Removed, doesn't seem to be the proper spot for this warning given that weapons can call |
|
// ShouldDraw before their properties are filled. |
|
|
|
// C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer(); |
|
|
|
// Warning( "BADNESS! Tell Matt that the weapon '%s' tried to draw with a null model ( %d, %d, %s ) \n", |
|
// GetDODWpnData().szClassName, |
|
// m_iWorldModelIndex.Get(), m_iReloadModelIndex.Get(), m_bUseAltWeaponModel ? "alt" : "not alt" ); |
|
|
|
return false; |
|
} |
|
|
|
return BaseClass::ShouldDraw(); |
|
} |
|
|
|
#else |
|
|
|
void CWeaponDODBase::AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles ) |
|
{ |
|
|
|
} |
|
|
|
float CWeaponDODBase::CalcViewmodelBob( void ) |
|
{ |
|
return 0.0f; |
|
} |
|
|
|
void CWeaponDODBase::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) |
|
{ |
|
if ( CanDrop() == false ) |
|
return; |
|
|
|
CDODPlayer *pPlayer = ToDODPlayer( pActivator ); |
|
|
|
if ( pPlayer ) |
|
{ |
|
pPlayer->PickUpWeapon( this ); |
|
} |
|
} |
|
|
|
#endif |
|
|
|
|