sqwarmed/sdk_src/game/shared/swarm/asw_weapon_railgun_shared.cpp

740 lines
23 KiB
C++

#include "cbase.h"
#include "asw_weapon_railgun_shared.h"
#include "in_buttons.h"
#ifdef CLIENT_DLL
#define CASW_Weapon C_ASW_Weapon
#define CASW_Marine C_ASW_Marine
#define CBasePlayer C_BasePlayer
#include "c_asw_player.h"
#include "c_asw_weapon.h"
#include "c_asw_marine.h"
#include "c_asw_railgun_beam.h"
#include "iviewrender_beams.h"
#include "c_asw_marine_resource.h"
#include "precache_register.h"
#include "c_te_effect_dispatch.h"
#else
#include "asw_lag_compensation.h"
#include "asw_marine.h"
#include "asw_player.h"
#include "asw_weapon.h"
#include "npcevent.h"
#include "shot_manipulator.h"
#include "te_effect_dispatch.h"
#include "asw_marine_resource.h"
#include "asw_marine_speech.h"
#include "decals.h"
#include "ammodef.h"
#include "asw_weapon_ammo_bag_shared.h"
#include "asw_rocket.h"
#endif
#include "asw_marine_skills.h"
#include "asw_weapon_parse.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//#define ASW_RAILGUN_SWEEP_STYLE 1 // makes railgun do hull sweep style damage
//#define ASW_RAILGUN_WIDE_SWEEP 1 // makes railgun do a wide low damage sweep in addition to the above
#define ASW_RAILGUN_BURST_COUNT 3 // how many bullets are fired in each burst
#define ASW_RAILGUN_BURST_INTERVAL 0.12f // time between each bullet in a burst
IMPLEMENT_NETWORKCLASS_ALIASED( ASW_Weapon_Railgun, DT_ASW_Weapon_Railgun )
BEGIN_NETWORK_TABLE( CASW_Weapon_Railgun, DT_ASW_Weapon_Railgun )
#ifdef CLIENT_DLL
// recvprops
RecvPropTime( RECVINFO( m_fSlowTime ) ),
RecvPropInt(RECVINFO(m_iRailBurst)),
#else
// sendprops
SendPropTime( SENDINFO( m_fSlowTime ) ),
SendPropInt( SENDINFO(m_iRailBurst), Q_log2( ASW_RAILGUN_BURST_COUNT ) + 1, SPROP_UNSIGNED ),
#endif
END_NETWORK_TABLE()
#ifdef CLIENT_DLL
BEGIN_PREDICTION_DATA( CASW_Weapon_Railgun )
DEFINE_PRED_FIELD_TOL( m_fSlowTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, TD_MSECTOLERANCE ),
DEFINE_PRED_FIELD( m_iRailBurst, FIELD_INTEGER, FTYPEDESC_INSENDTABLE )
END_PREDICTION_DATA()
#endif
LINK_ENTITY_TO_CLASS( asw_weapon_railgun, CASW_Weapon_Railgun );
PRECACHE_WEAPON_REGISTER(asw_weapon_railgun);
extern ConVar asw_weapon_max_shooting_distance;
ConVar asw_railgun_force_scale("asw_railgun_force_scale", "60.0f", FCVAR_REPLICATED, "Force of railgun shots");
#ifndef CLIENT_DLL
extern ConVar asw_debug_marine_damage;
//---------------------------------------------------------
// Save/Restore
//---------------------------------------------------------
BEGIN_DATADESC( CASW_Weapon_Railgun )
END_DATADESC()
#else
//Precache the effects
PRECACHE_REGISTER_BEGIN( GLOBAL, ASWPrecacheEffectRailgun )
PRECACHE( MATERIAL, "swarm/effects/railgun" )
PRECACHE_REGISTER_END()
#endif /* not client */
CASW_Weapon_Railgun::CASW_Weapon_Railgun()
{
m_fSlowTime = 0;
m_iRailBurst = 0;
}
CASW_Weapon_Railgun::~CASW_Weapon_Railgun()
{
}
void CASW_Weapon_Railgun::Precache()
{
PrecacheModel("swarm/effects/railgun.vmt");
PrecacheScriptSound("ASW_Railgun.Single");
BaseClass::Precache();
}
#define MAX_GLASS_PENETRATION_DEPTH 16.0f
extern short g_sModelIndexFireball; // (in combatweapon.cpp) holds the index for the smoke cloud
void CASW_Weapon_Railgun::PrimaryAttack()
{
// If my clip is empty (and I use clips) start reload
if ( UsesClipsForAmmo1() && !m_iClip1 )
{
Reload();
return;
}
CASW_Player *pPlayer = GetCommander();
CASW_Marine *pMarine = GetMarine();
if (!pMarine) // firing from a marine
return;
#ifndef CLIENT_DLL
//Msg("[S] Railgun PrimaryAttack time=%f\n", gpGlobals->curtime);
#else
//Msg("[C] Railgun PrimaryAttack time=%f\n", gpGlobals->curtime);
#endif
m_iRailBurst = 1; // disable burst firing..
//if (m_iRailBurst <= 0)
//m_iRailBurst = ASW_RAILGUN_BURST_COUNT;
// MUST call sound before removing a round from the clip of a CMachineGun
WeaponSound(SINGLE);
m_bIsFiring = true;
// tell the marine to tell its weapon to draw the muzzle flash
pMarine->DoMuzzleFlash();
// sets the animation on the weapon model iteself
SendWeaponAnim( GetPrimaryAttackActivity() );
// sets the animation on the marine holding this weapon
//pMarine->SetAnimation( PLAYER_ATTACK1 );
#ifdef GAME_DLL // check for turning on lag compensation
if (pPlayer && pMarine->IsInhabited())
{
CASW_Lag_Compensation::RequestLagCompensation( pPlayer, pPlayer->GetCurrentUserCommand() );
}
#endif
FireBulletsInfo_t info;
info.m_vecSrc = pMarine->Weapon_ShootPosition( );
if ( pPlayer && pMarine->IsInhabited() )
{
info.m_vecDirShooting = pPlayer->GetAutoaimVectorForMarine(pMarine, GetAutoAimAmount(), GetVerticalAdjustOnlyAutoAimAmount()); // 45 degrees = 0.707106781187
}
else
{
#ifdef CLIENT_DLL
Msg("Error, clientside firing of a weapon that's being controlled by an AI marine\n");
#else
info.m_vecDirShooting = pMarine->GetActualShootTrajectory( info.m_vecSrc );
#endif
}
// To make the firing framerate independent, we may have to fire more than one bullet here on low-framerate systems,
// especially if the weapon we're firing has a really fast rate of fire.
info.m_iShots = 0;
float fireRate = GetFireRate();
if (m_iRailBurst > 1)
fireRate = ASW_RAILGUN_BURST_INTERVAL;
//float current_attack_time = m_flNextPrimaryAttack;
//float attack_delta = gpGlobals->curtime - current_attack_time;
while ( m_flNextPrimaryAttack <= gpGlobals->curtime )
{
if (m_iRailBurst == 0) // this loop could fire all our burst rounds in one go, se chcek for resetting it up
m_iRailBurst = ASW_RAILGUN_BURST_COUNT;
m_flNextPrimaryAttack = m_flNextPrimaryAttack + fireRate;
#ifndef CLIENT_DLL
//Msg("[S] Set m_flNextPrimaryAttack to %f Firerate=%f curtime=%f\n", m_flNextPrimaryAttack.Get(), fireRate, gpGlobals->curtime);
#else
//Msg("[C] Set m_flNextPrimaryAttack to %f Firerate=%f curtime=%f\n", m_flNextPrimaryAttack.Get(), fireRate, gpGlobals->curtime);
#endif
info.m_iShots++;
m_iRailBurst--;
// recalc the fire rate as our burst var can change it
fireRate = GetFireRate();
if (m_iRailBurst > 1)
fireRate = ASW_RAILGUN_BURST_INTERVAL;
if ( !fireRate )
break;
}
// Make sure we don't fire more than the amount in the clip
if ( UsesClipsForAmmo1() )
{
info.m_iShots = MIN( info.m_iShots, m_iClip1 );
m_iClip1 -= info.m_iShots;
#ifdef GAME_DLL
CASW_Marine *pMarine = GetMarine();
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
}
else
{
info.m_iShots = MIN( info.m_iShots, pMarine->GetAmmoCount( m_iPrimaryAmmoType ) );
pMarine->RemoveAmmo( info.m_iShots, m_iPrimaryAmmoType );
}
info.m_flDistance = asw_weapon_max_shooting_distance.GetFloat();
info.m_iAmmoType = m_iPrimaryAmmoType;
info.m_iTracerFreq = 1;
info.m_flDamage = GetWeaponDamage();
#ifndef CLIENT_DLL
if (asw_debug_marine_damage.GetBool())
Msg("Weapon dmg = %f\n", info.m_flDamage);
info.m_flDamage *= pMarine->GetMarineResource()->OnFired_GetDamageScale();
#endif
info.m_vecSpread = pMarine->GetActiveWeapon()->GetBulletSpread();
info.m_flDamageForceScale = asw_railgun_force_scale.GetFloat();
//float max_dist = asw_weapon_max_shooting_distance.GetFloat();
//inline void UTIL_TraceLine( const Vector& vecAbsStart, const Vector& vecAbsEnd, unsigned int mask,
//const IHandleEntity *ignore, int collisionGroup, trace_t *ptr )
// find impact point of the RG shot
#ifdef ASW_RAILGUN_SWEEP_STYLE
trace_t tr;
UTIL_TraceLine(info.m_vecSrc, info.m_vecSrc + info.m_vecDirShooting * max_dist, MASK_SOLID_BRUSHONLY, pMarine, COLLISION_GROUP_NONE, &tr);
if (!tr.startsolid)
{
#ifndef CLIENT_DLL
bool bHitGlass = false;
if ( tr.m_pEnt != NULL )
{
Msg("trace hit something\n");
surfacedata_t *psurf = physprops->GetSurfaceData( tr.surface.surfaceProps );
if (psurf != NULL)
{
Msg("psurf isn't null. mat = %d glass = %d class = %s match = %d\n", psurf->game.material, CHAR_TEX_GLASS, tr.m_pEnt->GetClassname(), tr.m_pEnt->ClassMatches( "CBreakableSurface" ));
}
if ( ( psurf != NULL ) && ( psurf->game.material == CHAR_TEX_GLASS ) && ( tr.m_pEnt->ClassMatches( "CBreakableSurface" ) ) )
{
Msg("so this is a glass hit\n");
bHitGlass = true;
}
}
int glassCount = 10;
while (bHitGlass && glassCount > 0)
{
Msg("hit glass\n");
bHitGlass = false;
glassCount--;
// Move through the glass until we're at the other side
Vector testPos = tr.endpos + ( info.m_vecDirShooting * MAX_GLASS_PENETRATION_DEPTH );
CEffectData data;
data.m_vNormal = tr.plane.normal;
data.m_vOrigin = tr.endpos;
DispatchEffect( "GlassImpact", data );
trace_t penetrationTrace;
UTIL_TraceLine(testPos, tr.endpos, MASK_SHOT, pMarine, COLLISION_GROUP_NONE, &penetrationTrace);
// See if we found the surface again
if ( !penetrationTrace.startsolid && tr.fraction != 0.0f && penetrationTrace.fraction != 1.0f )
{
// Impact the other side (will look like an exit effect)
DoImpactEffect( penetrationTrace, GetAmmoDef()->DamageType(info.m_iAmmoType) );
data.m_vNormal = penetrationTrace.plane.normal;
data.m_vOrigin = penetrationTrace.endpos;
DispatchEffect( "GlassImpact", data );
// continue trace past the glass
UTIL_TraceLine(penetrationTrace.endpos, penetrationTrace.endpos + info.m_vecDirShooting * max_dist, MASK_SOLID_BRUSHONLY, pMarine, COLLISION_GROUP_NONE, &tr);
if ( tr.m_pEnt != NULL )
{
surfacedata_t *psurf = physprops->GetSurfaceData( tr.surface.surfaceProps );
if ( ( psurf != NULL ) && ( psurf->game.material == CHAR_TEX_GLASS ) && ( tr.m_pEnt->ClassMatches( "func_breakable" ) ) )
{
bHitGlass = true;
}
}
}
}
Vector vecEndPos = tr.endpos;
trace_t ptr;
//CTakeDamageInfo( CBaseEntity *pInflictor, CBaseEntity *pAttacker, float flDamage, int bitsDamageType, int iKillType = 0 );
//CTakeDamageInfo( CBaseEntity *pInflictor, CBaseEntity *pAttacker, const Vector &damageForce, const Vector &damagePosition, float flDamage, int bitsDamageType, int iKillType = 0, Vector *reportedPosition = NULL );
// do close high damage FF damaging trace
CTakeDamageInfo dmg(this, pMarine, Vector(0,0,0), GetAbsOrigin(), GetWeaponDamage(), DMG_SONIC); // | DMG_ALWAYSGIB
CTraceFilterRG traceFilter( pMarine, COLLISION_GROUP_NONE, &dmg, true );
Vector vecMin(-3, -3, -3);
Vector vecMax(3, 3, 3);
UTIL_TraceHull( info.m_vecSrc, vecEndPos, vecMin, vecMax,
CONTENTS_MONSTER, &traceFilter, &ptr );
// do wide less damaging sweep
#ifdef ASW_RAILGUN_WIDE_SWEEP
CTakeDamageInfo wdmg(this, pMarine, Vector(0,0,0), GetAbsOrigin(), GetWeaponDamage() * 0.33f, DMG_SONIC); // | DMG_ALWAYSGIB
CTraceFilterRG wtraceFilter( pMarine, COLLISION_GROUP_NONE, &wdmg, false );
Vector vecWMin(-15, -15, -15);
Vector vecWMax(15, 15, 15);
UTIL_TraceHull( info.m_vecSrc, vecEndPos, vecWMin, vecWMax,
CONTENTS_MONSTER, &wtraceFilter, &ptr );
#endif // ASW_RAILGUN_WIDE_SWEEP
#endif // CLIENT_DLL
//CreateRailgunBeam(GetAbsOrigin(), tr.endpos);
}
#else
//trace_t tr;
//UTIL_TraceLine(info.m_vecSrc, info.m_vecSrc + info.m_vecDirShooting * max_dist, MASK_SHOT, pMarine, COLLISION_GROUP_NONE, &tr);
//Vector vecExplosionPos = tr.endpos;
//CPASFilter filter( vecExplosionPos );
/*te->Explosion( filter, 0.1, // IRecipientFilter& filter, float delay
&vecExplosionPos, // pos
g_sModelIndexFireball, // modelindex
0.1, // scale
1, // framerate
TE_EXPLFLAG_NONE, // flags
0.5, // radius
0.5 ); // magnitude
*/
pMarine->FirePenetratingBullets( info, 10, 1.0f, 0, true, NULL, false );
//pMarine->FireBullets( info );
#endif // ASW_RAILGUN_SWEEP_STYLE
// increment shooting stats
#ifndef CLIENT_DLL
if (pMarine && pMarine->GetMarineResource())
{
pMarine->GetMarineResource()->UsedWeapon(this, info.m_iShots);
pMarine->OnWeaponFired( this, info.m_iShots );
}
#endif
if (!m_iClip1 && pMarine->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
{
// HEV suit - indicate out of ammo condition
if (pPlayer)
pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
}
m_fSlowTime = gpGlobals->curtime + 0.1f;
}
// creates a translucent beam effect coming out from the gun
void CASW_Weapon_Railgun::CreateRailgunBeam( const Vector &vecStartPoint, const Vector &vecEndPoint )
{
//Vector vecEndPoint = info.m_vecSrc + info.m_vecDirShooting * 1000;
//Vector vecStartPoint = GetAbsOrigin();
CASW_Marine* pOwner = GetMarine();
if (!pOwner)
return;
CEffectData data;
data.m_vStart = vecStartPoint;
data.m_vOrigin = vecEndPoint;
data.m_fFlags |= TRACER_FLAG_USEATTACHMENT;
data.m_nAttachmentIndex = LookupAttachment("muzzle");
#ifdef CLIENT_DLL
data.m_hEntity = this;
#else
data.m_nEntIndex = entindex();
#endif
CPASFilter filter( data.m_vOrigin );
#ifndef CLIENT_DLL
if (gpGlobals->maxClients > 1 && pOwner->IsInhabited() && pOwner->GetCommander())
{
// multiplayer game, where this marine is currently being controlled by a client, who will spawn his own effect
// so just make the beam effect for all other clients
filter.RemoveRecipient(pOwner->GetCommander());
}
#endif
DispatchEffect(filter, 0.0, "RailgunBeam", data );
return;
/*
#ifdef CLIENT_DLL
QAngle muzzleAngles;
GetAttachment( LookupAttachment("muzzle"), vecStartPoint, muzzleAngles );
// create a railgun beam (it'll fade out and kill itself after a short period)
C_ASW_Railgun_Beam *pBeam = new C_ASW_Railgun_Beam();
if (pBeam)
{
if (pBeam->InitializeAsClientEntity( NULL, false ))
{
pBeam->InitBeam(vecStartPoint, vecEndPoint);
}
else
{
pBeam->Release();
}
}*/
/*
// Draw a beam
BeamInfo_t beamInfo;
beamInfo.m_pStartEnt = this;
beamInfo.m_nStartAttachment = 1;
beamInfo.m_pEndEnt = NULL;
beamInfo.m_nEndAttachment = -1;
beamInfo.m_vecStart = vec3_origin;
beamInfo.m_vecEnd = vecEndPoint;
beamInfo.m_pszModelName = "swarm/effects/railgun.vmt";
beamInfo.m_flHaloScale = 0.0f;
beamInfo.m_flLife = 0.1f;
beamInfo.m_flWidth = 12.0f;
beamInfo.m_flEndWidth = 4.0f;
beamInfo.m_flFadeLength = 0.0f;
beamInfo.m_flAmplitude = 0;
beamInfo.m_flBrightness = 255.0;
beamInfo.m_flSpeed = 0.0f;
beamInfo.m_nStartFrame = 0.0;
beamInfo.m_flFrameRate = 0.0;
beamInfo.m_flRed = 255.0;
beamInfo.m_flGreen = 255.0;
beamInfo.m_flBlue = 255.0;
beamInfo.m_nSegments = 16;
beamInfo.m_bRenderable = true;
beamInfo.m_nFlags = FBEAM_ONLYNOISEONCE | FBEAM_SOLID;
beams->CreateBeamEntPoint( beamInfo );
*/
/*
#else
CASW_Marine* pOwner = GetMarine();
if (!pOwner)
return;
CEffectData data;
data.m_vStart = vecStartPoint;
data.m_vOrigin = vecEndPoint;
data.m_fFlags |= TRACER_FLAG_USEATTACHMENT;
data.m_nAttachmentIndex = LookupAttachment("muzzle");
data.m_nEntIndex = entindex();
CPASFilter filter( data.m_vOrigin );
if (gpGlobals->maxClients > 1 && pOwner->IsInhabited() && pOwner->GetCommander())
{
// multiplayer game, where this marine is currently being controlled by a client, who will spawn his own effect
// so just make the beam effect for all other clients
filter.RemoveRecipient(pOwner->GetCommander());
}
te->DispatchEffect( filter, 0.0, data.m_vOrigin, "RailgunBeam", data );
#endif*/
}
bool CASW_Weapon_Railgun::ShouldMarineMoveSlow()
{
return BaseClass::ShouldMarineMoveSlow();
//return m_fSlowTime > gpGlobals->curtime;
}
float CASW_Weapon_Railgun::GetMovementScale()
{
return ShouldMarineMoveSlow() ? 0.75f : 1.0f;
}
bool CASW_Weapon_Railgun::Reload()
{
m_iRailBurst = 0;
bool bReloaded = ASWReload( GetMaxClip1(), GetMaxClip2(), ACT_VM_RELOAD );
// skip reload chatter on the railgun, since it reloads after every shot
/*
if (bReloaded)
{
#ifdef GAME_DLL
CASW_Marine *pMarine = GetMarine();
if (pMarine)
{
if (pMarine->IsAlienNear())
{
//Msg("potentially reload chattering as there is an alien near\n");
pMarine->GetMarineSpeech()->Chatter(CHATTER_RELOADING);
}
else
{
//Msg("Not reload chattering as there's no aliens near\n");
}
}
#endif
}
*/
return bReloaded;
}
bool CASW_Weapon_Railgun::Holster( CBaseCombatWeapon *pSwitchingTo )
{
m_iRailBurst = 0;
return BaseClass::Holster( pSwitchingTo );
}
void CASW_Weapon_Railgun::GetButtons(bool& bAttack1, bool& bAttack2, bool& bReload, bool& bOldReload, bool& bOldAttack1 )
{
BaseClass::GetButtons(bAttack1, bAttack2, bReload, bOldReload, bOldAttack1 );
// make sure the fire button stays held down until our burst is clear
CASW_Marine *pMarine = GetMarine();
if (m_iRailBurst > 0 && !(pMarine && pMarine->GetFlags() & FL_FROZEN))
bAttack1 = true;
}
bool CASW_Weapon_Railgun::SupportsBayonet()
{
return true;
}
float CASW_Weapon_Railgun::GetWeaponDamage()
{
//float flDamage = 35.0f;
float flDamage = GetWeaponInfo()->m_flBaseDamage;
if ( GetMarine() )
{
flDamage += MarineSkills()->GetSkillBasedValueByMarine(GetMarine(), ASW_MARINE_SKILL_ACCURACY, ASW_MARINE_SUBSKILL_ACCURACY_RAILGUN_DMG);
}
//CALL_ATTRIB_HOOK_FLOAT( flDamage, mod_damage_done );
return flDamage;
}
int CASW_Weapon_Railgun::ASW_SelectWeaponActivity(int idealActivity)
{
switch( idealActivity )
{
case ACT_WALK: idealActivity = ACT_WALK_AIM_RIFLE; break;
case ACT_RUN: idealActivity = ACT_RUN_AIM_RIFLE; break;
case ACT_IDLE: idealActivity = ACT_IDLE_RIFLE; break;
case ACT_RELOAD: idealActivity = ACT_RELOAD; break;
default: break;
}
return idealActivity;
}
#ifndef CLIENT_DLL
bool CTraceFilterRG::ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask )
{
if ( !StandardFilterRules( pHandleEntity, contentsMask ) )
return false;
if ( !PassServerEntityFilter( pHandleEntity, m_pPassEnt ) )
return false;
// Don't test if the game code tells us we should ignore this collision...
CBaseEntity *pEntity = EntityFromEntityHandle( pHandleEntity );
if ( pEntity )
{
if ( !pEntity->ShouldCollide( m_collisionGroup, contentsMask ) )
return false;
if ( !g_pGameRules->ShouldCollide( m_collisionGroup, pEntity->GetCollisionGroup() ) )
return false;
if ( pEntity->m_takedamage == DAMAGE_NO )
return false;
Vector attackDir = pEntity->WorldSpaceCenter() - m_dmgInfo->GetAttacker()->WorldSpaceCenter();
VectorNormalize( attackDir );
CTakeDamageInfo info = (*m_dmgInfo);
CalculateMeleeDamageForce( &info, attackDir, info.GetAttacker()->WorldSpaceCenter(), 1.0f );
CBaseCombatCharacter *pBCC = info.GetAttacker()->MyCombatCharacterPointer();
CBaseCombatCharacter *pVictimBCC = pEntity->MyCombatCharacterPointer();
// Only do these comparisons between NPCs
if ( pBCC && pVictimBCC )
{
// Can only damage other NPCs that we hate
if ( m_bFFDamage || pBCC->IRelationType( pEntity ) == D_HT )
{
if ( info.GetDamage() )
{
pEntity->TakeDamage( info );
}
// Put a combat sound in
CSoundEnt::InsertSound( SOUND_COMBAT, info.GetDamagePosition(), 200, 0.2f, info.GetAttacker() );
m_pHit = pEntity;
return true;
}
}
else
{
// Make sure if the player is holding this, he drops it
Pickup_ForcePlayerToDropThisObject( pEntity );
// Otherwise just damage passive objects in our way
if ( info.GetDamage() )
{
pEntity->TakeDamage( info );
}
}
}
return false;
}
#endif
void CASW_Weapon_Railgun::SecondaryAttack()
{
// Only the player fires this way so we can cast
CASW_Player *pPlayer = GetCommander();
if (!pPlayer)
return;
CASW_Marine *pMarine = GetMarine();
if (!pMarine)
return;
// dry fire - no secondary enabled on RG (below rocket stuff is an experiment)
SendWeaponAnim( ACT_VM_DRYFIRE );
BaseClass::WeaponSound( EMPTY );
m_flNextSecondaryAttack = gpGlobals->curtime + 0.5f;
return;
//Must have ammo - temp comment
//bool bUsesSecondary = UsesSecondaryAmmo();
bool bUsesClips = UsesClipsForAmmo2();
//int iAmmoCount = pMarine->GetAmmoCount(m_iSecondaryAmmoType);
//bool bInWater = ( pMarine->GetWaterLevel() == 3 );
/*
if ( (bUsesSecondary &&
( ( bUsesClips && m_iClip2 <= 0) ||
( !bUsesClips && iAmmoCount<=0 )
) )
|| bInWater || m_bInReload )
{
SendWeaponAnim( ACT_VM_DRYFIRE );
BaseClass::WeaponSound( EMPTY );
m_flNextSecondaryAttack = gpGlobals->curtime + 0.5f;
return;
}
*/
// MUST call sound before removing a round from the clip of a CMachineGun
BaseClass::WeaponSound( SPECIAL1 );
Vector vecSrc = pMarine->Weapon_ShootPosition();
Vector vecThrow;
// Don't autoaim on grenade tosses
vecThrow = pPlayer->GetAutoaimVectorForMarine(pMarine, GetAutoAimAmount(), GetVerticalAdjustOnlyAutoAimAmount()); // 45 degrees = 0.707106781187
QAngle angGrenFacing;
VectorAngles(vecThrow, angGrenFacing);
VectorScale( vecThrow, 1000.0f, vecThrow );
#ifndef CLIENT_DLL
//Create the grenade
/*
float fGrenadeDamage = MarineSkills()->GetSkillBasedValueByMarine(pMarine, ASW_MARINE_SKILL_GRENADES, ASW_MARINE_SUBSKILL_GRENADE_DMG);
float fGrenadeRadius = MarineSkills()->GetSkillBasedValueByMarine(pMarine, ASW_MARINE_SKILL_GRENADES, ASW_MARINE_SUBSKILL_GRENADE_RADIUS);
if (asw_debug_marine_damage.GetBool())
{
Msg("Grenade damage = %f radius = %f\n", fGrenadeDamage, fGrenadeRadius);
}
CASW_Grenade_PRifle::PRifle_Grenade_Create(
fGrenadeDamage,
fGrenadeRadius,
vecSrc, angGrenFacing, vecThrow, AngularImpulse(0,0,0), pMarine );
*/
const int num_rockets = 5;
const int fan_spread = 90;
for (int i=0;i<num_rockets;i++)
{
int angle = (-fan_spread * 0.5f) + float(fan_spread) * (float(i) / float(num_rockets));
QAngle vecRocketAngle = angGrenFacing;
vecRocketAngle[YAW] += angle;
//CASW_Rocket::Create(vecSrc, vecRocketAngle, GetMarine());
}
#endif
SendWeaponAnim( ACT_VM_SECONDARYATTACK );
if ( bUsesClips )
{
m_iClip2 -= 1;
}
else
{
pMarine->RemoveAmmo( 1, m_iSecondaryAmmoType );
}
// Can shoot again immediately
m_flNextPrimaryAttack = gpGlobals->curtime + 0.5f;
// Can blow up after a short delay (so have time to release mouse button)
m_flNextSecondaryAttack = gpGlobals->curtime + 1.0f;
}
float CASW_Weapon_Railgun::GetFireRate()
{
//float flRate = 0.1f;
float flRate = GetWeaponInfo()->m_flFireRate;
//CALL_ATTRIB_HOOK_FLOAT( flRate, mod_fire_rate );
return flRate;
}