diff options
Diffstat (limited to 'game/shared/hl1/hl1mp_weapon_egon.cpp')
| -rw-r--r-- | game/shared/hl1/hl1mp_weapon_egon.cpp | 529 |
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 ); +} |