Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

388 lines
12 KiB

#include "cbase.h"
#include "asw_weapon.h"
#include "asw_marine.h"
#include "asw_player.h"
#include "in_buttons.h"
#include "asw_marine_skills.h"
#include "asw_marine_profile.h"
#include "asw_weapon_parse.h"
#include "util_shared.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
void* SendProxy_SendASWLocalWeaponDataTable( const SendProp *pProp, const void *pStruct, const void *pVarData, CSendProxyRecipients *pRecipients, int objectID )
{
// Get the weapon entity
CASW_Weapon *pWeapon = (CASW_Weapon*)pVarData;
if ( pWeapon )
{
// Only send this chunk of data to the commander of the marine carrying this weapon
CASW_Player *pPlayer = pWeapon->GetCommander();
if ( pPlayer )
{
pRecipients->SetOnly( pPlayer->GetClientIndex() );
}
else
{
pRecipients->ClearAllRecipients();
}
}
return (void*)pVarData;
}
REGISTER_SEND_PROXY_NON_MODIFIED_POINTER( SendProxy_SendASWLocalWeaponDataTable );
//-----------------------------------------------------------------------------
// Purpose: Only send to local player if this weapon is the active weapon and this marine is the active marine
// Input : *pStruct -
// *pVarData -
// *pRecipients -
// objectID -
// Output : void*
//-----------------------------------------------------------------------------
void* SendProxy_SendASWActiveLocalWeaponDataTable( const SendProp *pProp, const void *pStruct, const void *pVarData, CSendProxyRecipients *pRecipients, int objectID )
{
// Get the weapon entity
CASW_Weapon *pWeapon = (CASW_Weapon*)pVarData;
if ( pWeapon )
{
// Only send this chunk of data to the commander of the marine carrying this weapon
CASW_Player *pPlayer = pWeapon->GetCommander();
if ( pPlayer && pPlayer->GetMarine() == pWeapon->GetOwner() )
{
pRecipients->SetOnly( pPlayer->GetClientIndex() );
}
else
{
pRecipients->ClearAllRecipients();
}
}
return (void*)pVarData;
}
REGISTER_SEND_PROXY_NON_MODIFIED_POINTER( SendProxy_SendASWActiveLocalWeaponDataTable );
LINK_ENTITY_TO_CLASS( asw_weapon, CASW_Weapon );
BEGIN_NETWORK_TABLE_NOBASE( CASW_Weapon, DT_ASWLocalWeaponData )
SendPropIntWithMinusOneFlag( SENDINFO(m_iClip2 ), 8 ),
SendPropInt( SENDINFO(m_iSecondaryAmmoType ), 8 ),
SendPropFloat(SENDINFO(m_fReloadStart)),
SendPropFloat(SENDINFO(m_fFastReloadStart)),
SendPropFloat(SENDINFO(m_fFastReloadEnd)),
END_NETWORK_TABLE()
BEGIN_NETWORK_TABLE_NOBASE( CASW_Weapon, DT_ASWActiveLocalWeaponData )
SendPropTime( SENDINFO( m_flNextPrimaryAttack ) ),
SendPropTime( SENDINFO( m_flNextSecondaryAttack ) ),
SendPropInt( SENDINFO( m_nNextThinkTick ) ),
SendPropTime( SENDINFO( m_flTimeWeaponIdle ) ),
END_NETWORK_TABLE()
IMPLEMENT_SERVERCLASS_ST(CASW_Weapon, DT_ASW_Weapon)
SendPropExclude( "DT_BaseAnimating", "m_flPoseParameter" ),
SendPropExclude( "DT_BaseAnimating", "m_flPlaybackRate" ),
SendPropExclude( "DT_BaseAnimating", "m_nSequence" ),
SendPropExclude( "DT_BaseAnimatingOverlay", "overlay_vars" ),
SendPropExclude( "DT_ServerAnimationData" , "m_flCycle" ),
SendPropExclude( "DT_AnimTimeMustBeFirst" , "m_flAnimTime" ),
SendPropBool(SENDINFO(m_bIsFiring)),
SendPropBool(SENDINFO(m_bInReload)),
SendPropBool(SENDINFO(m_bSwitchingWeapons)),
SendPropExclude( "DT_BaseCombatWeapon", "LocalWeaponData" ),
SendPropExclude( "DT_BaseCombatWeapon", "LocalActiveWeaponData" ),
SendPropDataTable("ASWLocalWeaponData", 0, &REFERENCE_SEND_TABLE(DT_ASWLocalWeaponData), SendProxy_SendASWLocalWeaponDataTable ),
SendPropDataTable("ASWActiveLocalWeaponData", 0, &REFERENCE_SEND_TABLE(DT_ASWActiveLocalWeaponData), SendProxy_SendASWActiveLocalWeaponDataTable ),
SendPropBool(SENDINFO(m_bFastReloadSuccess)),
SendPropBool(SENDINFO(m_bFastReloadFailure)),
SendPropBool(SENDINFO(m_bPoweredUp)),
SendPropIntWithMinusOneFlag( SENDINFO(m_iClip1 ), 8 ),
SendPropInt( SENDINFO(m_iPrimaryAmmoType ), 8 ),
END_SEND_TABLE()
//---------------------------------------------------------
// Save/Restore
//---------------------------------------------------------
BEGIN_DATADESC( CASW_Weapon )
DEFINE_FIELD(m_iEquipmentListIndex, FIELD_INTEGER),
DEFINE_FIELD( m_bShotDelayed, FIELD_BOOLEAN ),
DEFINE_FIELD( m_flDelayedFire, FIELD_TIME ),
DEFINE_FIELD( m_fReloadStart, FIELD_TIME ),
DEFINE_FIELD( m_fFastReloadStart, FIELD_TIME ),
DEFINE_FIELD( m_fFastReloadEnd, FIELD_TIME ),
END_DATADESC()
ConVar asw_weapon_safety_hull("asw_weapon_safety_hull", "0", FCVAR_CHEAT, "Size of hull used to check for AI shots going too near a friendly");
extern ConVar asw_debug_alien_damage;
CASW_Weapon::CASW_Weapon()
{
SetPredictionEligible(true);
m_iEquipmentListIndex = -1;
m_bSwitchingWeapons = false;
m_fMinRange1 = 0;
m_fMaxRange1 = 512;
m_fMinRange2 = 0;
m_fMaxRange2 = 512;
m_bShotDelayed = 0;
m_flDelayedFire = 0;
m_fReloadClearFiringTime = 0;
m_flReloadFailTime = 1.0;
m_bFastReloadSuccess = false;
m_bFastReloadFailure = false;
m_bPoweredUp = false;
}
CASW_Weapon::~CASW_Weapon()
{
}
int CASW_Weapon::WeaponRangeAttack1Condition( float flDot, float flDist )
{
if (!IsOffensiveWeapon())
return COND_NO_WEAPON; // make sure the AI doesn't try to attack with this
if ( UsesPrimaryAmmo() && !HasPrimaryAmmo() )
{
return COND_NO_PRIMARY_AMMO;
}
else if ( flDist < m_fMinRange1)
{
return COND_TOO_CLOSE_TO_ATTACK;
}
else if (flDist > m_fMaxRange1)
{
return COND_TOO_FAR_TO_ATTACK;
}
return COND_CAN_RANGE_ATTACK1;
}
void CASW_Weapon::MarineDropped(CASW_Marine* pMarine)
{
ClearIsFiring();
}
int CASW_Weapon::UpdateTransmitState()
{
return SetTransmitState( FL_EDICT_ALWAYS );
}
int CASW_Weapon::ShouldTransmit( const CCheckTransmitInfo *pInfo )
{
// asw temp
return FL_EDICT_ALWAYS;
}
// railgun
/*
class CASW_Railgun_Beam : public CBaseEntity
{
DECLARE_SERVERCLASS();
DECLARE_CLASS( CASW_Railgun_Beam, CBaseEntity );
};
IMPLEMENT_SERVERCLASS_ST( CASW_Railgun_Beam, DT_ASW_Railgun_Beam )
END_SEND_TABLE()
*/
bool CASW_Weapon::ShouldAlienFlinch(CBaseEntity *pAlien, const CTakeDamageInfo &info)
{
if (!GetWeaponInfo())
return false;
float fFlinchChance = GetWeaponInfo()->m_fFlinchChance;
CASW_Marine *pMarine = dynamic_cast<CASW_Marine*>(GetOwner());
if (asw_debug_alien_damage.GetBool())
Msg("BaseFlinch chance %f ", fFlinchChance);
if (pMarine && pMarine->GetMarineProfile() && pMarine->GetMarineProfile()->GetMarineClass() == MARINE_CLASS_SPECIAL_WEAPONS)
{
// this is a special weapons marine, so we need to add our flinch bonus onto it
fFlinchChance += GetWeaponInfo()->m_fStoppingPowerFlinchBonus * MarineSkills()->GetSkillBasedValueByMarine(pMarine, ASW_MARINE_SKILL_STOPPING_POWER);
if (asw_debug_alien_damage.GetBool())
Msg("Boosted by specialweaps to %f ", fFlinchChance);
}
//CALL_ATTRIB_HOOK_FLOAT( fFlinchChance, mod_stopping );
if (pAlien)
{
int iHealth = pAlien->GetHealth();
int iDamage = info.GetDamage();
float fAlienHealth = float(iHealth + iDamage) / float(pAlien->GetMaxHealth());
fFlinchChance *= fAlienHealth;
if (asw_debug_alien_damage.GetBool())
Msg("adjusted by alien health (%f) to %f ", fAlienHealth, fFlinchChance);
}
float f = random->RandomFloat();
bool bResult = ( f < fFlinchChance);
if (asw_debug_alien_damage.GetBool())
Msg("random float is %f shouldflinch = %d\n", f, bResult);
return bResult;
}
//-----------------------------------------------------------------------------
// Purpose: Weapons ignore other weapons when LOS tracing
//-----------------------------------------------------------------------------
class CASWWeaponLOSFilter : public CTraceFilterSkipTwoEntities
{
DECLARE_CLASS( CASWWeaponLOSFilter, CTraceFilterSkipTwoEntities );
public:
CASWWeaponLOSFilter::CASWWeaponLOSFilter( IHandleEntity *pHandleEntity, IHandleEntity *pHandleEntity2, int collisionGroup ) :
CTraceFilterSkipTwoEntities( pHandleEntity, pHandleEntity2, collisionGroup )
{
}
virtual bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask )
{
CBaseEntity *pEntity = (CBaseEntity *)pServerEntity;
if ( pEntity->GetCollisionGroup() == COLLISION_GROUP_WEAPON )
return false;
return BaseClass::ShouldHitEntity( pServerEntity, contentsMask );
}
};
//-----------------------------------------------------------------------------
// Purpose: Check the weapon LOS for an owner at an arbitrary position
// If bSetConditions is true, LOS related conditions will also be set
//-----------------------------------------------------------------------------
bool CASW_Weapon::WeaponLOSCondition( const Vector &ownerPos, const Vector &targetPos, bool bSetConditions )
{
bool bHasLOS = BaseClass::WeaponLOSCondition(ownerPos, targetPos, bSetConditions);
// if the weapon has LOS, then do another wider trace to check we don't hit any friendlies
// this is to stop the AI marines shooting way too close to other marines, which stops the player thinking about positioning so much
if (bHasLOS && GetOwner() && asw_weapon_safety_hull.GetFloat() > 0)
{
CAI_BaseNPC* npcOwner = GetOwner()->MyNPCPointer();
Vector vecRelativeShootPosition;
VectorSubtract( npcOwner->Weapon_ShootPosition(), npcOwner->GetAbsOrigin(), vecRelativeShootPosition ); // Find its relative shoot position
Vector barrelPos = ownerPos + vecRelativeShootPosition;
CASWWeaponLOSFilter traceFilter( GetOwner(), npcOwner->GetEnemy(), COLLISION_GROUP_BREAKABLE_GLASS ); // Use the custom LOS trace filter
trace_t tr;
UTIL_TraceHull( barrelPos, targetPos, Vector(-asw_weapon_safety_hull.GetFloat(), -asw_weapon_safety_hull.GetFloat(), -asw_weapon_safety_hull.GetFloat()),
Vector(asw_weapon_safety_hull.GetFloat(), asw_weapon_safety_hull.GetFloat(), asw_weapon_safety_hull.GetFloat()), MASK_SHOT, &traceFilter, &tr );
if ( tr.fraction == 1.0 || tr.m_pEnt == npcOwner->GetEnemy() )
return true;
// if a friendly is in the way, then we report failure
CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( tr.m_pEnt );
if ( pBCC )
{
if ( npcOwner->IRelationType( pBCC ) == D_HT )
return true;
if ( bSetConditions )
{
npcOwner->SetCondition( COND_WEAPON_BLOCKED_BY_FRIEND );
}
return false;
}
}
return bHasLOS;
}
bool CASW_Weapon::DestroyIfEmpty( bool bDestroyWhenActive, bool bCheckSecondaryAmmo )
{
CASW_Marine *pMarine = GetMarine();
if ( !pMarine )
return false;
bool bActive = (pMarine->GetActiveASWWeapon() == this);
if ( bActive && !bDestroyWhenActive )
return false;
if ( bCheckSecondaryAmmo && (m_iClip2 || pMarine->GetAmmoCount(m_iSecondaryAmmoType) > 0) )
return false;
if ( !m_iClip1 && pMarine->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
{
#ifndef CLIENT_DLL
if (pMarine)
{
pMarine->Weapon_Detach(this);
if (bActive)
pMarine->SwitchToNextBestWeapon(NULL);
}
Kill();
return true;
#endif
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Drop/throw the weapon with the given velocity.
//-----------------------------------------------------------------------------
void CASW_Weapon::Drop( const Vector &vecVelocity )
{
StopAnimation();
StopFollowingEntity( );
SetMoveType( MOVETYPE_FLYGRAVITY );
// clear follow stuff, setup for collision
SetGravity(1.0);
m_iState = WEAPON_NOT_CARRIED;
RemoveEffects( EF_NODRAW );
FallInit();
SetGroundEntity( NULL );
SetTouch(NULL);
IPhysicsObject *pObj = VPhysicsGetObject();
if ( pObj != NULL )
{
AngularImpulse angImp( 200, 200, 200 );
pObj->AddVelocity( &vecVelocity, &angImp );
}
else
{
SetAbsVelocity( vecVelocity );
}
SetNextThink( gpGlobals->curtime + 1.0f );
SetOwnerEntity( NULL );
SetOwner( NULL );
SetModel( GetWorldModel() );
}
// player has used this item
void CASW_Weapon::ActivateUseIcon( CASW_Marine* pMarine, int nHoldType )
{
if ( nHoldType == ASW_USE_HOLD_START )
return;
pMarine->TakeWeaponPickup(this);
}
//-----------------------------------------------------------------------------
// Is anyone carrying it?
//-----------------------------------------------------------------------------
bool CASW_Weapon::IsBeingCarried() const
{
return ( GetOwner() != NULL );
}
//-----------------------------------------------------------------------------
bool CASW_Weapon::IsCarriedByLocalPlayer()
{
if ( gpGlobals->maxClients <= 1 && !engine->IsDedicatedServer() )
{
CASW_Marine *pMarine = dynamic_cast<CASW_Marine*>( GetOwner() );
return ( pMarine && pMarine->IsInhabited() && pMarine->GetCommander() == UTIL_GetListenServerHost() );
}
return false;
}