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

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
}