2010-07-22 01:46:14 -05:00
# include "cbase.h"
# include "npcevent.h"
# include "Sprite.h"
# include "beam_shared.h"
# include "takedamageinfo.h"
# include "gamerules.h"
# include "in_buttons.h"
2010-07-23 21:26:45 -05:00
# include "asw_weapon_parse.h"
# include "asw_marine_skills.h"
2010-07-22 01:46:14 -05:00
# ifdef CLIENT_DLL
# include "c_baseplayer.h"
# include "c_asw_player.h"
# include "c_asw_marine.h"
# include "c_te_effect_dispatch.h"
# include "c_asw_alien.h"
# include "fx.h"
# else
# include "player.h"
# include "asw_player.h"
# include "asw_marine.h"
# include "soundent.h"
# include "game.h"
# include "te_effect_dispatch.h"
# include "asw_marine_speech.h"
# include "asw_weapon_ammo_bag_shared.h"
# include "asw_alien.h"
# include "ndebugoverlay.h"
# endif
# include "vstdlib/random.h"
# include "engine/IEngineSound.h"
# include "IEffects.h"
# include "asw_trace_filter_shot.h"
# include "particle_parse.h"
# include "asw_weapon_tesla_gun_shared.h"
// memdbgon must be the last include file in a .cpp file!!!
# include "tier0/memdbgon.h"
static const float ASW_TG_RANGE = 240.0f ; // Range of electrical discharge - TODO: make this an attribute?
static const float ASW_TG_TRACE_SIZE = 10.0f ; // Size of the laser's trace attack
static const float ASW_TG_FIELD_DURATION = 2.0f ; // Duration of electrical field left behind
//static const float ASW_TG_SHOCK_RATE = 0.25f; // Rate at which we shock entities we're latched on
static const float ASW_TG_SEARCH_DIAMETER = 48.0f ; // How far past the range to search for enemies to latch on to
static const float SQRT3 = 1.732050807569 ; // for computing max extents inside a box
static const Vector ASW_TG_SEARCH_BOX_EXTENTS ( ASW_TG_SEARCH_DIAMETER / 2.0f , ASW_TG_SEARCH_DIAMETER / 2.0f , ASW_TG_SEARCH_DIAMETER / 2.0f ) ;
static const int ASW_TG_MAX_SHOCK_ALIENS = 6 ; // Max # of aliens to search for a shock target
extern int g_sModelIndexSmoke ; // (in combatweapon.cpp) holds the index for the smoke cloud
IMPLEMENT_NETWORKCLASS_ALIASED ( ASW_Weapon_Tesla_Gun , DT_ASW_Weapon_Tesla_Gun ) ;
BEGIN_NETWORK_TABLE ( CASW_Weapon_Tesla_Gun , DT_ASW_Weapon_Tesla_Gun )
# ifdef CLIENT_DLL
// recvprops
RecvPropTime ( RECVINFO ( m_fSlowTime ) ) ,
RecvPropInt ( RECVINFO ( m_FireState ) ) ,
RecvPropEHandle ( RECVINFO ( m_hShockEntity ) ) ,
RecvPropVector ( RECVINFO ( m_vecShockPos ) ) ,
# else
// sendprops
SendPropTime ( SENDINFO ( m_fSlowTime ) ) ,
SendPropInt ( SENDINFO ( m_FireState ) , Q_log2 ( ASW_TG_NUM_FIRE_STATES ) + 1 , SPROP_UNSIGNED ) ,
SendPropEHandle ( SENDINFO ( m_hShockEntity ) ) ,
SendPropVector ( SENDINFO ( m_vecShockPos ) ) ,
# endif
END_NETWORK_TABLE ( )
LINK_ENTITY_TO_CLASS ( asw_weapon_tesla_gun , CASW_Weapon_Tesla_Gun ) ;
PRECACHE_WEAPON_REGISTER ( asw_weapon_tesla_gun ) ;
# if defined( CLIENT_DLL )
BEGIN_PREDICTION_DATA ( CASW_Weapon_Tesla_Gun )
DEFINE_PRED_FIELD_TOL ( m_fSlowTime , FIELD_FLOAT , FTYPEDESC_INSENDTABLE , TD_MSECTOLERANCE ) ,
DEFINE_PRED_FIELD ( m_vecShockPos , FIELD_VECTOR , FTYPEDESC_INSENDTABLE ) ,
END_PREDICTION_DATA ( )
# endif
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CASW_Weapon_Tesla_Gun : : CASW_Weapon_Tesla_Gun ( void )
{
m_bReloadsSingly = false ;
m_bFiresUnderwater = true ;
# ifdef GAME_DLL
m_fLastForcedFireTime = 0 ; // last time we forced an AI marine to push its fire button
# endif
2010-07-23 21:26:45 -05:00
m_flLastShockTime = 0.0f ;
m_flLastDischargeTime = 0.0f ;
2010-07-22 01:46:14 -05:00
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CASW_Weapon_Tesla_Gun : : Precache ( void )
{
PrecacheScriptSound ( " ASW_MiningLaser.ReloadA " ) ;
PrecacheScriptSound ( " ASW_MiningLaser.ReloadB " ) ;
PrecacheScriptSound ( " ASW_MiningLaser.ReloadC " ) ;
PrecacheScriptSound ( " ASW_Tesla_Laser.Damage " ) ;
PrecacheScriptSound ( " ASW_Tesla_Laser.Loop " ) ;
PrecacheScriptSound ( " ASW_Tesla_Laser.Stop " ) ;
PrecacheParticleSystem ( " mining_laser_exhaust " ) ;
BaseClass : : Precache ( ) ;
}
bool CASW_Weapon_Tesla_Gun : : HasAmmo ( )
{
return m_iClip1 > 0 ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CASW_Weapon_Tesla_Gun : : PrimaryAttack ( void )
{
CASW_Player * pPlayer = GetCommander ( ) ;
CASW_Marine * pMarine = GetMarine ( ) ;
if ( ! pMarine | | ! pMarine - > IsAlive ( ) )
{
EndAttack ( ) ;
return ;
}
// don't fire underwater
if ( pMarine - > GetWaterLevel ( ) = = 3 )
{
WeaponSound ( EMPTY ) ;
m_flNextPrimaryAttack = gpGlobals - > curtime + 0.5 ;
m_flNextSecondaryAttack = gpGlobals - > curtime + 0.5 ;
return ;
}
Vector vecSrc = pMarine - > Weapon_ShootPosition ( ) ;
Vector vecAiming = vec3_origin ;
if ( pPlayer & & pMarine - > IsInhabited ( ) )
{
vecAiming = pPlayer - > GetAutoaimVectorForMarine ( pMarine , GetAutoAimAmount ( ) , GetVerticalAdjustOnlyAutoAimAmount ( ) ) ; // 45 degrees = 0.707106781187
}
else
{
# ifndef CLIENT_DLL
vecAiming = pMarine - > GetActualShootTrajectory ( vecSrc ) ;
# endif
}
# ifdef GAME_DLL
m_bIsFiring = true ;
switch ( m_FireState )
{
case ASW_TG_FIRE_OFF :
{
Fire ( vecSrc , vecAiming ) ;
m_flNextPrimaryAttack = gpGlobals - > curtime ;
break ;
}
case ASW_TG_FIRE_DISCHARGE :
{
Fire ( vecSrc , vecAiming ) ;
EHANDLE hShockEntity = m_hShockEntity . Get ( ) ;
// Search for nearby entities to shock
if ( ! hShockEntity )
{
CBaseEntity * pList [ ASW_TG_MAX_SHOCK_ALIENS ] ;
int nCount = UTIL_EntitiesInBox ( pList , ASW_TG_MAX_SHOCK_ALIENS , m_vecShockPos . Get ( ) - ASW_TG_SEARCH_BOX_EXTENTS , m_vecShockPos . Get ( ) + ASW_TG_SEARCH_BOX_EXTENTS , 0 ) ;
for ( int i = 0 ; i < nCount ; i + + )
{
if ( ShockAttach ( pList [ i ] ) )
{
SetFiringState ( ASW_TG_FIRE_ATTACHED ) ;
m_flLastShockTime = 0.0f ;
break ;
}
}
}
2010-07-23 21:26:45 -05:00
if ( gpGlobals - > curtime > m_flLastDischargeTime + ( GetFireRate ( ) * 3 ) )
{
m_iClip1 = MAX ( 0 , m_iClip1 - 1 ) ;
m_flLastDischargeTime = gpGlobals - > curtime ;
}
2010-07-22 01:46:14 -05:00
m_flNextPrimaryAttack = gpGlobals - > curtime ;
break ;
}
case ASW_TG_FIRE_ATTACHED :
{
Fire ( vecSrc , vecAiming ) ;
EHANDLE hShockEntity = m_hShockEntity . Get ( ) ;
if ( ! hShockEntity | | hShockEntity - > GetHealth ( ) < = 0 )
{
SetFiringState ( ASW_TG_FIRE_DISCHARGE ) ;
break ;
}
// detach if...
// too far
float flShockDistance = ( hShockEntity - > GetAbsOrigin ( ) - pMarine - > GetAbsOrigin ( ) ) . LengthSqr ( ) ;
if ( flShockDistance > ( GetWeaponRange ( ) + SQRT3 * ASW_TG_SEARCH_DIAMETER ) * ( GetWeaponRange ( ) + SQRT3 * ASW_TG_SEARCH_DIAMETER ) )
{
ShockDetach ( ) ;
SetFiringState ( ASW_TG_FIRE_DISCHARGE ) ;
break ;
}
// dead
if ( hShockEntity - > m_iHealth < = 0 )
{
ShockDetach ( ) ;
SetFiringState ( ASW_TG_FIRE_DISCHARGE ) ;
break ;
}
// facing another direction
Vector vecAttach = hShockEntity - > GetAbsOrigin ( ) - pMarine - > GetAbsOrigin ( ) ;
Vector vecForward ;
CASW_Player * pPlayer = pMarine - > GetCommander ( ) ;
if ( pPlayer )
{
AngleVectors ( pPlayer - > EyeAngles ( ) , & vecForward ) ;
if ( DotProduct ( vecForward , vecAttach ) < 0.0f )
{
ShockDetach ( ) ;
SetFiringState ( ASW_TG_FIRE_DISCHARGE ) ;
break ;
}
}
2010-07-23 21:26:45 -05:00
if ( gpGlobals - > curtime > = m_flLastShockTime + GetFireRate ( ) )
2010-07-22 01:46:14 -05:00
{
ShockEntity ( ) ;
m_flLastShockTime = gpGlobals - > curtime ;
pMarine - > OnWeaponFired ( this , 1 ) ;
}
//if (m_iClip1 > 0) // only force the fire wait time if we have ammo for another shot
// m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate();
//else
m_flNextPrimaryAttack = gpGlobals - > curtime + GetFireRate ( ) ;
break ;
}
}
SendWeaponAnim ( GetPrimaryAttackActivity ( ) ) ;
SetWeaponIdleTime ( gpGlobals - > curtime + GetFireRate ( ) ) ;
# endif
m_fSlowTime = gpGlobals - > curtime + GetFireRate ( ) ;
}
2010-07-23 21:26:45 -05:00
float CASW_Weapon_Tesla_Gun : : GetWeaponDamage ( )
{
float flDamage = GetWeaponInfo ( ) - > m_flBaseDamage ;
if ( GetMarine ( ) )
{
flDamage + = MarineSkills ( ) - > GetSkillBasedValueByMarine ( GetMarine ( ) , ASW_MARINE_SKILL_ACCURACY , ASW_MARINE_SUBSKILL_ACCURACY_TESLA_CANNON_DMG ) ;
}
return flDamage ;
}
2010-07-22 01:46:14 -05:00
void CASW_Weapon_Tesla_Gun : : ShockEntity ( )
{
CASW_Marine * pMarine = GetMarine ( ) ;
EHANDLE hShockEntity = m_hShockEntity . Get ( ) ;
Assert ( hShockEntity & & hShockEntity - > m_takedamage ! = DAMAGE_NO & & pMarine ) ;
Vector vecDir = hShockEntity - > GetAbsOrigin ( ) - pMarine - > GetAbsOrigin ( ) ;
ClearMultiDamage ( ) ;
float flBaseDamage = GetWeaponDamage ( ) * g_pGameRules - > GetDamageMultiplier ( ) ;
CTakeDamageInfo info ( this , pMarine , flBaseDamage , DMG_SHOCK ) ;
info . SetWeapon ( this ) ;
CalculateMeleeDamageForce ( & info , vecDir , m_AttackTrace . endpos ) ;
# ifdef GAME_DLL
DoArcingShock ( flBaseDamage , hShockEntity . Get ( ) ) ;
# endif
// Whatever damage didn't get used for electricity arcing gets applied to a single target
info . SetDamage ( info . GetDamage ( ) + flBaseDamage ) ;
hShockEntity - > DispatchTraceAttack ( info , vecDir , & m_AttackTrace ) ;
ApplyMultiDamage ( ) ;
//Msg( "%f - Shocking target for %f\n", gpGlobals->curtime, info.GetDamage() + flBaseDamage );
# ifdef GAME_DLL
CASW_Alien * pTargetAlien = dynamic_cast < CASW_Alien * > ( hShockEntity . Get ( ) ) ;
if ( pTargetAlien )
{
pTargetAlien - > ForceFlinch ( pMarine - > GetAbsOrigin ( ) ) ;
}
# endif
// decrement ammo
m_iClip1 = MAX ( 0 , m_iClip1 - 1 ) ;
CPASFilter filter ( hShockEntity - > GetAbsOrigin ( ) ) ;
CBaseEntity : : EmitSound ( filter , SOUND_FROM_WORLD , " ASW_Tesla_Laser.Damage " , & hShockEntity - > GetAbsOrigin ( ) ) ;
}
# ifdef GAME_DLL
void CASW_Weapon_Tesla_Gun : : DoArcingShock ( float flBaseDamage , CBaseEntity * pLastShocked )
{
if ( ! GetOwner ( ) )
return ;
// search other enemies near this one
int iMaxArcs = 2 ; // TODO: max arc should be attribute of the weapon? if we can combine two attribs into one somehow
CUtlVector < CBaseEntity * > shocked ;
int iNumShocked = 0 ; // TODO: Use size of shocked vector for this?
shocked . AddToTail ( pLastShocked ) ;
float flArcDistSqr = ( GetWeaponRange ( ) / 1.5f ) * ( GetWeaponRange ( ) / 1.5f ) ;
float flShockDamage = flBaseDamage ; // TODO: base on attribute?
float flDamageReduction = flShockDamage / ( float ) iMaxArcs ; // how much damage each arc loses
Vector vecShockSrc = pLastShocked - > WorldSpaceCenter ( ) ;
//CBaseEntity *pLastShocked = pTarget;
//pLastShocked->EmitSound( "Electricity.Zap" );
//CASW_Alien *pAlien = dynamic_cast<CASW_Alien*>( pTarget );
//if ( pAlien )
// pAlien->ForceFlinch( vecShockPos );
for ( int k = 0 ; k < iMaxArcs ; k + + )
{
CAI_BaseNPC * * ppAIs = g_AI_Manager . AccessAIs ( ) ;
int nAIs = g_AI_Manager . NumAIs ( ) ;
bool bShocked = false ;
for ( int i = 0 ; i < nAIs ; i + + )
{
if ( shocked . Find ( ppAIs [ i ] ) ! = shocked . InvalidIndex ( ) ) // already shocked this guy
continue ;
if ( GetOwner ( ) - > IRelationType ( ppAIs [ i ] ) > = D_LI ) // friendly
continue ;
if ( ppAIs [ i ] - > GetAbsOrigin ( ) . DistToSqr ( vecShockSrc ) > flArcDistSqr ) // too far away
continue ;
// trace from the last shock position to this guy
trace_t shockTR ;
Vector vecAIPos = ppAIs [ i ] - > WorldSpaceCenter ( ) ;
CASWTraceFilterShot traceFilter ( this , pLastShocked , COLLISION_GROUP_NONE ) ;
AI_TraceLine ( vecShockSrc , vecAIPos , MASK_SHOT , & traceFilter , & shockTR ) ;
if ( shockTR . fraction ! = 1.0 & & shockTR . m_pEnt )
{
if ( GetOwner ( ) - > IRelationType ( shockTR . m_pEnt ) > = D_LI ) // friendly
continue ;
// shock this thing
vecAIPos = shockTR . endpos ;
CTakeDamageInfo shockDmgInfo ( this , this , flShockDamage , DMG_SHOCK ) ;
Vector vecDir = vecAIPos - vecShockSrc ;
VectorNormalize ( vecDir ) ;
ClearMultiDamage ( ) ;
shockDmgInfo . SetDamagePosition ( shockTR . endpos ) ;
shockDmgInfo . SetDamageForce ( vecDir ) ;
shockDmgInfo . ScaleDamageForce ( 1.0 ) ;
shockDmgInfo . SetWeapon ( this ) ;
shockTR . m_pEnt - > DispatchTraceAttack ( shockDmgInfo , vecDir , & shockTR ) ;
CASW_Alien * pAlien = dynamic_cast < CASW_Alien * > ( shockTR . m_pEnt ) ;
if ( pAlien )
pAlien - > ForceFlinch ( pLastShocked - > WorldSpaceCenter ( ) ) ;
// spawn a shock effect
CRecipientFilter filter ;
filter . AddAllPlayers ( ) ;
UserMessageBegin ( filter , " ASWEnemyTeslaGunArcShock " ) ;
WRITE_SHORT ( shockTR . m_pEnt - > entindex ( ) ) ;
WRITE_SHORT ( pLastShocked - > entindex ( ) ) ;
MessageEnd ( ) ;
vecShockSrc = vecAIPos ;
pLastShocked = shockTR . m_pEnt ;
bShocked = true ;
iNumShocked + + ;
// reduce shock damage as energy arcs
flShockDamage = MAX ( flShockDamage - flDamageReduction , 0.0f ) ;
break ;
}
}
if ( ! bShocked )
break ;
}
/*
if ( iNumShocked > 0 )
{
// Return reduced shock damage if we arced
info . SetDamage ( flShockDamage ) ;
} */
}
# endif //GAME_DLL
void CASW_Weapon_Tesla_Gun : : Fire ( const Vector & vecOrigSrc , const Vector & vecDir )
{
CASW_Marine * pMarine = GetMarine ( ) ;
if ( ! pMarine )
{
return ;
}
Vector vecDest = vecOrigSrc + ( vecDir * GetWeaponRange ( ) ) ;
Vector mins = Vector ( - ASW_TG_TRACE_SIZE , - ASW_TG_TRACE_SIZE , 0.0f ) ;
Vector maxs = Vector ( ASW_TG_TRACE_SIZE , ASW_TG_TRACE_SIZE , 12.0f ) ;
trace_t tr ;
//UTIL_TraceLine( vecOrigSrc, vecDest, MASK_SHOT, pMarine, COLLISION_GROUP_NONE, &tr );
UTIL_TraceHull ( vecOrigSrc , vecDest , mins , maxs , MASK_SHOT , pMarine , COLLISION_GROUP_NONE , & tr ) ;
# ifndef CLIENT_DLL
//QAngle angles;
//VectorAngles( vecDir, angles );
//if ( tr.DidHit() && tr.m_pEnt && tr.m_pEnt->IsNPC() )
//{
// NDebugOverlay::SweptBox( vecOrigSrc, tr.endpos, mins, maxs, angles, 0, 255, 0, 128, 5.0f );
//}
//else
//{
// //NDebugOverlay::Line( vecOrigSrc, tr.endpos, 0, 255, 0, true, 5.0f );
// NDebugOverlay::SweptBox( vecOrigSrc, (tr.m_pEnt && tr.m_pEnt->IsNPC()) ? tr.endpos : vecDest, mins, maxs, angles, 255, 0, 0, 128, 5.0f );
//}
# endif
if ( tr . allsolid )
return ;
CBaseEntity * pEntity = tr . m_pEnt ;
CASW_Marine * pTargetMarine = NULL ;
if ( pEntity )
{
pTargetMarine = CASW_Marine : : AsMarine ( pEntity ) ;
}
Vector vecUp , vecRight ;
QAngle angDir ;
VectorAngles ( vecDir , angDir ) ;
AngleVectors ( angDir , NULL , & vecRight , & vecUp ) ;
m_AttackTrace = tr ;
if ( ShockAttach ( pEntity ) )
{
SetFiringState ( ASW_TG_FIRE_ATTACHED ) ;
}
else if ( ! m_hShockEntity . Get ( ) )
{
// If we fail to hit something, and we're not shocking someone, we're just discharging onto the ground
SetFiringState ( ASW_TG_FIRE_DISCHARGE ) ;
}
# ifdef GAME_DLL
if ( pMarine & & m_iClip1 < = 0 & & pMarine - > GetAmmoCount ( m_iPrimaryAmmoType ) < = 0 )
{
// check he doesn't have ammo in an ammo bay
CASW_Weapon_Ammo_Bag * pAmmoBag = dynamic_cast < CASW_Weapon_Ammo_Bag * > ( pMarine - > GetASWWeapon ( 0 ) ) ;
if ( ! pAmmoBag )
pAmmoBag = dynamic_cast < CASW_Weapon_Ammo_Bag * > ( pMarine - > GetASWWeapon ( 1 ) ) ;
if ( ! pAmmoBag | | ! pAmmoBag - > CanGiveAmmoToWeapon ( this ) )
pMarine - > OnWeaponOutOfAmmo ( true ) ;
}
# endif
if ( tr . DidHit ( ) )
{
vecDest = tr . endpos ;
}
else
{
// Arc down to the ground with a bit of randomness
Vector down = 0.9f * Vector ( 0.0f , 0.0f , - 1.0f ) + 0.1f * RandomVector ( - 1.0 , 1.0 ) ;
// Trace down far enough to hit lower levels
UTIL_TraceLine ( vecDest , vecDest + GetWeaponRange ( ) * down * 2.0f , MASK_NPCSOLID_BRUSHONLY , pMarine , COLLISION_GROUP_NONE , & tr ) ;
// FIXME: if we really can't hit anything, just leave vecDest alone
if ( tr . DidHit ( ) )
{
vecDest = tr . endpos ;
}
}
m_vecShockPos = vecDest ;
}
bool CASW_Weapon_Tesla_Gun : : Reload ( void )
{
EndAttack ( ) ;
return BaseClass : : Reload ( ) ;
}
void CASW_Weapon_Tesla_Gun : : EndAttack ( void )
{
/*
Vector vecEjectPos , vecEjectPos2 ;
QAngle angEject , angEject2 ;
int iAttachment = LookupAttachment ( " eject1 " ) ;
GetAttachment ( iAttachment , vecEjectPos , angEject ) ;
unsigned char color [ 3 ] ;
color [ 0 ] = 50 ;
color [ 1 ] = 128 ;
color [ 2 ] = 50 ;
iAttachment = LookupAttachment ( " eject2 " ) ;
GetAttachment ( iAttachment , vecEjectPos2 , angEject2 ) ;
*/
# ifdef CLIENT_DLL
//FX_Smoke( vecEjectPos, angEject, 0.5, 5, &color[0], 192 );
//FX_Smoke( vecEjectPos2, angEject2, 0.5, 5, &color[0], 192 );
if ( m_pDischargeEffect )
{
m_pDischargeEffect - > StopEmission ( ) ;
}
# else
//CPVSFilter filter( vecEjectPos );
//te->Smoke( filter, 0.0, &vecEjectPos, g_sModelIndexSmoke, 0.5f, 10 );
//te->Smoke( filter, 0.0, &vecEjectPos2, g_sModelIndexSmoke, 0.5f, 10 );
# endif
SetWeaponIdleTime ( gpGlobals - > curtime + 2.0 ) ;
SetFiringState ( ASW_TG_FIRE_OFF ) ;
ShockDetach ( ) ;
ClearIsFiring ( ) ;
m_bIsFiring = false ;
}
void CASW_Weapon_Tesla_Gun : : Drop ( const Vector & vecVelocity )
{
EndAttack ( ) ;
BaseClass : : Drop ( vecVelocity ) ;
}
bool CASW_Weapon_Tesla_Gun : : Holster ( CBaseCombatWeapon * pSwitchingTo )
{
EndAttack ( ) ;
return BaseClass : : Holster ( pSwitchingTo ) ;
}
void CASW_Weapon_Tesla_Gun : : WeaponIdle ( void )
{
if ( ! HasWeaponIdleTimeElapsed ( ) )
return ;
if ( m_FireState ! = ASW_TG_FIRE_OFF )
{
EndAttack ( ) ;
}
float flIdleTime = gpGlobals - > curtime + 5.0 ;
SetWeaponIdleTime ( flIdleTime ) ;
}
bool CASW_Weapon_Tesla_Gun : : ShouldMarineMoveSlow ( )
{
return m_fSlowTime > gpGlobals - > curtime | | IsReloading ( ) ;
}
# ifdef CLIENT_DLL
void CASW_Weapon_Tesla_Gun : : ClientThink ( )
{
BaseClass : : ClientThink ( ) ;
UpdateEffects ( ) ;
}
const char * CASW_Weapon_Tesla_Gun : : GetPartialReloadSound ( int iPart )
{
switch ( iPart )
{
case 1 : return " ASW_MiningLaser.ReloadB " ; break ;
case 2 : return " ASW_MiningLaser.ReloadC " ; break ;
default : break ;
} ;
return " ASW_MiningLaser.ReloadA " ;
}
void CASW_Weapon_Tesla_Gun : : UpdateEffects ( )
{
switch ( m_FireState )
{
case ASW_TG_FIRE_OFF :
{
if ( m_pDischargeEffect )
{
m_pDischargeEffect - > StopEmission ( ) ;
m_pDischargeEffect = NULL ;
DispatchParticleEffect ( " mining_laser_exhaust " , PATTACH_POINT_FOLLOW , this , " eject1 " ) ;
}
break ;
}
case ASW_TG_FIRE_DISCHARGE :
{
if ( m_pDischargeEffect & & m_pDischargeEffect - > GetControlPointEntity ( 1 ) ! = NULL )
{
// Still attach, detach us
m_pDischargeEffect - > StopEmission ( ) ;
m_pDischargeEffect = NULL ;
}
if ( ! m_pDischargeEffect )
{
m_pDischargeEffect = ParticleProp ( ) - > Create ( " electric_weapon_shot_continuous_off " , PATTACH_POINT_FOLLOW , " muzzle " ) ;
}
m_pDischargeEffect - > SetControlPoint ( 1 , m_vecShockPos ) ;
Vector vecPos = m_vecShockPos . Get ( ) ;
//FX_MicroExplosion( vecPos, Vector(0,0,1) );
break ;
}
case ASW_TG_FIRE_ATTACHED :
{
EHANDLE hTarget = m_hShockEntity . Get ( ) ;
if ( ! hTarget )
{
break ;
}
if ( m_pDischargeEffect )
{
if ( m_pDischargeEffect - > GetControlPointEntity ( 1 ) ! = m_hShockEntity . Get ( ) )
{
m_pDischargeEffect - > StopEmission ( ) ;
m_pDischargeEffect = NULL ;
}
}
if ( ! m_pDischargeEffect )
{
m_pDischargeEffect = ParticleProp ( ) - > Create ( " electric_weapon_shot_continuous " , PATTACH_POINT_FOLLOW , " muzzle " ) ;
}
Assert ( m_pDischargeEffect ) ;
if ( m_pDischargeEffect - > GetControlPointEntity ( 1 ) = = NULL )
{
float flHeight = hTarget - > BoundingRadius ( ) ;
Vector vOffset ( 0.0f , 0.0f , flHeight * 0.25 ) ;
C_ASW_Alien * pAlien = dynamic_cast < C_ASW_Alien * > ( hTarget . Get ( ) ) ;
// TODO: get some standardization in the attachment naming
if ( pAlien & & pAlien - > LookupAttachment ( " eyes " ) )
{
ParticleProp ( ) - > AddControlPoint ( m_pDischargeEffect , 1 , pAlien , PATTACH_POINT_FOLLOW , " eyes " ) ;
}
else
{
ParticleProp ( ) - > AddControlPoint ( m_pDischargeEffect , 1 , hTarget , PATTACH_ABSORIGIN_FOLLOW , NULL , vOffset ) ;
}
}
break ;
}
}
}
# endif
# ifdef GAME_DLL
void CASW_Weapon_Tesla_Gun : : GetButtons ( bool & bAttack1 , bool & bAttack2 , bool & bReload , bool & bOldReload , bool & bOldAttack1 )
{
CASW_Marine * pMarine = GetMarine ( ) ;
// make AI fire this weapon whenever they have an enemy within a certain range
if ( pMarine & & ! pMarine - > IsInhabited ( ) )
{
bool bHasEnemy = ( pMarine - > GetEnemy ( ) & & pMarine - > GetEnemy ( ) - > GetAbsOrigin ( ) . DistTo ( pMarine - > GetAbsOrigin ( ) ) < 250.0f ) ;
if ( bHasEnemy )
m_fLastForcedFireTime = gpGlobals - > curtime ;
bAttack1 = ( bHasEnemy | | gpGlobals - > curtime < m_fLastForcedFireTime + 1.0f ) ; // fire for 2 seconds after killing our enemy
bAttack2 = false ;
bReload = false ;
bOldReload = false ;
return ;
}
BaseClass : : GetButtons ( bAttack1 , bAttack2 , bReload , bOldReload , bOldAttack1 ) ;
}
# endif
void CASW_Weapon_Tesla_Gun : : SetFiringState ( ASW_Weapon_TeslaGunFireState_t state )
{
# ifdef CLIENT_DLL
//Msg("[C] SetFiringState %d\n", state);
# else
//Msg("[C] SetFiringState %d\n", state);
# endif
// Check for transitions
if ( m_FireState ! = state )
{
if ( state = = ASW_TG_FIRE_DISCHARGE | | state = = ASW_TG_FIRE_ATTACHED )
{
EmitSound ( " ASW_Tesla_Laser.Loop " ) ;
}
else if ( state = = ASW_TG_FIRE_OFF )
{
StopSound ( " ASW_Tesla_Laser.Loop " ) ;
EmitSound ( " ASW_Tesla_Laser.Stop " ) ;
}
}
m_FireState = state ;
}
bool CASW_Weapon_Tesla_Gun : : ShockAttach ( CBaseEntity * pEntity )
{
# ifdef CLIENT_DLL
return false ;
# else
if ( ! pEntity | | ( pEntity - > m_takedamage = = DAMAGE_NO ) | |
( pEntity - > Classify ( ) = = CLASS_ASW_MARINE ) | | ( pEntity - > Classify ( ) = = CLASS_ASW_SENTRY_BASE ) | |
( pEntity = = m_hShockEntity . Get ( ) ) | | ( pEntity - > m_iHealth < = 0 ) | |
( pEntity = = GetMarine ( ) ) )
{
return false ;
}
if ( m_hShockEntity . Get ( ) )
{
ShockDetach ( ) ;
}
m_hShockEntity . Set ( pEntity ) ;
// we need a trace_t struct representing the entity we're shocking, but if we
// attached based on proximity to the end of the beam, we might not have actually performed a trace - for now just update m_AttackTrace
// but it'd be nice to decouple attribute damage from requiring a trace
if ( m_AttackTrace . m_pEnt ! = pEntity )
{
m_AttackTrace . endpos = pEntity - > GetAbsOrigin ( ) ;
m_AttackTrace . m_pEnt = pEntity ;
}
ASW_WPN_DEV_MSG ( " Attached to %d:%s \n " , m_hShockEntity . Get ( ) - > entindex ( ) , m_hShockEntity . Get ( ) - > GetClassname ( ) ) ;
return true ;
# endif
}
void CASW_Weapon_Tesla_Gun : : ShockDetach ( )
{
# ifdef GAME_DLL
ASW_WPN_DEV_MSG ( " Detaching from %d:%s \n " , m_hShockEntity . Get ( ) ? m_hShockEntity . Get ( ) - > entindex ( ) : - 1 , m_hShockEntity . Get ( ) ? m_hShockEntity . Get ( ) - > GetClassname ( ) : " (null) " ) ;
m_hShockEntity . Set ( NULL ) ;
# endif
}