📄 weapon_repairgun.cpp
字号:
//=========== (C) Copyright 2000 Valve, L.L.C. All rights reserved. ===========
//
// The copyright to the contents herein is the property of Valve, L.L.C.
// The contents may be used and/or copied only with the written permission of
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
// the agreement/contract under which the contents have been supplied.
//
// Purpose: The Medic's Medikit weapon
//
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//=============================================================================
#include "cbase.h"
#include "basetfplayer_shared.h"
#include "in_buttons.h"
#include "weapon_combatshield.h"
#include "engine/ienginesound.h"
#include "grenade_base_empable.h"
#include "basetfvehicle.h"
#include "tf_gamerules.h"
//#define REPAIR_GUN_DISABLES_GRENADES // Uncomment if you want the repair gun to disable grenades.
#if defined( CLIENT_DLL )
#include "particles_simple.h"
#else
#include "ndebugoverlay.h"
#endif
#include "weapon_repairgun.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// Buff ranges
ConVar weapon_repairgun_target_range( "weapon_repairgun_target_range", "450", FCVAR_REPLICATED, "The farthest away you can be for the repair gun to initially lock onto a player." );
ConVar weapon_repairgun_stick_range( "weapon_repairgun_stick_range", "512", FCVAR_REPLICATED, "How far away the repair gun can stay locked onto someone." );
ConVar weapon_repairgun_rate( "weapon_repairgun_rate", "12", FCVAR_REPLICATED, "Health healed per second by the repair gun." );
ConVar weapon_repairgun_damage_modifier( "weapon_repairgun_damage_modifier", "1.5", FCVAR_REPLICATED, "Scales the damage a player does while being healed with the repair gun." );
ConVar weapon_repairgun_debug( "weapon_repairgun_debug", "0", FCVAR_REPLICATED, "Show debugging info for the repair gun." );
ConVar weapon_repairgun_construction_rate( "weapon_repairgun_construction_rate", "10", FCVAR_REPLICATED, "Constructing object health healed per second by the repair gun." );
LINK_ENTITY_TO_CLASS( weapon_repairgun, CWeaponRepairGun );
PRECACHE_WEAPON_REGISTER( weapon_repairgun );
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponRepairGun, DT_WeaponRepairGun )
BEGIN_NETWORK_TABLE( CWeaponRepairGun, DT_WeaponRepairGun )
#if !defined( CLIENT_DLL )
SendPropInt( SENDINFO( m_bHealing ), 1, SPROP_UNSIGNED ),
SendPropInt( SENDINFO( m_bAttacking ), 1, SPROP_UNSIGNED ),
SendPropEHandle( SENDINFO( m_hHealingTarget ) ),
#else
RecvPropInt( RECVINFO( m_bAttacking ) ),
RecvPropInt( RECVINFO( m_bHealing ) ),
RecvPropEHandle( RECVINFO(m_hHealingTarget) ),
#endif
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CWeaponRepairGun )
DEFINE_PRED_FIELD( CWeaponRepairGun, m_bHealing, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( CWeaponRepairGun, m_bAttacking, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( CWeaponRepairGun, m_hHealingTarget, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
DEFINE_FIELD( CWeaponRepairGun, m_flHealEffectLifetime, FIELD_FLOAT ),
// DEFINE_PRED_FIELD( CWeaponRepairGun, m_pEmitter, FIELD_POINTER ),
// DEFINE_PRED_FIELD( CWeaponRepairGun, m_hParticleMaterial, FIELD_???, ),
// DEFINE_PRED_FIELD( CWeaponRepairGun, m_PathParticleEvent, FIELD_???, ),
// DEFINE_PRED_FIELD( CWeaponRepairGun, m_bPlayingSound, FIELD_BOOLEAN ),
END_PREDICTION_DATA()
#define PARTICLE_PATH_VEL 140.0
#define NUM_PATH_PARTICLES_PER_SEC 600.0f
#define NUM_TARGET_PARTICLES_PER_SEC 720.0f
#define NUM_REPAIRGUN_PATH_POINTS 8
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CWeaponRepairGun::CWeaponRepairGun( void )
{
m_flHealEffectLifetime = 0;
m_bHealing = false;
m_bAttacking = false;
m_flNextBuzzTime = 0;
#if defined( CLIENT_DLL )
m_pEmitter = NULL;
m_hParticleMaterial = INVALID_MATERIAL_HANDLE;
m_PathParticleEvent.Init( NUM_PATH_PARTICLES_PER_SEC );
m_bPlayingSound = false;
#endif
SetPredictionEligible( true );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CWeaponRepairGun::Holster( CBaseCombatWeapon *pSwitchingTo )
{
RemoveHealingTarget();
m_bAttacking = false;
return BaseClass::Holster( pSwitchingTo );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CWeaponRepairGun::GetTargetRange( void )
{
return weapon_repairgun_target_range.GetFloat();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CWeaponRepairGun::GetStickRange( void )
{
return weapon_repairgun_stick_range.GetFloat();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CWeaponRepairGun::GetHealRate( void )
{
return weapon_repairgun_rate.GetFloat();
}
// Now make sure there isn't something other than team players in the way.
class CRepairFilter : public CTraceFilterSimple
{
public:
CRepairFilter( CBaseEntity *pShooter ) : CTraceFilterSimple( pShooter, TFCOLLISION_GROUP_WEAPON )
{
m_pShooter = pShooter;
}
virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask )
{
// If it hit an edict the isn't the target and is on our team, then the ray is blocked.
CBaseEntity *pEnt = static_cast<CBaseEntity*>(pHandleEntity);
// Ignore collisions with the shooter
if ( pEnt == m_pShooter )
return false;
// You can't heal a vehicle you are sitting in.
if( ((CBaseTFPlayer*)m_pShooter)->IsInAVehicle() )
{
CBaseEntity* pVehicle = ((CBaseTFPlayer*)m_pShooter)->GetVehicle()->GetVehicleEnt();
if( pVehicle == pEnt )
{
return false;
}
}
#ifdef REPAIR_GUN_DISABLES_GRENADES
// Repairgun can also disable enemy grenades
CBaseEMPableGrenade *pGrenade = dynamic_cast<CBaseEMPableGrenade*>(pEnt);
// Ignore collisions with teammates, or friendly grenades
if ( !pGrenade )
{
if ( pEnt->GetTeam() == m_pShooter->GetTeam() )
return false;
}
#else
if ( pEnt->GetTeam() == m_pShooter->GetTeam() )
return false;
#endif
return CTraceFilterSimple::ShouldHitEntity( pHandleEntity, contentsMask );
}
CBaseEntity *m_pShooter;
};
//-----------------------------------------------------------------------------
// Purpose: Vehicle checking to see if we should switch targets from a player
// to a vehicle, or vice versa.
//-----------------------------------------------------------------------------
CBaseEntity *CWeaponRepairGun::CheckVehicleTargets( CBaseEntity *pCurHealing )
{
// Unable to switch to/from players?
if ( !TargetsPlayers() )
return pCurHealing;
CBaseTFVehicle *pTargetVehicle = NULL;
// If we're a fully healed player sitting in a vehicle, see if the vehicle needs healing instead
if ( pCurHealing->IsPlayer() && pCurHealing->GetHealth() >= pCurHealing->GetMaxHealth() )
{
CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)pCurHealing;
if ( !pPlayer->IsInAVehicle() )
return pCurHealing;
pTargetVehicle = (CBaseTFVehicle*)(pPlayer->GetVehicle()->GetVehicleEnt());
if ( pTargetVehicle->GetHealth() < pTargetVehicle->GetMaxHealth() )
return pTargetVehicle;
}
else
{
// If the entity is a vehicle, and it's fully healed, heal any players in it instead
pTargetVehicle = dynamic_cast<CBaseTFVehicle *>(pCurHealing);
}
// Is the vehicle fully healed?
if ( pTargetVehicle && pTargetVehicle->GetHealth() >= pTargetVehicle->GetMaxHealth() )
{
CBaseTFPlayer *pUnhurtPlayer = NULL;
CBaseTFPlayer *pHurtPlayer = NULL;
// Go through all players in the vehicle
int iMax = pTargetVehicle->GetMaxPassengerCount();
for ( int i = 0; i < iMax; i++ )
{
CBaseTFPlayer *pPlayer = (CBaseTFPlayer *)pTargetVehicle->GetPassenger(i);
if ( pPlayer )
{
if ( pPlayer->GetHealth() < pPlayer->GetMaxHealth() )
{
pUnhurtPlayer = pPlayer;
}
else
{
pHurtPlayer = pPlayer;
}
}
}
// Heal hurt players first
if ( pHurtPlayer )
return pHurtPlayer;
if ( pUnhurtPlayer )
return pUnhurtPlayer;
}
return pCurHealing;
}
//-----------------------------------------------------------------------------
// Purpose: Returns a pointer to a healable target
//-----------------------------------------------------------------------------
CBaseEntity *CWeaponRepairGun::GetTargetToHeal( CBaseEntity *pCurHealing )
{
CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() );
if ( !pOwner )
return NULL;
Vector vecSrc = pOwner->Weapon_ShootPosition( );
// If we're already healing someone, stick onto them as long as possible.
// Even if we can't heal them at the moment, lock onto them until they release the buttom.
CBaseEntity* pTarget = pCurHealing;
CBaseEntity* pVehicle = NULL; // Vehicle the owner is in, or NULL.
// You can't heal a vehicle you are sitting in, make sure we aren't healing a vehicle right after we've gotten in.
if( ((CBaseTFPlayer*)pOwner)->IsInAVehicle() )
{
pVehicle = ((CBaseTFPlayer*)pOwner)->GetVehicle()->GetVehicleEnt();
if( pVehicle == pTarget )
{
pTarget = NULL;
}
}
if ( pTarget && pTarget->IsAlive() && (pTarget->GetTeam() == pOwner->GetTeam()) )
{
// Make sure the guy didn't go out of range.
Vector vecTargetPoint = pTarget->WorldSpaceCenter();
Vector vecPoint;
// If it's brush built, use absmins/absmaxs
CalcClosestPointOnAABB( pTarget->GetAbsMins(), pTarget->GetAbsMaxs(), vecSrc, vecPoint );
#ifndef CLIENT_DLL
//NDebugOverlay::Box( vecPoint, Vector(-2,-2,-2), Vector(2,2,2), 255,0,0, 8, 0.1 );
#endif
float flDistance = (vecPoint - vecSrc).Length();
if ( flDistance < GetStickRange() )
{
trace_t tr;
CRepairFilter drainFilter( pOwner );
UTIL_TraceLine( vecSrc, vecTargetPoint, MASK_SHOT, &drainFilter, &tr );
if (( tr.fraction == 1.0f) || (tr.m_pEnt == pTarget))
return CheckVehicleTargets( pTarget );
}
// Return null so we can't heal this player but m_hHealingPlayer stays set to them.
return NULL;
}
else
{
// Ok, try to find a new player to heal.
// Get the target point and location
Vector vecAiming;
pOwner->EyeVectors( &vecAiming );
// Find a player in range of this player, and make sure they're healable.
Vector vecEnd = vecSrc + vecAiming * GetTargetRange();
trace_t tr;
// Use WeaponTraceLine so shields are tested...
TFGameRules()->WeaponTraceLine( vecSrc, vecEnd, (MASK_SHOT & ~CONTENTS_HITBOX), pOwner, DMG_PROBE, &tr );
#ifndef CLIENT_DLL
//NDebugOverlay::Box( vecSrc, Vector(-2,-2,-2), Vector(2,2,2), 192,192,0, 8, 10 );
//NDebugOverlay::Box( vecEnd, Vector(-2,-2,-2), Vector(2,2,2), 0,255,0, 8, 10 );
//NDebugOverlay::Box( tr.endpos, Vector(-2,-2,-2), Vector(2,2,2), 0,0,255, 8, 10 );
#endif
if ( tr.fraction != 1.0 )
{
CBaseEntity *pEntity = tr.m_pEnt;
if ( pEntity )
{
// Repairgun can also disable enemy grenades
#ifdef REPAIR_GUN_DISABLES_GRENADES
CBaseEMPableGrenade *pGrenade = dynamic_cast<CBaseEMPableGrenade*>(pEntity);
if ( pGrenade && !pGrenade->InSameTeam( pOwner ) )
return pGrenade;
#endif
// Only target players if I'm allowed to
if ( !TargetsPlayers() && pEntity->IsPlayer() )
return NULL;
// You can't heal a vehicle you are sitting in.
if ( pVehicle && ( pVehicle == pEntity ) )
return NULL;
if ( (pEntity != pOwner) && pEntity->IsAlive() && pEntity->CanBePoweredUp() )
{
// Target needs to be on the same team
if ( pEntity->InSameTeam( pOwner ) )
return CheckVehicleTargets( pEntity );
}
}
}
if ( weapon_repairgun_debug.GetBool() )
{
ClientPrint( pOwner, HUD_PRINTCENTER, "REPAIRGUN: no target found\n" );
}
return NULL;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -