summaryrefslogtreecommitdiff
path: root/game/shared/hl1/hl1mp_weapon_sachel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/shared/hl1/hl1mp_weapon_sachel.cpp')
-rw-r--r--game/shared/hl1/hl1mp_weapon_sachel.cpp600
1 files changed, 600 insertions, 0 deletions
diff --git a/game/shared/hl1/hl1mp_weapon_sachel.cpp b/game/shared/hl1/hl1mp_weapon_sachel.cpp
new file mode 100644
index 0000000..cc26019
--- /dev/null
+++ b/game/shared/hl1/hl1mp_weapon_sachel.cpp
@@ -0,0 +1,600 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Satchel charge
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "npcevent.h"
+#include "hl1_basecombatweapon_shared.h"
+//#include "basecombatweapon.h"
+//#include "basecombatcharacter.h"
+#ifdef CLIENT_DLL
+#include "c_baseplayer.h"
+#else
+#include "player.h"
+#endif
+//#include "AI_BaseNPC.h"
+//#include "player.h"
+#include "gamerules.h"
+#include "in_buttons.h"
+#ifndef CLIENT_DLL
+#include "soundent.h"
+#include "game.h"
+#endif
+#include "vstdlib/random.h"
+#include "engine/IEngineSound.h"
+#include "hl1mp_weapon_satchel.h"
+
+
+//-----------------------------------------------------------------------------
+// CWeaponSatchel
+//-----------------------------------------------------------------------------
+
+
+#define SATCHEL_VIEW_MODEL "models/v_satchel.mdl"
+#define SATCHEL_WORLD_MODEL "models/w_satchel.mdl"
+#define SATCHELRADIO_VIEW_MODEL "models/v_satchel_radio.mdl"
+#define SATCHELRADIO_WORLD_MODEL "models/w_satchel.mdl" // this needs fixing if we do multiplayer
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponSatchel, DT_WeaponSatchel );
+
+BEGIN_NETWORK_TABLE( CWeaponSatchel, DT_WeaponSatchel )
+#ifdef CLIENT_DLL
+ RecvPropInt( RECVINFO( m_iRadioViewIndex ) ),
+ RecvPropInt( RECVINFO( m_iRadioWorldIndex ) ),
+ RecvPropInt( RECVINFO( m_iSatchelViewIndex ) ),
+ RecvPropInt( RECVINFO( m_iSatchelWorldIndex ) ),
+ RecvPropInt( RECVINFO( m_iChargeReady ) ),
+#else
+ SendPropInt( SENDINFO( m_iRadioViewIndex ) ),
+ SendPropInt( SENDINFO( m_iRadioWorldIndex ) ),
+ SendPropInt( SENDINFO( m_iSatchelViewIndex ) ),
+ SendPropInt( SENDINFO( m_iSatchelWorldIndex ) ),
+ SendPropInt( SENDINFO( m_iChargeReady ) ),
+#endif
+END_NETWORK_TABLE()
+
+LINK_ENTITY_TO_CLASS( weapon_satchel, CWeaponSatchel );
+
+PRECACHE_WEAPON_REGISTER( weapon_satchel );
+
+//IMPLEMENT_SERVERCLASS_ST( CWeaponSatchel, DT_WeaponSatchel )
+//END_SEND_TABLE()
+
+
+BEGIN_PREDICTION_DATA( CWeaponSatchel )
+#ifdef CLIENT_DLL
+ DEFINE_PRED_FIELD( m_iRadioViewIndex, FIELD_INTEGER, FTYPEDESC_INSENDTABLE | FTYPEDESC_MODELINDEX ),
+ DEFINE_PRED_FIELD( m_iRadioWorldIndex, FIELD_INTEGER, FTYPEDESC_INSENDTABLE | FTYPEDESC_MODELINDEX ),
+ DEFINE_PRED_FIELD( m_iSatchelViewIndex, FIELD_INTEGER, FTYPEDESC_INSENDTABLE | FTYPEDESC_MODELINDEX ),
+ DEFINE_PRED_FIELD( m_iSatchelWorldIndex, FIELD_INTEGER, FTYPEDESC_INSENDTABLE | FTYPEDESC_MODELINDEX ),
+ DEFINE_PRED_FIELD( m_iChargeReady, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
+#endif
+END_PREDICTION_DATA()
+
+
+BEGIN_DATADESC( CWeaponSatchel )
+ DEFINE_FIELD( m_iChargeReady, FIELD_INTEGER ),
+
+// DEFINE_FIELD( m_iRadioViewIndex, FIELD_INTEGER ),
+// DEFINE_FIELD( m_iRadioWorldIndex, FIELD_INTEGER ),
+// DEFINE_FIELD( m_iSatchelViewIndex, FIELD_INTEGER ),
+// DEFINE_FIELD( m_iSatchelWorldIndex, FIELD_INTEGER ),
+END_DATADESC()
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CWeaponSatchel::CWeaponSatchel( void )
+{
+ m_bReloadsSingly = false;
+ m_bFiresUnderwater = true;
+}
+
+void CWeaponSatchel::Equip( CBaseCombatCharacter *pOwner )
+{
+ BaseClass::Equip( pOwner );
+
+ m_iChargeReady = 0; // this satchel charge weapon now forgets that any satchels are deployed by it.
+}
+
+bool CWeaponSatchel::HasAnyAmmo( void )
+{
+ CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
+ if ( !pPlayer )
+ {
+ return false;
+ }
+
+ if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) > 0 )
+ {
+ // player is carrying some satchels
+ return true;
+ }
+
+ if ( HasChargeDeployed() )
+ {
+ // player isn't carrying any satchels, but has some out
+ return true;
+ }
+
+ return BaseClass::HasAnyAmmo();
+}
+
+bool CWeaponSatchel::CanDeploy( void )
+{
+ if ( HasAnyAmmo() )
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWeaponSatchel::Precache( void )
+{
+ m_iSatchelViewIndex = PrecacheModel( SATCHEL_VIEW_MODEL );
+ m_iSatchelWorldIndex = PrecacheModel( SATCHEL_WORLD_MODEL );
+ m_iRadioViewIndex = PrecacheModel( SATCHELRADIO_VIEW_MODEL );
+ m_iRadioWorldIndex = PrecacheModel( SATCHELRADIO_WORLD_MODEL );
+
+#ifndef CLIENT_DLL
+ UTIL_PrecacheOther( "monster_satchel" );
+#endif
+
+ BaseClass::Precache();
+}
+
+void CWeaponSatchel::ItemPostFrame( void )
+{
+ CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
+ if (!pOwner)
+ {
+ return;
+ }
+
+ if ( (pOwner->m_nButtons & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime) )
+ {
+ // If the firing button was just pressed, reset the firing time
+ if ( pOwner->m_afButtonPressed & IN_ATTACK )
+ {
+ m_flNextPrimaryAttack = gpGlobals->curtime;
+ }
+
+ PrimaryAttack();
+ }
+
+ BaseClass::ItemPostFrame();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWeaponSatchel::PrimaryAttack( void )
+{
+ switch ( m_iChargeReady )
+ {
+ case 0:
+ {
+ Throw();
+ }
+ break;
+ case 1:
+ {
+ CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
+ if ( !pPlayer )
+ {
+ return;
+ }
+
+ SendWeaponAnim( ACT_VM_PRIMARYATTACK );
+
+#ifndef CLIENT_DLL
+ CBaseEntity *pSatchel = NULL;
+
+ while ( (pSatchel = gEntList.FindEntityByClassname( pSatchel, "monster_satchel" ) ) != NULL)
+ {
+ if ( pSatchel->GetOwnerEntity() == pPlayer )
+ {
+ pSatchel->Use( pPlayer, pPlayer, USE_ON, 0 );
+ }
+ }
+#endif
+
+ m_iChargeReady = 2;
+ m_flNextPrimaryAttack = gpGlobals->curtime + 0.5;
+ m_flNextSecondaryAttack = gpGlobals->curtime + 0.5;
+ SetWeaponIdleTime( gpGlobals->curtime + 0.5 );
+ break;
+ }
+
+ case 2:
+ // we're reloading, don't allow fire
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWeaponSatchel::SecondaryAttack( void )
+{
+ if ( m_iChargeReady != 2 )
+ {
+ Throw();
+ }
+}
+
+void CWeaponSatchel::Throw( void )
+{
+ CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
+ if ( !pPlayer )
+ {
+ return;
+ }
+
+ if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) > 0 )
+ {
+ Vector vecForward;
+ pPlayer->EyeVectors( &vecForward );
+
+ Vector vecSrc = pPlayer->WorldSpaceCenter();
+ Vector vecThrow = vecForward * 274 + pPlayer->GetAbsVelocity();
+
+#ifndef CLIENT_DLL
+ CBaseEntity *pSatchel = Create( "monster_satchel", vecSrc, QAngle( 0, 0, 90 ), pPlayer );
+ if ( pSatchel )
+ {
+ pSatchel->SetAbsVelocity( vecThrow );
+ QAngle angVel = pSatchel->GetLocalAngularVelocity();
+ angVel.y = 400;
+ pSatchel->SetLocalAngularVelocity( angVel );
+
+ ActivateRadioModel();
+
+ SendWeaponAnim( ACT_VM_DRAW );
+
+ // player "shoot" animation
+ pPlayer->SetAnimation( PLAYER_ATTACK1 );
+
+ m_iChargeReady = 1;
+
+ pPlayer->RemoveAmmo( 1, m_iPrimaryAmmoType );
+
+ }
+#endif
+
+ m_flNextPrimaryAttack = gpGlobals->curtime + 1.0;
+ m_flNextSecondaryAttack = gpGlobals->curtime + 0.5;
+ }
+}
+
+void CWeaponSatchel::WeaponIdle( void )
+{
+ if ( !HasWeaponIdleTimeElapsed() )
+ return;
+
+ switch( m_iChargeReady )
+ {
+ case 0:
+ case 1:
+ SendWeaponAnim( ACT_VM_FIDGET );
+ break;
+ case 2:
+ {
+ CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
+
+ if ( pPlayer && (pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0) )
+ {
+ m_iChargeReady = 0;
+ if ( !pPlayer->SwitchToNextBestWeapon( pPlayer->GetActiveWeapon() ) )
+ {
+ Holster();
+ }
+
+ return;
+ }
+
+ ActivateSatchelModel();
+
+ SendWeaponAnim( ACT_VM_DRAW );
+
+ m_flNextPrimaryAttack = gpGlobals->curtime + 0.5;
+ m_flNextSecondaryAttack = gpGlobals->curtime + 0.5;
+ m_iChargeReady = 0;
+ break;
+ }
+ }
+
+ SetWeaponIdleTime( gpGlobals->curtime + random->RandomFloat( 10, 15 ) );// how long till we do this again.
+}
+
+bool CWeaponSatchel::Deploy( void )
+{
+ SetWeaponIdleTime( gpGlobals->curtime + random->RandomFloat( 10, 15 ) );
+
+ if ( HasChargeDeployed() )
+ {
+ ActivateRadioModel();
+ }
+ else
+ {
+ ActivateSatchelModel();
+ }
+
+ bool bRet = BaseClass::Deploy();
+ if ( bRet )
+ {
+ //
+ CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
+ if ( pPlayer )
+ {
+ pPlayer->SetNextAttack( gpGlobals->curtime + 1.0 );
+ }
+ }
+
+ return bRet;
+
+}
+
+bool CWeaponSatchel::Holster( CBaseCombatWeapon *pSwitchingTo )
+{
+ if ( !BaseClass::Holster( pSwitchingTo ) )
+ {
+ return false;
+ }
+
+ CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
+ if ( pPlayer )
+ {
+ pPlayer->SetNextAttack( gpGlobals->curtime + 0.5 );
+
+ if ( (pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0) && !HasChargeDeployed() )
+ {
+#ifndef CLIENT_DLL
+ SetThink( &CWeaponSatchel::DestroyItem );
+ SetNextThink( gpGlobals->curtime + 0.1 );
+#endif
+ }
+ }
+
+ return true;
+}
+
+void CWeaponSatchel::ActivateSatchelModel( void )
+{
+ m_iViewModelIndex = m_iSatchelViewIndex;
+ m_iWorldModelIndex = m_iSatchelWorldIndex;
+ SetModel( GetViewModel() );
+}
+
+void CWeaponSatchel::ActivateRadioModel( void )
+{
+ m_iViewModelIndex = m_iRadioViewIndex;
+ m_iWorldModelIndex = m_iRadioWorldIndex;
+ SetModel( GetViewModel() );
+}
+
+const char *CWeaponSatchel::GetViewModel( int ) const
+{
+ if ( m_iViewModelIndex == m_iSatchelViewIndex )
+ {
+ return SATCHEL_VIEW_MODEL;
+ }
+ else
+ {
+ return SATCHELRADIO_VIEW_MODEL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+const char *CWeaponSatchel::GetWorldModel( void ) const
+{
+ if ( m_iViewModelIndex == m_iSatchelViewIndex )
+ {
+ return SATCHEL_WORLD_MODEL;
+ }
+ else
+ {
+ return SATCHELRADIO_WORLD_MODEL;
+ }
+}
+
+void CWeaponSatchel::OnRestore( void )
+{
+ BaseClass::OnRestore();
+ if ( HasChargeDeployed() )
+ {
+ ActivateRadioModel();
+ }
+ else
+ {
+ ActivateSatchelModel();
+ }
+}
+
+#ifndef CLIENT_DLL
+//-----------------------------------------------------------------------------
+// CSatchelCharge
+//-----------------------------------------------------------------------------
+
+#define SATCHEL_CHARGE_MODEL "models/w_satchel.mdl"
+
+
+extern ConVar sk_plr_dmg_satchel;
+
+
+BEGIN_DATADESC( CSatchelCharge )
+ DEFINE_FIELD( m_flNextBounceSoundTime, FIELD_TIME ),
+ DEFINE_FIELD( m_bInAir, FIELD_BOOLEAN ),
+ DEFINE_FIELD( m_vLastPosition, FIELD_POSITION_VECTOR ),
+
+ // Function Pointers
+ DEFINE_ENTITYFUNC( SatchelTouch ),
+ DEFINE_THINKFUNC( SatchelThink ),
+ DEFINE_USEFUNC( SatchelUse ),
+END_DATADESC()
+
+LINK_ENTITY_TO_CLASS( monster_satchel, CSatchelCharge );
+
+//=========================================================
+// Deactivate - do whatever it is we do to an orphaned
+// satchel when we don't want it in the world anymore.
+//=========================================================
+void CSatchelCharge::Deactivate( void )
+{
+ AddSolidFlags( FSOLID_NOT_SOLID );
+ UTIL_Remove( this );
+}
+
+
+void CSatchelCharge::Spawn( void )
+{
+ Precache( );
+ // motor
+ SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_SLIDE );
+ SetSolid( SOLID_BBOX );
+
+ SetModel( SATCHEL_CHARGE_MODEL );
+
+ UTIL_SetSize( this, Vector( -4, -4, 0), Vector(4, 4, 8) );
+
+ SetTouch( &CSatchelCharge::SatchelTouch );
+ SetUse( &CSatchelCharge::SatchelUse );
+ SetThink( &CSatchelCharge::SatchelThink );
+ SetNextThink( gpGlobals->curtime + 0.1f );
+
+ m_flDamage = sk_plr_dmg_satchel.GetFloat();
+ m_DmgRadius = m_flDamage * 2.5;
+ m_takedamage = DAMAGE_NO;
+ m_iHealth = 1;
+
+ SetGravity( UTIL_ScaleForGravity( 560 ) ); // slightly lower gravity
+ SetFriction( 0.97 ); //used in SatchelTouch to slow us when sliding
+ SetSequence( LookupSequence( "onback" ) );
+
+ m_bInAir = false;
+ m_flNextBounceSoundTime = 0;
+
+ m_vLastPosition = vec3_origin;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input :
+// Output :
+//-----------------------------------------------------------------------------
+void CSatchelCharge::SatchelUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
+{
+ SetThink( &CBaseGrenade::Detonate );
+ SetNextThink( gpGlobals->curtime );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input :
+// Output :
+//-----------------------------------------------------------------------------
+void CSatchelCharge::SatchelTouch( CBaseEntity *pOther )
+{
+ Assert( pOther );
+ if ( pOther->IsSolidFlagSet(FSOLID_TRIGGER | FSOLID_VOLUME_CONTENTS) || GetWaterLevel() > 0 )
+ return;
+
+ StudioFrameAdvance( );
+
+ UpdateSlideSound();
+
+ if ( m_bInAir )
+ {
+ BounceSound();
+ m_bInAir = false;
+ }
+
+ // add a bit of static friction
+ SetAbsVelocity( GetAbsVelocity() * GetFriction() );
+ SetLocalAngularVelocity( GetLocalAngularVelocity() * GetFriction() );
+}
+
+void CSatchelCharge::UpdateSlideSound( void )
+{
+ // HACKHACK - On ground isn't always set, so look for ground underneath
+ trace_t tr;
+ UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() - Vector(0,0,10), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr );
+
+ if ( !(tr.fraction < 1.0) )
+ {
+ m_bInAir = true;
+ }
+}
+
+void CSatchelCharge::SatchelThink( void )
+{
+ UpdateSlideSound();
+
+ StudioFrameAdvance( );
+ SetNextThink( gpGlobals->curtime + 0.1f );
+
+ if (!IsInWorld())
+ {
+ UTIL_Remove( this );
+ return;
+ }
+
+ Vector vecNewVel = GetAbsVelocity();
+
+ if ( GetWaterLevel() > 0 )
+ {
+ SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
+ vecNewVel *= 0.8;
+ SetLocalAngularVelocity( GetLocalAngularVelocity() * 0.9 );
+
+ vecNewVel.z = 0;
+ SetGravity( -0.2 );
+ }
+ else if ( GetWaterLevel() == 0 )
+ {
+ SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_SLIDE );
+
+ SetGravity( 1.0 );
+ }
+
+ SetAbsVelocity( vecNewVel );
+}
+
+void CSatchelCharge::Precache( void )
+{
+ PrecacheModel( SATCHEL_CHARGE_MODEL );
+ PrecacheScriptSound( "SatchelCharge.Bounce" );
+}
+
+void CSatchelCharge::BounceSound( void )
+{
+ if ( gpGlobals->curtime > m_flNextBounceSoundTime )
+ {
+ EmitSound( "SatchelCharge.Bounce" );
+
+ m_flNextBounceSoundTime = gpGlobals->curtime + 0.1;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+// Input :
+// Output :
+//-----------------------------------------------------------------------------
+CSatchelCharge::CSatchelCharge(void)
+{
+ m_vLastPosition.Init();
+}
+
+#endif