summaryrefslogtreecommitdiff
path: root/game/shared/hl1/hl1mp_weapon_egon.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/shared/hl1/hl1mp_weapon_egon.cpp')
-rw-r--r--game/shared/hl1/hl1mp_weapon_egon.cpp529
1 files changed, 529 insertions, 0 deletions
diff --git a/game/shared/hl1/hl1mp_weapon_egon.cpp b/game/shared/hl1/hl1mp_weapon_egon.cpp
new file mode 100644
index 0000000..335f687
--- /dev/null
+++ b/game/shared/hl1/hl1mp_weapon_egon.cpp
@@ -0,0 +1,529 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Egon
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "npcevent.h"
+#include "hl1mp_basecombatweapon_shared.h"
+#include "Sprite.h"
+#include "beam_shared.h"
+#include "takedamageinfo.h"
+//#include "basecombatcharacter.h"
+//#include "AI_BaseNPC.h"
+
+#ifdef CLIENT_DLL
+#include "c_baseplayer.h"
+#include "hl1/hl1_c_player.h"
+#else
+#include "player.h"
+#include "hl1_player.h"
+#endif
+
+//#include "player.h"
+#include "gamerules.h"
+#include "in_buttons.h"
+
+#ifdef CLIENT_DLL
+#else
+#include "soundent.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
+
+
+enum EGON_FIRESTATE { FIRE_OFF, FIRE_STARTUP, FIRE_CHARGE };
+
+#define EGON_PULSE_INTERVAL 0.1
+#define EGON_DISCHARGE_INTERVAL 0.1
+
+#define EGON_BEAM_SPRITE "sprites/xbeam1.vmt"
+#define EGON_FLARE_SPRITE "sprites/XSpark1.vmt"
+
+extern ConVar sk_plr_dmg_egon_wide;
+
+//-----------------------------------------------------------------------------
+// CWeaponEgon
+//-----------------------------------------------------------------------------
+
+#ifdef CLIENT_DLL
+#define CWeaponEgon C_WeaponEgon
+#endif
+
+class CWeaponEgon : public CBaseHL1MPCombatWeapon
+{
+ DECLARE_CLASS( CWeaponEgon, CBaseHL1MPCombatWeapon );
+public:
+
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+
+ CWeaponEgon(void);
+
+ virtual bool Deploy( void );
+ void PrimaryAttack( void );
+ virtual void Precache( void );
+
+ void SecondaryAttack( void )
+ {
+ PrimaryAttack();
+ }
+
+ void WeaponIdle( void );
+ bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL );
+
+ // DECLARE_SERVERCLASS();
+ // DECLARE_DATADESC();
+
+private:
+ bool HasAmmo( void );
+ void UseAmmo( int count );
+ void Attack( void );
+ void EndAttack( void );
+ void Fire( const Vector &vecOrigSrc, const Vector &vecDir );
+ void UpdateEffect( const Vector &startPoint, const Vector &endPoint );
+ void CreateEffect( void );
+ void DestroyEffect( void );
+
+ EGON_FIRESTATE m_fireState;
+ float m_flAmmoUseTime; // since we use < 1 point of ammo per update, we subtract ammo on a timer.
+ float m_flShakeTime;
+ float m_flStartFireTime;
+ float m_flDmgTime;
+ CHandle<CSprite> m_hSprite;
+ CHandle<CBeam> m_hBeam;
+ CHandle<CBeam> m_hNoise;
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponEgon, DT_WeaponEgon );
+
+BEGIN_NETWORK_TABLE( CWeaponEgon, DT_WeaponEgon )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponEgon )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_egon, CWeaponEgon );
+PRECACHE_WEAPON_REGISTER( weapon_egon );
+
+/*
+IMPLEMENT_SERVERCLASS_ST( CWeaponEgon, DT_WeaponEgon )
+END_SEND_TABLE()
+*/
+
+ /*
+BEGIN_DATADESC( CWeaponEgon )
+ DEFINE_FIELD( m_fireState, FIELD_INTEGER ),
+ DEFINE_FIELD( m_flAmmoUseTime, FIELD_TIME ),
+ DEFINE_FIELD( m_flShakeTime, FIELD_TIME ),
+ DEFINE_FIELD( m_flStartFireTime, FIELD_TIME ),
+ DEFINE_FIELD( m_flDmgTime, FIELD_TIME ),
+ DEFINE_FIELD( m_hSprite, FIELD_EHANDLE ),
+ DEFINE_FIELD( m_hBeam, FIELD_EHANDLE ),
+ DEFINE_FIELD( m_hNoise, FIELD_EHANDLE ),
+END_DATADESC()
+ */
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CWeaponEgon::CWeaponEgon( void )
+{
+ m_bReloadsSingly = false;
+ m_bFiresUnderwater = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWeaponEgon::Precache( void )
+{
+ PrecacheScriptSound( "Weapon_Gluon.Start" );
+ PrecacheScriptSound( "Weapon_Gluon.Run" );
+ PrecacheScriptSound( "Weapon_Gluon.Off" );
+
+ PrecacheModel( EGON_BEAM_SPRITE );
+ PrecacheModel( EGON_FLARE_SPRITE );
+
+ BaseClass::Precache();
+}
+
+bool CWeaponEgon::Deploy( void )
+{
+ m_fireState = FIRE_OFF;
+
+ return BaseClass::Deploy();
+}
+
+bool CWeaponEgon::HasAmmo( void )
+{
+ CHL1_Player *pPlayer = ToHL1Player( GetOwner() );
+ if ( !pPlayer )
+ {
+ return false;
+ }
+
+ if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 )
+ return false;
+
+ return true;
+}
+
+void CWeaponEgon::UseAmmo( int count )
+{
+ CHL1_Player *pPlayer = ToHL1Player( GetOwner() );
+ if ( !pPlayer )
+ {
+ return;
+ }
+
+ if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) >= count )
+ pPlayer->RemoveAmmo( count, m_iPrimaryAmmoType );
+ else
+ pPlayer->RemoveAmmo( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ), m_iPrimaryAmmoType );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWeaponEgon::PrimaryAttack( void )
+{
+ CHL1_Player *pPlayer = ToHL1Player( GetOwner() );
+ if ( !pPlayer )
+ {
+ return;
+ }
+
+ // don't fire underwater
+ if ( pPlayer->GetWaterLevel() == 3 )
+ {
+ if ( m_fireState != FIRE_OFF || m_hBeam )
+ {
+ EndAttack();
+ }
+ else
+ {
+ WeaponSound( EMPTY );
+ }
+
+ m_flNextPrimaryAttack = gpGlobals->curtime + 0.5;
+ m_flNextSecondaryAttack = gpGlobals->curtime + 0.5;
+ return;
+ }
+
+ Vector vecAiming = pPlayer->GetAutoaimVector( 0 );
+ Vector vecSrc = pPlayer->Weapon_ShootPosition( );
+
+ switch( m_fireState )
+ {
+ case FIRE_OFF:
+ {
+ if ( !HasAmmo() )
+ {
+ m_flNextPrimaryAttack = gpGlobals->curtime + 0.25;
+ m_flNextSecondaryAttack = gpGlobals->curtime + 0.25;
+ WeaponSound( EMPTY );
+ return;
+ }
+
+ m_flAmmoUseTime = gpGlobals->curtime;// start using ammo ASAP.
+
+ EmitSound( "Weapon_Gluon.Start" );
+
+ SendWeaponAnim( ACT_VM_PRIMARYATTACK );
+
+ m_flShakeTime = 0;
+ m_flStartFireTime = gpGlobals->curtime;
+
+ SetWeaponIdleTime( gpGlobals->curtime + 0.1 );
+
+ m_flDmgTime = gpGlobals->curtime + EGON_PULSE_INTERVAL;
+ m_fireState = FIRE_STARTUP;
+ }
+ break;
+
+ case FIRE_STARTUP:
+ {
+ Fire( vecSrc, vecAiming );
+
+ if ( gpGlobals->curtime >= ( m_flStartFireTime + 2.0 ) )
+ {
+ EmitSound( "Weapon_Gluon.Run" );
+
+ m_fireState = FIRE_CHARGE;
+ }
+
+ if ( !HasAmmo() )
+ {
+ EndAttack();
+ m_flNextPrimaryAttack = gpGlobals->curtime + 1.0;
+ m_flNextSecondaryAttack = gpGlobals->curtime + 1.0;
+ }
+ }
+ case FIRE_CHARGE:
+ {
+ Fire( vecSrc, vecAiming );
+
+ if ( !HasAmmo() )
+ {
+ EndAttack();
+ m_flNextPrimaryAttack = gpGlobals->curtime + 1.0;
+ m_flNextSecondaryAttack = gpGlobals->curtime + 1.0;
+ }
+ }
+ break;
+ }
+}
+
+void CWeaponEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir )
+{
+ CHL1_Player *pPlayer = ToHL1Player( GetOwner() );
+ if ( !pPlayer )
+ {
+ return;
+ }
+
+ //CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 450, 0.1 );
+ WeaponSound( SINGLE );
+
+ Vector vecDest = vecOrigSrc + (vecDir * MAX_TRACE_LENGTH);
+
+ trace_t tr;
+ UTIL_TraceLine( vecOrigSrc, vecDest, MASK_SHOT, pPlayer, COLLISION_GROUP_NONE, &tr );
+
+ if ( tr.allsolid )
+ return;
+
+ CBaseEntity *pEntity = tr.m_pEnt;
+ if ( pEntity == NULL )
+ return;
+
+ if ( g_pGameRules->IsMultiplayer() )
+ {
+ if ( m_hSprite )
+ {
+ if ( pEntity->m_takedamage != DAMAGE_NO )
+ {
+ m_hSprite->TurnOn();
+ }
+ else
+ {
+ m_hSprite->TurnOff();
+ }
+ }
+ }
+
+ if ( m_flDmgTime < gpGlobals->curtime )
+ {
+ // wide mode does damage to the ent, and radius damage
+ if ( pEntity->m_takedamage != DAMAGE_NO )
+ {
+ ClearMultiDamage();
+ CTakeDamageInfo info( this, pPlayer, sk_plr_dmg_egon_wide.GetFloat() * g_pGameRules->GetDamageMultiplier(), DMG_ENERGYBEAM | DMG_ALWAYSGIB );
+ CalculateMeleeDamageForce( &info, vecDir, tr.endpos );
+ pEntity->DispatchTraceAttack( info, vecDir, &tr );
+ ApplyMultiDamage();
+ }
+
+ if ( g_pGameRules->IsMultiplayer() )
+ {
+ // radius damage a little more potent in multiplayer.
+#ifndef CLIENT_DLL
+ RadiusDamage( CTakeDamageInfo( this, pPlayer, sk_plr_dmg_egon_wide.GetFloat() * g_pGameRules->GetDamageMultiplier() / 4, DMG_ENERGYBEAM | DMG_BLAST | DMG_ALWAYSGIB ), tr.endpos, 128, CLASS_NONE, NULL );
+#endif
+ }
+
+ if ( !pPlayer->IsAlive() )
+ return;
+
+ if ( g_pGameRules->IsMultiplayer() )
+ {
+ //multiplayer uses 5 ammo/second
+ if ( gpGlobals->curtime >= m_flAmmoUseTime )
+ {
+ UseAmmo( 1 );
+ m_flAmmoUseTime = gpGlobals->curtime + 0.2;
+ }
+ }
+ else
+ {
+ // Wide mode uses 10 charges per second in single player
+ if ( gpGlobals->curtime >= m_flAmmoUseTime )
+ {
+ UseAmmo( 1 );
+ m_flAmmoUseTime = gpGlobals->curtime + 0.1;
+ }
+ }
+
+ m_flDmgTime = gpGlobals->curtime + EGON_DISCHARGE_INTERVAL;
+ if ( m_flShakeTime < gpGlobals->curtime )
+ {
+#ifndef CLIENT_DLL
+ UTIL_ScreenShake( tr.endpos, 5.0, 150.0, 0.75, 250.0, SHAKE_START );
+#endif
+ m_flShakeTime = gpGlobals->curtime + 1.5;
+ }
+ }
+
+ Vector vecUp, vecRight;
+ QAngle angDir;
+
+ VectorAngles( vecDir, angDir );
+ AngleVectors( angDir, NULL, &vecRight, &vecUp );
+
+ Vector tmpSrc = vecOrigSrc + (vecUp * -8) + (vecRight * 3);
+ UpdateEffect( tmpSrc, tr.endpos );
+}
+
+void CWeaponEgon::UpdateEffect( const Vector &startPoint, const Vector &endPoint )
+{
+ if ( !m_hBeam )
+ {
+ CreateEffect();
+ }
+
+ if ( m_hBeam )
+ {
+ m_hBeam->SetStartPos( endPoint );
+ }
+
+ if ( m_hSprite )
+ {
+ m_hSprite->SetAbsOrigin( endPoint );
+
+ m_hSprite->m_flFrame += 8 * gpGlobals->frametime;
+ if ( m_hSprite->m_flFrame > m_hSprite->Frames() )
+ m_hSprite->m_flFrame = 0;
+ }
+
+ if ( m_hNoise )
+ {
+ m_hNoise->SetStartPos( endPoint );
+ }
+}
+
+void CWeaponEgon::CreateEffect( void )
+{
+#ifndef CLIENT_DLL
+ CHL1_Player *pPlayer = ToHL1Player( GetOwner() );
+ if ( !pPlayer )
+ {
+ return;
+ }
+
+ DestroyEffect();
+
+ m_hBeam = CBeam::BeamCreate( EGON_BEAM_SPRITE, 3.5 );
+ m_hBeam->PointEntInit( GetAbsOrigin(), this );
+ m_hBeam->SetBeamFlags( FBEAM_SINENOISE );
+ m_hBeam->SetEndAttachment( 1 );
+ m_hBeam->AddSpawnFlags( SF_BEAM_TEMPORARY ); // Flag these to be destroyed on save/restore or level transition
+ m_hBeam->SetOwnerEntity( pPlayer );
+ m_hBeam->SetScrollRate( 10 );
+ m_hBeam->SetBrightness( 200 );
+ m_hBeam->SetColor( 50, 50, 255 );
+ m_hBeam->SetNoise( 0.2 );
+
+ m_hNoise = CBeam::BeamCreate( EGON_BEAM_SPRITE, 5.0 );
+ m_hNoise->PointEntInit( GetAbsOrigin(), this );
+ m_hNoise->SetEndAttachment( 1 );
+ m_hNoise->AddSpawnFlags( SF_BEAM_TEMPORARY );
+ m_hNoise->SetOwnerEntity( pPlayer );
+ m_hNoise->SetScrollRate( 25 );
+ m_hNoise->SetBrightness( 200 );
+ m_hNoise->SetColor( 50, 50, 255 );
+ m_hNoise->SetNoise( 0.8 );
+
+ m_hSprite = CSprite::SpriteCreate( EGON_FLARE_SPRITE, GetAbsOrigin(), false );
+ m_hSprite->SetScale( 1.0 );
+ m_hSprite->SetTransparency( kRenderGlow, 255, 255, 255, 255, kRenderFxNoDissipation );
+ m_hSprite->AddSpawnFlags( SF_SPRITE_TEMPORARY );
+ m_hSprite->SetOwnerEntity( pPlayer );
+#endif
+}
+
+
+void CWeaponEgon::DestroyEffect( void )
+{
+#ifndef CLIENT_DLL
+ if ( m_hBeam )
+ {
+ UTIL_Remove( m_hBeam );
+ m_hBeam = NULL;
+ }
+ if ( m_hNoise )
+ {
+ UTIL_Remove( m_hNoise );
+ m_hNoise = NULL;
+ }
+ if ( m_hSprite )
+ {
+ m_hSprite->Expand( 10, 500 );
+ m_hSprite = NULL;
+ }
+#endif
+}
+
+void CWeaponEgon::EndAttack( void )
+{
+ StopSound( "Weapon_Gluon.Run" );
+
+ if ( m_fireState != FIRE_OFF )
+ {
+ EmitSound( "Weapon_Gluon.Off" );
+ }
+
+ SetWeaponIdleTime( gpGlobals->curtime + 2.0 );
+ m_flNextPrimaryAttack = gpGlobals->curtime + 0.5;
+ m_flNextSecondaryAttack = gpGlobals->curtime + 0.5;
+
+ m_fireState = FIRE_OFF;
+
+ DestroyEffect();
+}
+
+bool CWeaponEgon::Holster( CBaseCombatWeapon *pSwitchingTo )
+{
+ EndAttack();
+
+ return BaseClass::Holster( pSwitchingTo );
+}
+
+void CWeaponEgon::WeaponIdle( void )
+{
+ if ( !HasWeaponIdleTimeElapsed() )
+ return;
+
+ if ( m_fireState != FIRE_OFF )
+ EndAttack();
+
+ int iAnim;
+
+ float flRand = random->RandomFloat( 0,1 );
+ float flIdleTime;
+ if ( flRand <= 0.5 )
+ {
+ iAnim = ACT_VM_IDLE;
+ flIdleTime = gpGlobals->curtime + random->RandomFloat( 10, 15 );
+ }
+ else
+ {
+ iAnim = ACT_VM_FIDGET;
+ flIdleTime = gpGlobals->curtime + 3.0;
+ }
+
+ SendWeaponAnim( iAnim );
+
+ SetWeaponIdleTime( flIdleTime );
+}