summaryrefslogtreecommitdiff
path: root/game/shared/hl1/hl1mp_weapon_crossbow.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/shared/hl1/hl1mp_weapon_crossbow.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/shared/hl1/hl1mp_weapon_crossbow.cpp')
-rw-r--r--game/shared/hl1/hl1mp_weapon_crossbow.cpp648
1 files changed, 648 insertions, 0 deletions
diff --git a/game/shared/hl1/hl1mp_weapon_crossbow.cpp b/game/shared/hl1/hl1mp_weapon_crossbow.cpp
new file mode 100644
index 0000000..7118ac1
--- /dev/null
+++ b/game/shared/hl1/hl1mp_weapon_crossbow.cpp
@@ -0,0 +1,648 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Crossbow
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "npcevent.h"
+#include "hl1mp_basecombatweapon_shared.h"
+//#include "basecombatcharacter.h"
+//#include "AI_BaseNPC.h"
+#ifdef CLIENT_DLL
+#include "c_baseplayer.h"
+#else
+#include "player.h"
+#endif
+//#include "player.h"
+#include "gamerules.h"
+#include "in_buttons.h"
+#ifdef CLIENT_DLL
+#else
+#include "soundent.h"
+#include "entitylist.h"
+#include "game.h"
+#endif
+#include "vstdlib/random.h"
+#include "engine/IEngineSound.h"
+#include "IEffects.h"
+#ifdef CLIENT_DLL
+#include "c_te_effect_dispatch.h"
+#else
+#include "te_effect_dispatch.h"
+#endif
+
+#define BOLT_MODEL "models/crossbow_bolt.mdl"
+
+#define BOLT_AIR_VELOCITY 2000
+#define BOLT_WATER_VELOCITY 1000
+
+extern ConVar sk_plr_dmg_xbow_bolt_plr;
+extern ConVar sk_plr_dmg_xbow_bolt_npc;
+
+extern short g_sModelIndexFireball; // (in combatweapon.cpp) holds the index for the fireball
+
+#if !defined(CLIENT_DLL)
+
+//-----------------------------------------------------------------------------
+// Crossbow Bolt
+//-----------------------------------------------------------------------------
+class CCrossbowBolt : public CBaseCombatCharacter
+{
+ DECLARE_CLASS( CCrossbowBolt, CBaseCombatCharacter );
+
+public:
+ CCrossbowBolt()
+ {
+ m_bExplode = true;
+ }
+
+ Class_T Classify( void ) { return CLASS_NONE; }
+
+public:
+ void Spawn( void );
+ void Precache( void );
+ void BubbleThink( void );
+ void BoltTouch( CBaseEntity *pOther );
+ void ExplodeThink( void );
+ void SetExplode( bool bVal ) { m_bExplode = bVal; }
+ bool CreateVPhysics( void );
+ unsigned int PhysicsSolidMaskForEntity() const;
+
+ static CCrossbowBolt *BoltCreate( const Vector &vecOrigin, const QAngle &angAngles, CBasePlayer *pentOwner = NULL );
+
+ DECLARE_DATADESC();
+
+private:
+ bool m_bExplode;
+};
+LINK_ENTITY_TO_CLASS( crossbow_bolt, CCrossbowBolt );
+
+BEGIN_DATADESC( CCrossbowBolt )
+ // Function Pointers
+ DEFINE_FUNCTION( BubbleThink ),
+ DEFINE_FUNCTION( BoltTouch ),
+ DEFINE_FUNCTION( ExplodeThink ),
+END_DATADESC()
+
+CCrossbowBolt *CCrossbowBolt::BoltCreate( const Vector &vecOrigin, const QAngle &angAngles, CBasePlayer *pentOwner )
+{
+ // Create a new entity with CCrossbowBolt private data
+ CCrossbowBolt *pBolt = (CCrossbowBolt *)CreateEntityByName( "crossbow_bolt" );
+ UTIL_SetOrigin( pBolt, vecOrigin );
+ pBolt->SetAbsAngles( angAngles );
+ pBolt->Spawn();
+ pBolt->SetOwnerEntity( pentOwner );
+
+ return pBolt;
+}
+
+void CCrossbowBolt::Spawn( )
+{
+ Precache( );
+
+ SetModel( BOLT_MODEL );
+ UTIL_SetSize( this, -Vector(1, 1, 1), Vector(1, 1, 1) );
+
+ SetSolid( SOLID_BBOX );
+ SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
+ SetGravity( UTIL_ScaleForGravity( 40 ) ); // use a really low gravity (40 in/s^2)
+
+ SetTouch( &CCrossbowBolt::BoltTouch );
+
+ SetThink( &CCrossbowBolt::BubbleThink );
+ SetNextThink( gpGlobals->curtime + 0.2 );
+
+ m_bExplode = true;
+}
+
+
+void CCrossbowBolt::Precache( )
+{
+ PrecacheModel( BOLT_MODEL );
+ PrecacheScriptSound( "BaseGrenade.Explode" );
+}
+
+void CCrossbowBolt::BoltTouch( CBaseEntity *pOther )
+{
+ if ( !pOther->IsSolid() || pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS) )
+ return;
+
+ SetTouch( NULL );
+ SetThink( NULL );
+
+ if ( pOther->m_takedamage != DAMAGE_NO )
+ {
+ trace_t tr, tr2;
+ tr = BaseClass::GetTouchTrace( );
+ Vector vecNormalizedVel = GetAbsVelocity();
+
+ ClearMultiDamage( );
+ VectorNormalize( vecNormalizedVel );
+
+ if ( pOther->IsPlayer() )
+ {
+ float m_fDamage = sk_plr_dmg_xbow_bolt_plr.GetFloat() * g_pGameRules->GetDamageMultiplier();
+
+ // If multiplayer sniper bolt, multiply damage by 4
+ if ( g_pGameRules->IsMultiplayer() && !m_bExplode )
+ m_fDamage *= 4;
+
+ CTakeDamageInfo dmgInfo( this, GetOwnerEntity(), m_fDamage,DMG_NEVERGIB );
+ CalculateMeleeDamageForce( &dmgInfo, vecNormalizedVel, tr.endpos );
+ pOther->DispatchTraceAttack( dmgInfo, vecNormalizedVel, &tr );
+ }
+ else
+ {
+ CTakeDamageInfo dmgInfo( this, GetOwnerEntity(), sk_plr_dmg_xbow_bolt_npc.GetFloat() * g_pGameRules->GetDamageMultiplier(), DMG_BULLET | DMG_NEVERGIB );
+ CalculateMeleeDamageForce( &dmgInfo, vecNormalizedVel, tr.endpos );
+ pOther->DispatchTraceAttack( dmgInfo, vecNormalizedVel, &tr );
+ }
+
+ ApplyMultiDamage();
+
+ SetAbsVelocity( Vector( 0, 0, 0 ) );
+
+ // play body "thwack" sound
+ EmitSound( "Weapon_Crossbow.BoltHitBody" );
+
+ Vector vForward;
+
+ AngleVectors( GetAbsAngles(), &vForward );
+ VectorNormalize ( vForward );
+
+ UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + vForward * 128, MASK_OPAQUE, pOther, COLLISION_GROUP_NONE, &tr2 );
+
+ if ( tr2.fraction != 1.0f )
+ {
+// NDebugOverlay::Box( tr2.endpos, Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 0, 255, 0, 0, 10 );
+// NDebugOverlay::Box( GetAbsOrigin(), Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 0, 0, 255, 0, 10 );
+
+ CEffectData data;
+
+ data.m_vOrigin = tr2.endpos;
+ data.m_vNormal = vForward;
+ data.m_nEntIndex = tr2.fraction != 1.0f;
+
+ DispatchEffect( "BoltImpact", data );
+ }
+
+ if ( !g_pGameRules->IsMultiplayer() || !m_bExplode )
+ {
+ UTIL_Remove( this );
+ }
+ }
+ else
+ {
+ EmitSound( "Weapon_Crossbow.BoltHitWorld" );
+
+ SetThink( &CCrossbowBolt::SUB_Remove );
+ SetNextThink( gpGlobals->curtime );// this will get changed below if the bolt is allowed to stick in what it hit.
+
+ if ( m_bExplode == false )
+ {
+ Vector vForward;
+ AngleVectors( GetAbsAngles(), &vForward );
+ VectorNormalize ( vForward );
+
+ CEffectData data;
+
+ data.m_vOrigin = GetAbsOrigin();
+ data.m_vNormal = vForward;
+ data.m_nEntIndex = 0;
+
+ DispatchEffect( "BoltImpact", data );
+ }
+
+ if ( UTIL_PointContents( GetAbsOrigin() ) != CONTENTS_WATER)
+ {
+ g_pEffects->Sparks( GetAbsOrigin() );
+ }
+ }
+
+ // Set up an explosion in one tenth of a second
+ if ( g_pGameRules->IsMultiplayer() && m_bExplode )
+ {
+ SetThink( &CCrossbowBolt::ExplodeThink );
+ SetNextThink( gpGlobals->curtime + 0.1f );
+ }
+}
+
+void CCrossbowBolt::ExplodeThink( void )
+{
+ // int iContents = UTIL_PointContents( pev->origin );
+ CTakeDamageInfo dmgInfo( this, GetOwnerEntity(), sk_plr_dmg_xbow_bolt_npc.GetFloat() * g_pGameRules->GetDamageMultiplier(), DMG_BLAST );
+
+ ::RadiusDamage( dmgInfo, GetAbsOrigin(), 128, CLASS_NONE, NULL );
+
+#if !defined( CLIENT_DLL )
+ CPASFilter filter( GetAbsOrigin() );
+
+ te->Explosion( filter, /* filter */
+ 0.0, /* delay */
+ &GetAbsOrigin(), /* pos */
+ g_sModelIndexFireball, /* modelindex */
+ 0.2, /* scale */
+ 25, /* framerate */
+ TE_EXPLFLAG_NONE, /* flags */
+ 128, /* radius */
+ 64, /* magnitude */
+ NULL, /* normal */
+ 'C' ); /* materialType */
+
+ //CSoundEnt::InsertSound ( SOUND_COMBAT, GetAbsOrigin(), BASEGRENADE_EXPLOSION_VOLUME, 3.0 );
+ EmitSound( "BaseGrenade.Explode" );
+#endif
+
+
+ SetThink( &CCrossbowBolt::SUB_Remove );
+ SetNextThink( gpGlobals->curtime );
+
+ AddEffects( EF_NODRAW );
+}
+
+void CCrossbowBolt::BubbleThink( void )
+{
+ QAngle angNewAngles;
+
+ VectorAngles( GetAbsVelocity(), angNewAngles );
+ SetAbsAngles( angNewAngles );
+
+ SetNextThink( gpGlobals->curtime + 0.1f );
+
+ if ( GetWaterLevel() == 0 )
+ return;
+
+ UTIL_BubbleTrail( GetAbsOrigin() - GetAbsVelocity() * 0.1, GetAbsOrigin(), 1 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CCrossbowBolt::CreateVPhysics( void )
+{
+ // Create the object in the physics system
+ VPhysicsInitNormal( SOLID_BBOX, FSOLID_NOT_STANDABLE, false );
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+unsigned int CCrossbowBolt::PhysicsSolidMaskForEntity() const
+{
+ return ( BaseClass::PhysicsSolidMaskForEntity() | CONTENTS_HITBOX ) & ~CONTENTS_GRATE;
+}
+
+
+#endif // crossbowbolt
+
+//-----------------------------------------------------------------------------
+// CWeaponCrossbow
+//-----------------------------------------------------------------------------
+
+#ifdef CLIENT_DLL
+#define CWeaponCrossbow C_WeaponCrossbow
+#endif
+
+class CWeaponCrossbow : public CBaseHL1MPCombatWeapon
+{
+ DECLARE_CLASS( CWeaponCrossbow, CBaseHL1MPCombatWeapon );
+public:
+
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+
+ CWeaponCrossbow( void );
+
+ void Precache( void );
+ void PrimaryAttack( void );
+ void SecondaryAttack( void );
+ bool Reload( void );
+ void WeaponIdle( void );
+ bool Deploy( void );
+ bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL );
+
+// DECLARE_SERVERCLASS();
+ DECLARE_DATADESC();
+
+#ifndef CLIENT_DLL
+// DECLARE_ACTTABLE();
+#endif
+
+private:
+ void FireBolt( void );
+ void ToggleZoom( void );
+
+private:
+// bool m_fInZoom;
+ CNetworkVar( bool, m_fInZoom );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponCrossbow, DT_WeaponCrossbow );
+
+BEGIN_NETWORK_TABLE( CWeaponCrossbow, DT_WeaponCrossbow )
+#ifdef CLIENT_DLL
+ RecvPropBool( RECVINFO( m_fInZoom ) ),
+#else
+ SendPropBool( SENDINFO( m_fInZoom ) ),
+#endif
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponCrossbow )
+#ifdef CLIENT_DLL
+ DEFINE_PRED_FIELD( m_fInZoom, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
+#endif
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_crossbow, CWeaponCrossbow );
+
+PRECACHE_WEAPON_REGISTER( weapon_crossbow );
+
+//IMPLEMENT_SERVERCLASS_ST( CWeaponCrossbow, DT_WeaponCrossbow )
+//END_SEND_TABLE()
+
+BEGIN_DATADESC( CWeaponCrossbow )
+END_DATADESC()
+
+#if 0
+#ifndef CLIENT_DLL
+
+acttable_t CWeaponCrossbow::m_acttable[] =
+{
+ { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_CROSSBOW, false },
+// { ACT_HL2MP_RUN, ACT_HL2MP_RUN_CROSSBOW, false },
+// { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_CROSSBOW, false },
+// { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_CROSSBOW, false },
+// { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_CROSSBOW, false },
+// { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_CROSSBOW, false },
+// { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_CROSSBOW, false },
+};
+
+IMPLEMENT_ACTTABLE(CWeaponCrossbow);
+
+#endif
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CWeaponCrossbow::CWeaponCrossbow( void )
+{
+ m_bReloadsSingly = false;
+ m_bFiresUnderwater = true;
+ m_fInZoom = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWeaponCrossbow::Precache( void )
+{
+#ifndef CLIENT_DLL
+ UTIL_PrecacheOther( "crossbow_bolt" );
+#endif
+
+ PrecacheScriptSound( "Weapon_Crossbow.BoltHitBody" );
+ PrecacheScriptSound( "Weapon_Crossbow.BoltHitWorld" );
+
+ BaseClass::Precache();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWeaponCrossbow::PrimaryAttack( void )
+{
+ if ( m_fInZoom && g_pGameRules->IsMultiplayer() )
+ {
+// FireSniperBolt();
+ FireBolt();
+ }
+ else
+ {
+ FireBolt();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWeaponCrossbow::SecondaryAttack( void )
+{
+ ToggleZoom();
+ m_flNextSecondaryAttack = gpGlobals->curtime + 1.0;
+}
+
+
+void CWeaponCrossbow::FireBolt( void )
+{
+ if ( m_iClip1 <= 0 )
+ {
+ if ( !m_bFireOnEmpty )
+ {
+ Reload();
+ }
+ else
+ {
+ WeaponSound( EMPTY );
+ m_flNextPrimaryAttack = 0.15;
+ }
+
+ return;
+ }
+
+ CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
+
+ if ( pOwner == NULL )
+ return;
+
+ Vector vecAiming = pOwner->GetAutoaimVector( AUTOAIM_2DEGREES );
+ Vector vecSrc = pOwner->Weapon_ShootPosition();
+
+ QAngle angAiming;
+ VectorAngles( vecAiming, angAiming );
+
+#ifndef CLIENT_DLL
+ CCrossbowBolt *pBolt = CCrossbowBolt::BoltCreate( vecSrc, angAiming, pOwner );
+
+ // In multiplayer, secondary fire is instantaneous.
+ if ( g_pGameRules->IsMultiplayer() && m_fInZoom )
+ {
+ Vector vecEnd = vecSrc + ( vecAiming * MAX_TRACE_LENGTH );
+
+ trace_t trace;
+ UTIL_TraceLine( vecSrc, vecEnd, MASK_SHOT, GetOwner(), COLLISION_GROUP_NONE, &trace );
+ pBolt->SetAbsOrigin( trace.endpos );
+
+ // We hit someone
+ if ( trace.m_pEnt && trace.m_pEnt->m_takedamage )
+ {
+ pBolt->SetExplode( false );
+ pBolt->BoltTouch( trace.m_pEnt );
+ return;
+ }
+ }
+ else
+ {
+ if ( pOwner->GetWaterLevel() == 3 )
+ {
+ pBolt->SetAbsVelocity( vecAiming * BOLT_WATER_VELOCITY );
+ }
+ else
+ {
+ pBolt->SetAbsVelocity( vecAiming * BOLT_AIR_VELOCITY );
+ }
+ }
+
+ pBolt->SetLocalAngularVelocity( QAngle( 0, 0, 10 ) );
+
+ if ( m_fInZoom || !g_pGameRules->IsMultiplayer() )
+ {
+ pBolt->SetExplode( false );
+
+ }
+#endif
+
+ m_iClip1--;
+
+ pOwner->ViewPunch( QAngle( -2, 0, 0 ) );
+
+ WeaponSound( SINGLE );
+ WeaponSound( RELOAD );
+
+#ifdef CLIENT_DLL
+#else
+ CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 200, 0.2 );
+#endif
+
+ if ( m_iClip1 > 0 )
+ {
+ SendWeaponAnim( ACT_VM_PRIMARYATTACK );
+ }
+ else if ( pOwner->GetAmmoCount(m_iPrimaryAmmoType) > 0 )
+ {
+ SendWeaponAnim( ACT_VM_SECONDARYATTACK );
+ }
+
+ if ( !m_iClip1 && pOwner->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 )
+ {
+ // HEV suit - indicate out of ammo condition
+ pOwner->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
+ }
+
+ m_flNextPrimaryAttack = gpGlobals->curtime + 0.75;
+ m_flNextSecondaryAttack = gpGlobals->curtime + 0.75;
+
+ if ( m_iClip1 > 0 )
+ {
+ SetWeaponIdleTime( gpGlobals->curtime + 5.0 );
+ }
+ else
+ {
+ SetWeaponIdleTime( gpGlobals->curtime + 0.75 );
+ }
+}
+
+
+bool CWeaponCrossbow::Reload( void )
+{
+ bool fRet;
+
+ fRet = DefaultReload( GetMaxClip1(), GetMaxClip2(), ACT_VM_RELOAD );
+ if ( fRet )
+ {
+ if ( m_fInZoom )
+ {
+ ToggleZoom();
+ }
+
+ WeaponSound( RELOAD );
+ }
+
+ return fRet;
+}
+
+
+void CWeaponCrossbow::WeaponIdle( void )
+{
+ CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
+ if ( pPlayer )
+ {
+ pPlayer->GetAutoaimVector( AUTOAIM_2DEGREES );
+ }
+
+ if ( !HasWeaponIdleTimeElapsed() )
+ return;
+
+ int iAnim;
+ float flRand = random->RandomFloat( 0, 1 );
+ if ( flRand <= 0.75 )
+ {
+ if ( m_iClip1 <= 0 )
+ iAnim = ACT_CROSSBOW_IDLE_UNLOADED;
+ else
+ iAnim = ACT_VM_IDLE;
+ }
+ else
+ {
+ if ( m_iClip1 <= 0 )
+ iAnim = ACT_CROSSBOW_FIDGET_UNLOADED;
+ else
+ iAnim = ACT_VM_FIDGET;
+ }
+
+ SendWeaponAnim( iAnim );
+}
+
+
+bool CWeaponCrossbow::Deploy( void )
+{
+ if ( m_iClip1 <= 0 )
+ {
+ return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), ACT_CROSSBOW_DRAW_UNLOADED, (char*)GetAnimPrefix() );
+ }
+
+ return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), ACT_VM_DRAW, (char*)GetAnimPrefix() );
+}
+
+
+bool CWeaponCrossbow::Holster( CBaseCombatWeapon *pSwitchingTo )
+{
+ if ( m_fInZoom )
+ {
+ ToggleZoom();
+ }
+
+ return BaseClass::Holster( pSwitchingTo );
+}
+
+
+void CWeaponCrossbow::ToggleZoom( void )
+{
+ CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
+ if ( !pPlayer )
+ {
+ return;
+ }
+
+#if !defined(CLIENT_DLL)
+ if ( m_fInZoom )
+ {
+ if ( pPlayer->SetFOV( this, 0 ) )
+ {
+ m_fInZoom = false;
+ }
+ }
+ else
+ {
+ if ( pPlayer->SetFOV( this, 20 ) )
+ {
+ m_fInZoom = true;
+ }
+ }
+#endif
+}