|
|
//========= 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
|