379 lines
9.6 KiB
C++
379 lines
9.6 KiB
C++
#include "cbase.h"
|
|
#include "asw_weapon_blink.h"
|
|
#include "in_buttons.h"
|
|
|
|
#ifdef CLIENT_DLL
|
|
#include "c_asw_player.h"
|
|
#include "c_asw_weapon.h"
|
|
#include "c_asw_marine.h"
|
|
#include "prediction.h"
|
|
#else
|
|
#include "asw_marine.h"
|
|
#include "asw_player.h"
|
|
#include "asw_weapon.h"
|
|
#include "npcevent.h"
|
|
#include "shot_manipulator.h"
|
|
#include "asw_path_utils.h"
|
|
#include "ai_network.h"
|
|
#include "ai_waypoint.h"
|
|
#include "ai_node.h"
|
|
#include "asw_trace_filter_doors.h"
|
|
#include "ai_navigator.h"
|
|
#include "ai_pathfinder.h"
|
|
#endif
|
|
#include "asw_marine_gamemovement.h"
|
|
#include "asw_melee_system.h"
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
IMPLEMENT_NETWORKCLASS_ALIASED( ASW_Weapon_Blink, DT_ASW_Weapon_Blink )
|
|
|
|
BEGIN_NETWORK_TABLE( CASW_Weapon_Blink, DT_ASW_Weapon_Blink )
|
|
#ifdef CLIENT_DLL
|
|
RecvPropFloat ( RECVINFO( m_flPower ) ),
|
|
RecvPropVector ( RECVINFO( m_vecAbilityDestination ) ),
|
|
#else
|
|
SendPropFloat ( SENDINFO( m_flPower ), 0, SPROP_NOSCALE ),
|
|
SendPropVector ( SENDINFO( m_vecAbilityDestination ) ),
|
|
#endif
|
|
END_NETWORK_TABLE()
|
|
|
|
#ifdef CLIENT_DLL
|
|
BEGIN_PREDICTION_DATA( CASW_Weapon_Blink )
|
|
DEFINE_PRED_FIELD_TOL( m_flPower, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, TD_MSECTOLERANCE ),
|
|
END_PREDICTION_DATA()
|
|
#endif
|
|
|
|
LINK_ENTITY_TO_CLASS( asw_weapon_blink, CASW_Weapon_Blink );
|
|
PRECACHE_WEAPON_REGISTER( asw_weapon_blink );
|
|
|
|
#ifndef CLIENT_DLL
|
|
|
|
//---------------------------------------------------------
|
|
// Save/Restore
|
|
//---------------------------------------------------------
|
|
BEGIN_DATADESC( CASW_Weapon_Blink )
|
|
DEFINE_FIELD( m_flSoonestPrimaryAttack, FIELD_TIME ),
|
|
END_DATADESC()
|
|
|
|
ConVar asw_blink_debug( "asw_blink_debug", "0", FCVAR_CHEAT );
|
|
|
|
#else
|
|
|
|
|
|
#endif /* not client */
|
|
|
|
ConVar asw_blink_charge_time( "asw_blink_charge_time", "30.0", FCVAR_CHEAT | FCVAR_REPLICATED );
|
|
ConVar asw_blink_range( "asw_blink_range", "2000", FCVAR_REPLICATED | FCVAR_CHEAT );
|
|
ConVar asw_blink_time( "asw_blink_time", "0.6", FCVAR_REPLICATED | FCVAR_CHEAT );
|
|
|
|
CASW_Weapon_Blink::CASW_Weapon_Blink()
|
|
{
|
|
m_flSoonestPrimaryAttack = 0;
|
|
m_flPower = asw_blink_charge_time.GetFloat();
|
|
}
|
|
|
|
|
|
CASW_Weapon_Blink::~CASW_Weapon_Blink()
|
|
{
|
|
|
|
}
|
|
|
|
void CASW_Weapon_Blink::Spawn()
|
|
{
|
|
BaseClass::Spawn();
|
|
|
|
m_flPower = asw_blink_charge_time.GetFloat();
|
|
}
|
|
|
|
bool CASW_Weapon_Blink::OffhandActivate()
|
|
{
|
|
if (!GetMarine() || GetMarine()->GetFlags() & FL_FROZEN) // don't allow this if the marine is frozen
|
|
return false;
|
|
|
|
PrimaryAttack();
|
|
|
|
return true;
|
|
}
|
|
|
|
#ifdef GAME_DLL
|
|
bool CASW_Weapon_Blink::SetBlinkDestination()
|
|
{
|
|
CASW_Player *pPlayer = GetCommander();
|
|
if ( !pPlayer )
|
|
return false;
|
|
|
|
CASW_Marine *pMarine = GetMarine();
|
|
if ( !pMarine )
|
|
return false;
|
|
|
|
Vector vecStart = pPlayer->GetCrosshairTracePos() + Vector( 0, 0, 30 );
|
|
Vector vecEnd = pPlayer->GetCrosshairTracePos() - Vector( 0, 0, 30 );
|
|
trace_t tr;
|
|
UTIL_TraceHull( vecStart, vecEnd, pMarine->WorldAlignMins(), pMarine->WorldAlignMaxs(), MASK_PLAYERSOLID_BRUSHONLY, pMarine, COLLISION_GROUP_PLAYER_MOVEMENT, &tr );
|
|
if ( tr.startsolid || tr.allsolid )
|
|
{
|
|
m_vecInvalidDestination = vecStart;
|
|
return false;
|
|
}
|
|
|
|
if ( pMarine->GetAbsOrigin().DistTo( tr.endpos ) > asw_blink_range.GetFloat() )
|
|
{
|
|
m_vecInvalidDestination = tr.endpos;
|
|
return false;
|
|
}
|
|
|
|
Vector vecDest = tr.endpos;
|
|
|
|
// now see if we can build an AI path from the marine to this spot
|
|
bool bValidRoute = false;
|
|
|
|
if ( !pMarine->GetPathfinder() )
|
|
{
|
|
m_vecInvalidDestination = vecDest;
|
|
return false;
|
|
}
|
|
|
|
AI_Waypoint_t *pRoute = pMarine->GetPathfinder()->BuildRoute( pMarine->GetAbsOrigin(), vecDest, NULL, 30, NAV_GROUND, bits_BUILD_GROUND | bits_BUILD_IGNORE_NPCS );
|
|
if ( pRoute && !UTIL_ASW_DoorBlockingRoute( pRoute, true ) )
|
|
{
|
|
if ( !UTIL_ASW_BrushBlockingRoute( pRoute, MASK_PLAYERSOLID_BRUSHONLY, COLLISION_GROUP_PLAYER_MOVEMENT ) )
|
|
{
|
|
// if end node of the route is too Z different, then abort, to stop people jumping on top of walls
|
|
AI_Waypoint_t *pLast = pRoute->GetLast();
|
|
if ( pLast )
|
|
{
|
|
AI_Waypoint_t *pNode = pLast->GetPrev();
|
|
if ( !pNode || fabs( pNode->GetPos().z - pLast->GetPos().z ) < 80.0f )
|
|
{
|
|
bValidRoute = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !bValidRoute )
|
|
{
|
|
// find the closest node to the dest and try to path there instead
|
|
CAI_Network *pNetwork = pMarine->GetNavigator() ? pMarine->GetNavigator()->GetNetwork() : NULL;
|
|
if ( pNetwork )
|
|
{
|
|
int nNode = pNetwork->NearestNodeToPoint( vecDest, false );
|
|
if ( nNode != NO_NODE )
|
|
{
|
|
CAI_Node *pNode = pNetwork->GetNode( nNode );
|
|
if ( pNode && pNode->GetType() == NODE_GROUND )
|
|
{
|
|
vecDest = pNode->GetOrigin();
|
|
if ( pRoute )
|
|
{
|
|
ASWPathUtils()->DeleteRoute( pRoute );
|
|
pRoute = NULL;
|
|
}
|
|
pRoute = pMarine->GetPathfinder()->BuildRoute( pMarine->GetAbsOrigin(), vecDest, NULL, 30, NAV_GROUND, bits_BUILD_GROUND | bits_BUILD_IGNORE_NPCS );
|
|
if ( pRoute && !UTIL_ASW_DoorBlockingRoute( pRoute, true ) )
|
|
{
|
|
if ( !UTIL_ASW_BrushBlockingRoute( pRoute, MASK_PLAYERSOLID_BRUSHONLY, COLLISION_GROUP_PLAYER_MOVEMENT ) )
|
|
{
|
|
bValidRoute = true;
|
|
}
|
|
}
|
|
if ( !bValidRoute )
|
|
{
|
|
m_vecInvalidDestination = vecDest;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !bValidRoute )
|
|
{
|
|
if ( pRoute )
|
|
{
|
|
ASWPathUtils()->DeleteRoute( pRoute );
|
|
pRoute = NULL;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if ( asw_blink_debug.GetBool() )
|
|
{
|
|
ASWPathUtils()->DebugDrawRoute( pMarine->GetAbsOrigin(), pRoute );
|
|
}
|
|
|
|
m_vecAbilityDestination = vecDest;
|
|
|
|
if ( pRoute )
|
|
{
|
|
ASWPathUtils()->DeleteRoute( pRoute );
|
|
pRoute = NULL;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
void CASW_Weapon_Blink::PrimaryAttack( void )
|
|
{
|
|
CASW_Player *pPlayer = GetCommander();
|
|
if (!pPlayer)
|
|
return;
|
|
|
|
CASW_Marine *pMarine = GetMarine();
|
|
if ( !pMarine || pMarine->GetCurrentMeleeAttack() || pMarine->GetForcedActionRequest() != 0 )
|
|
return;
|
|
|
|
if ( GetPower() < asw_blink_charge_time.GetFloat() )
|
|
{
|
|
#ifdef CLIENT_DLL
|
|
EmitSound( "ASW_Weapon.InsufficientBattery" );
|
|
#else
|
|
if ( gpGlobals->maxClients <= 1 )
|
|
{
|
|
EmitSound( "ASW_Weapon.InsufficientBattery" );
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
if ( pMarine->IsInhabited() )
|
|
{
|
|
// Get the server to verify destination and do a forced action to actually blink
|
|
#ifdef GAME_DLL
|
|
if ( !SetBlinkDestination() )
|
|
{
|
|
CSingleUserRecipientFilter user( pPlayer );
|
|
UserMessageBegin( user, "ASWInvalidDesination" );
|
|
WRITE_SHORT( pMarine->entindex() );
|
|
WRITE_FLOAT( m_vecInvalidDestination.x );
|
|
WRITE_FLOAT( m_vecInvalidDestination.y );
|
|
WRITE_FLOAT( m_vecInvalidDestination.z );
|
|
MessageEnd();
|
|
return;
|
|
}
|
|
|
|
pMarine->RequestForcedAction( FORCED_ACTION_BLINK );
|
|
pMarine->OnWeaponFired( this, 1 );
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void CASW_Weapon_Blink::Precache()
|
|
{
|
|
BaseClass::Precache();
|
|
|
|
PrecacheScriptSound( "ASW_Weapon.BatteryCharged" );
|
|
PrecacheScriptSound( "ASW_Weapon.InsufficientBattery" );
|
|
}
|
|
|
|
// this weapon doesn't reload
|
|
bool CASW_Weapon_Blink::Reload()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void CASW_Weapon_Blink::ItemPostFrame( void )
|
|
{
|
|
BaseClass::ItemPostFrame();
|
|
|
|
UpdatePower();
|
|
|
|
if ( m_bInReload )
|
|
return;
|
|
|
|
CBasePlayer *pOwner = GetCommander();
|
|
if ( !pOwner )
|
|
return;
|
|
|
|
//Allow a refire as fast as the player can click
|
|
if ( ( ( pOwner->m_nButtons & IN_ATTACK ) == false ) && ( m_flSoonestPrimaryAttack < gpGlobals->curtime ) )
|
|
{
|
|
m_flNextPrimaryAttack = gpGlobals->curtime - 0.1f;
|
|
}
|
|
}
|
|
|
|
void CASW_Weapon_Blink::HandleFireOnEmpty()
|
|
{
|
|
// Nightvision doesn't require ammo, so when firing empty, activate the NV
|
|
PrimaryAttack();
|
|
}
|
|
|
|
void CASW_Weapon_Blink::UpdatePower()
|
|
{
|
|
if ( GetPower() < asw_blink_charge_time.GetFloat() )
|
|
{
|
|
float flNewPower = GetPower() + gpGlobals->frametime * 1.4f;
|
|
flNewPower = MIN( asw_blink_charge_time.GetFloat(), flNewPower );
|
|
m_flPower = flNewPower;
|
|
|
|
if ( flNewPower >= asw_blink_charge_time.GetFloat() )
|
|
{
|
|
#ifdef CLIENT_DLL
|
|
EmitSound( "ASW_Weapon.BatteryCharged" );
|
|
#else
|
|
if ( gpGlobals->maxClients <= 1 )
|
|
{
|
|
EmitSound( "ASW_Weapon.BatteryCharged" );
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef CLIENT_DLL
|
|
#endif
|
|
|
|
int CASW_Weapon_Blink::ASW_SelectWeaponActivity(int idealActivity)
|
|
{
|
|
// we just use the normal 'no weapon' anims for this
|
|
return idealActivity;
|
|
}
|
|
|
|
// needs to be fully charged to activate
|
|
float CASW_Weapon_Blink::GetMinBatteryChargeToActivate()
|
|
{
|
|
return 1.0f;
|
|
}
|
|
|
|
float CASW_Weapon_Blink::GetBatteryCharge()
|
|
{
|
|
return GetPower() / asw_blink_charge_time.GetFloat();
|
|
}
|
|
|
|
void CASW_Weapon_Blink::DoBlink()
|
|
{
|
|
CASW_Marine *pMarine = GetMarine();
|
|
if ( !pMarine )
|
|
return;
|
|
|
|
pMarine->m_iJumpJetting = JJ_BLINK;
|
|
pMarine->m_vecJumpJetStart = pMarine->GetAbsOrigin();
|
|
pMarine->m_vecJumpJetEnd = m_vecAbilityDestination;
|
|
pMarine->m_flJumpJetStartTime = gpGlobals->curtime;
|
|
pMarine->m_flJumpJetEndTime = gpGlobals->curtime + asw_blink_time.GetFloat();
|
|
|
|
ASWMeleeSystem()->StartMeleeAttack( ASWMeleeSystem()->GetMeleeAttackByName( "Blink" ), pMarine, ASWGameMovement()->GetMoveData() );
|
|
|
|
// TODO:
|
|
/*
|
|
#ifdef GAME_DLL
|
|
// create a small stun volume at the start
|
|
CASW_Weapon_EffectVolume *pEffect = (CASW_Weapon_EffectVolume*) CreateEntityByName("asw_weapon_effect_volume");
|
|
if ( pEffect )
|
|
{
|
|
pEffect->SetAbsOrigin( pMarine->GetAbsOrigin() );
|
|
pEffect->SetOwnerEntity( pMarine );
|
|
pEffect->SetOwnerWeapon( NULL );
|
|
pEffect->SetEffectFlag( ASW_WEV_ELECTRIC_BIG );
|
|
pEffect->SetDuration( pSkill->GetValue( CASW_Skill_Details::Duration, GetSkillPoints() ) );
|
|
pEffect->Spawn();
|
|
}
|
|
#endif
|
|
*/
|
|
|
|
m_flPower = 0.0f;
|
|
|
|
// TODO: Check for charges being zero
|
|
} |