diff options
Diffstat (limited to 'game/shared/hl1/hl1mp_weapon_sachel.cpp')
| -rw-r--r-- | game/shared/hl1/hl1mp_weapon_sachel.cpp | 600 |
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 |