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
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; |
|
} |