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.
357 lines
8.4 KiB
357 lines
8.4 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#include "cbase.h" |
|
#include "in_buttons.h" |
|
#include "takedamageinfo.h" |
|
#include "ammodef.h" |
|
#include "hl2mp_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_hl2mp_player.h" |
|
#include "hud_crosshair.h" |
|
|
|
#else |
|
|
|
#include "hl2mp_player.h" |
|
#include "vphysics/constraints.h" |
|
|
|
#endif |
|
|
|
#include "weapon_hl2mpbase.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 |
|
}; |
|
|
|
|
|
// ----------------------------------------------------------------------------- // |
|
// CWeaponHL2MPBase tables. |
|
// ----------------------------------------------------------------------------- // |
|
|
|
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponHL2MPBase, DT_WeaponHL2MPBase ) |
|
|
|
BEGIN_NETWORK_TABLE( CWeaponHL2MPBase, DT_WeaponHL2MPBase ) |
|
|
|
#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( CWeaponHL2MPBase ) |
|
END_PREDICTION_DATA() |
|
|
|
LINK_ENTITY_TO_CLASS( weapon_hl2mp_base, CWeaponHL2MPBase ); |
|
|
|
|
|
#ifdef GAME_DLL |
|
|
|
BEGIN_DATADESC( CWeaponHL2MPBase ) |
|
|
|
END_DATADESC() |
|
|
|
#endif |
|
|
|
// ----------------------------------------------------------------------------- // |
|
// CWeaponHL2MPBase implementation. |
|
// ----------------------------------------------------------------------------- // |
|
CWeaponHL2MPBase::CWeaponHL2MPBase() |
|
{ |
|
SetPredictionEligible( true ); |
|
AddSolidFlags( FSOLID_TRIGGER ); // Nothing collides with these but it gets touches. |
|
|
|
m_flNextResetCheckTime = 0.0f; |
|
} |
|
|
|
|
|
bool CWeaponHL2MPBase::IsPredicted() const |
|
{ |
|
return true; |
|
} |
|
|
|
void CWeaponHL2MPBase::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* CWeaponHL2MPBase::GetPlayerOwner() const |
|
{ |
|
return dynamic_cast< CBasePlayer* >( GetOwner() ); |
|
} |
|
|
|
CHL2MP_Player* CWeaponHL2MPBase::GetHL2MPPlayerOwner() const |
|
{ |
|
return dynamic_cast< CHL2MP_Player* >( GetOwner() ); |
|
} |
|
|
|
#ifdef CLIENT_DLL |
|
|
|
void CWeaponHL2MPBase::OnDataChanged( DataUpdateType_t type ) |
|
{ |
|
BaseClass::OnDataChanged( type ); |
|
|
|
if ( GetPredictable() && !ShouldPredict() ) |
|
ShutdownPredictable(); |
|
} |
|
|
|
|
|
bool CWeaponHL2MPBase::ShouldPredict() |
|
{ |
|
if ( GetOwner() && GetOwner() == C_BasePlayer::GetLocalPlayer() ) |
|
return true; |
|
|
|
return BaseClass::ShouldPredict(); |
|
} |
|
|
|
|
|
#else |
|
|
|
void CWeaponHL2MPBase::Spawn() |
|
{ |
|
BaseClass::Spawn(); |
|
|
|
// Set this here to allow players to shoot dropped weapons |
|
SetCollisionGroup( COLLISION_GROUP_WEAPON ); |
|
} |
|
|
|
void CWeaponHL2MPBase::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 ); |
|
|
|
HL2MPRules()->AddLevelDesignerPlacedObject( this ); |
|
} |
|
|
|
if ( HasSpawnFlags( SF_NORESPAWN ) == false ) |
|
{ |
|
if ( GetOriginalSpawnOrigin() == vec3_origin ) |
|
{ |
|
m_vOriginalSpawnOrigin = GetAbsOrigin(); |
|
m_vOriginalSpawnAngles = GetAbsAngles(); |
|
} |
|
} |
|
|
|
SetPickupTouch(); |
|
|
|
SetThink (NULL); |
|
} |
|
|
|
int CWeaponHL2MPBase::ObjectCaps() |
|
{ |
|
return BaseClass::ObjectCaps() & ~FCAP_IMPULSE_USE; |
|
} |
|
|
|
#endif |
|
|
|
void CWeaponHL2MPBase::FallInit( void ) |
|
{ |
|
#ifndef CLIENT_DLL |
|
SetModel( GetWorldModel() ); |
|
VPhysicsDestroyObject(); |
|
|
|
if ( HasSpawnFlags( SF_NORESPAWN ) == false ) |
|
{ |
|
SetMoveType( MOVETYPE_NONE ); |
|
SetSolid( SOLID_BBOX ); |
|
AddSolidFlags( FSOLID_TRIGGER ); |
|
|
|
UTIL_DropToFloor( this, MASK_SOLID ); |
|
} |
|
else |
|
{ |
|
if ( !VPhysicsInitNormal( SOLID_BBOX, GetSolidFlags() | FSOLID_TRIGGER, false ) ) |
|
{ |
|
SetMoveType( MOVETYPE_NONE ); |
|
SetSolid( SOLID_BBOX ); |
|
AddSolidFlags( FSOLID_TRIGGER ); |
|
} |
|
else |
|
{ |
|
#if !defined( CLIENT_DLL ) |
|
// Constrained start? |
|
if ( HasSpawnFlags( SF_WEAPON_START_CONSTRAINED ) ) |
|
{ |
|
//Constrain the weapon in place |
|
IPhysicsObject *pReferenceObject, *pAttachedObject; |
|
|
|
pReferenceObject = g_PhysWorldObject; |
|
pAttachedObject = VPhysicsGetObject(); |
|
|
|
if ( pReferenceObject && pAttachedObject ) |
|
{ |
|
constraint_fixedparams_t fixed; |
|
fixed.Defaults(); |
|
fixed.InitWithCurrentObjectState( pReferenceObject, pAttachedObject ); |
|
|
|
fixed.constraint.forceLimit = lbs2kg( 10000 ); |
|
fixed.constraint.torqueLimit = lbs2kg( 10000 ); |
|
|
|
IPhysicsConstraint *pConstraint = GetConstraint(); |
|
|
|
pConstraint = physenv->CreateFixedConstraint( pReferenceObject, pAttachedObject, NULL, fixed ); |
|
|
|
pConstraint->SetGameData( (void *) this ); |
|
} |
|
} |
|
#endif //CLIENT_DLL |
|
} |
|
} |
|
|
|
SetPickupTouch(); |
|
|
|
SetThink( &CWeaponHL2MPBase::FallThink ); |
|
|
|
SetNextThink( gpGlobals->curtime + 0.1f ); |
|
|
|
#endif |
|
} |
|
|
|
#ifdef GAME_DLL |
|
void CWeaponHL2MPBase::FallThink( void ) |
|
{ |
|
// Prevent the common HL2DM weapon respawn bug from happening |
|
// When a weapon is spawned, the following chain of events occurs: |
|
// - Spawn() is called (duh), which then calls FallInit() |
|
// - FallInit() is called, and prepares the weapon's 'Think' function (CBaseCombatWeapon::FallThink()) |
|
// - FallThink() is called, and performs several checks before deciding whether the weapon should Materialize() |
|
// - Materialize() is called (the HL2DM version above), which sets the weapon's respawn location. |
|
// The problem occurs when a weapon isn't placed properly by a level designer. |
|
// If the weapon is unable to move from its location (e.g. if its bounding box is halfway inside a wall), Materialize() never gets called. |
|
// Since Materialize() never gets called, the weapon's respawn location is never set, so if a person picks it up, it respawns forever at |
|
// 0 0 0 on the map (infinite loop of fall, wait, respawn, not nice at all for performance and bandwidth!) |
|
|
|
if( HasSpawnFlags( SF_NORESPAWN ) == false ) |
|
{ |
|
if( GetOriginalSpawnOrigin() == vec3_origin ) |
|
{ |
|
m_vOriginalSpawnOrigin = GetAbsOrigin(); |
|
m_vOriginalSpawnAngles = GetAbsAngles(); |
|
} |
|
} |
|
|
|
return BaseClass::FallThink(); |
|
} |
|
#endif |
|
|
|
const CHL2MPSWeaponInfo &CWeaponHL2MPBase::GetHL2MPWpnData() const |
|
{ |
|
const FileWeaponInfo_t *pWeaponInfo = &GetWpnData(); |
|
const CHL2MPSWeaponInfo *pHL2MPInfo; |
|
|
|
#ifdef _DEBUG |
|
pHL2MPInfo = dynamic_cast< const CHL2MPSWeaponInfo* >( pWeaponInfo ); |
|
Assert( pHL2MPInfo ); |
|
#else |
|
pHL2MPInfo = static_cast< const CHL2MPSWeaponInfo* >( pWeaponInfo ); |
|
#endif |
|
|
|
return *pHL2MPInfo; |
|
} |
|
void CWeaponHL2MPBase::FireBullets( const FireBulletsInfo_t &info ) |
|
{ |
|
FireBulletsInfo_t modinfo = info; |
|
|
|
modinfo.m_iPlayerDamage = GetHL2MPWpnData().m_iPlayerDamage; |
|
|
|
BaseClass::FireBullets( modinfo ); |
|
} |
|
|
|
|
|
#if defined( CLIENT_DLL ) |
|
|
|
#include "c_te_effect_dispatch.h" |
|
|
|
#define NUM_MUZZLE_FLASH_TYPES 4 |
|
|
|
bool CWeaponHL2MPBase::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 |
|
|
|
|