diff --git a/src/game/server/CMakeLists.txt b/src/game/server/CMakeLists.txt index 5f9434ff9..fd002b63f 100644 --- a/src/game/server/CMakeLists.txt +++ b/src/game/server/CMakeLists.txt @@ -1589,6 +1589,11 @@ target_sources_grouped( neo/bot/behavior/neo_bot_ctg_seek.cpp neo/bot/behavior/neo_bot_ctg_seek.h neo/bot/behavior/neo_bot_dead.h + neo/bot/behavior/neo_bot_detpack_deploy.cpp + neo/bot/behavior/neo_bot_detpack_deploy.h + neo/bot/behavior/neo_bot_detpack_trigger.cpp + neo/bot/behavior/neo_bot_detpack_trigger.h + neo/bot/behavior/neo_bot_grenade_dispatch.cpp neo/bot/behavior/neo_bot_grenade_dispatch.h neo/bot/behavior/neo_bot_grenade_throw.h neo/bot/behavior/neo_bot_grenade_throw_frag.h diff --git a/src/game/server/neo/bot/behavior/neo_bot_ctg_lone_wolf.cpp b/src/game/server/neo/bot/behavior/neo_bot_ctg_lone_wolf.cpp index 060824007..5a2556b01 100644 --- a/src/game/server/neo/bot/behavior/neo_bot_ctg_lone_wolf.cpp +++ b/src/game/server/neo/bot/behavior/neo_bot_ctg_lone_wolf.cpp @@ -5,6 +5,7 @@ #include "bot/behavior/neo_bot_ctg_lone_wolf.h" #include "bot/behavior/neo_bot_ctg_lone_wolf_ambush.h" #include "bot/behavior/neo_bot_ctg_lone_wolf_seek.h" +#include "bot/behavior/neo_bot_detpack_deploy.h" #include "bot/neo_bot_path_compute.h" #include "neo_gamerules.h" #include "neo_ghost_cap_point.h" @@ -57,6 +58,10 @@ ActionResult< CNEOBot > CNEOBotCtgLoneWolf::Update( CNEOBot *me, float interval const CNavArea *myArea = me->GetLastKnownArea(); if ( ghostArea && myArea && ghostArea->IsPotentiallyVisible( myArea ) ) { + if ( pDetpackWeapon && !pDetpackWeapon->m_bThisDetpackHasBeenThrown && NEORules()->m_pGhost ) + { + return ChangeTo( new CNEOBotDetpackDeploy( NEORules()->GetGhostPos(), new CNEOBotCtgLoneWolfAmbush() ), "Moving to plant detpack" ); + } return ChangeTo( new CNEOBotCtgLoneWolfAmbush(), "Waiting in ambush near ghost" ); } diff --git a/src/game/server/neo/bot/behavior/neo_bot_detpack_deploy.cpp b/src/game/server/neo/bot/behavior/neo_bot_detpack_deploy.cpp new file mode 100644 index 000000000..65bb4ae17 --- /dev/null +++ b/src/game/server/neo/bot/behavior/neo_bot_detpack_deploy.cpp @@ -0,0 +1,218 @@ +#include "cbase.h" +#include "bot/neo_bot.h" +#include "bot/neo_bot_path_compute.h" +#include "bot/behavior/neo_bot_attack.h" +#include "bot/behavior/neo_bot_ctg_lone_wolf_seek.h" +#include "bot/behavior/neo_bot_detpack_deploy.h" +#include "neo_detpack.h" +#include "weapon_detpack.h" + +//--------------------------------------------------------------------------------------------- +CNEOBotDetpackDeploy::CNEOBotDetpackDeploy( const Vector &targetPos, Action< CNEOBot > *nextAction ) + : m_targetPos( targetPos ), m_nextAction( nextAction ), m_flDeployDistSq( 0.0f ) +{ + m_bPushedWeapon = false; + m_losTimer.Invalidate(); +} + + +//--------------------------------------------------------------------------------------------- +ActionResult< CNEOBot > CNEOBotDetpackDeploy::OnStart( CNEOBot *me, Action< CNEOBot > *priorAction ) +{ + m_hDetpackWeapon = assert_cast< CWeaponDetpack* >( me->Weapon_OwnsThisType( "weapon_remotedet" ) ); + if ( !m_hDetpackWeapon ) + { + if (m_nextAction != nullptr) + { + return ChangeTo( m_nextAction, "No detpack weapon, transitioning to next action" ); + } + return Done( "No detpack weapon found" ); + } + + me->PushRequiredWeapon( m_hDetpackWeapon ); + m_bPushedWeapon = true; + + // Ignore enemy to prevent weapon handling interference with detpack deployment + me->StopLookingAroundForEnemies(); + me->SetAttribute( CNEOBot::IGNORE_ENEMIES ); + + m_expiryTimer.Start( 10.0f ); + m_repathTimer.Invalidate(); + + m_flDeployDistSq = Square( MAX( 100.0f, CWeaponDetpack::GetArmingTime() * me->GetNormSpeed() ) ); + + return Continue(); +} + +//--------------------------------------------------------------------------------------------- +ActionResult< CNEOBot > CNEOBotDetpackDeploy::Update( CNEOBot *me, float interval ) +{ + if ( !m_hDetpackWeapon ) + { + if ( m_nextAction ) + { + return ChangeTo( m_nextAction, "No detpack weapon, transitioning to next action" ); + } + return Done( "No detpack weapon" ); + } + + if ( m_expiryTimer.IsElapsed() ) + { + if ( m_nextAction ) + { + return ChangeTo( m_nextAction, "Detpack deploy timer expired, transitioning to next action" ); + } + return Done( "Detpack deploy timer expired" ); + } + + if ( m_hDetpackWeapon->m_bThisDetpackHasBeenThrown ) + { + if ( m_nextAction ) + { + return ChangeTo( m_nextAction, "Detpack deployed, transitioning to next action" ); + } + return Done( "Detpack deployed" ); + } + + const CKnownEntity* threat = me->GetVisionInterface()->GetPrimaryKnownThreat( true ); + if ( threat && threat->GetEntity() ) + { + if (m_nextAction != nullptr) + { + return ChangeTo( m_nextAction, "Interrupting detpack deploy to let next action handle enemy" ); + } + return ChangeTo( new CNEOBotAttack(), "Engaging enemy encountered while deploying detpack" ); + } + + float flDistToTargetSq = me->GetAbsOrigin().DistToSqr( m_targetPos ); + if ( flDistToTargetSq < m_flDeployDistSq ) + { + if ( me->GetActiveWeapon() == m_hDetpackWeapon ) + { + if ( !m_losTimer.HasStarted() || m_losTimer.IsElapsed() ) + { + if ( me->GetVisionInterface()->IsLineOfSightClear( m_targetPos ) ) + { + CBaseEntity *pEnts[256]; + int numEnts = UTIL_EntitiesInSphere( pEnts, 256, me->GetAbsOrigin(), NEO_DETPACK_DAMAGE_RADIUS, 0 ); + bool bDetpackNear = false; + for ( int i = 0; i < numEnts; ++i ) + { + if ( pEnts[i] && FClassnameIs( pEnts[i], "neo_deployed_detpack" ) ) + { + bDetpackNear = true; + break; + } + } + + if ( bDetpackNear ) + { + if ( m_nextAction ) + { + return ChangeTo( m_nextAction, "Skipping detpack deploy: in blast radius of another detpack" ); + } + return Done( "Aborting detpack deploy: in blast radius of another detpack" ); + } + + me->PressFireButton(); + + if ( flDistToTargetSq < Square( 64.0f ) ) + { + m_path.Invalidate(); + m_repathTimer.Start( 10.0f ); + } + } + + m_losTimer.Start( RandomFloat( 0.2f, 0.4f ) ); + } + } + } + + if ( !m_path.IsValid() ) + { + if ( !m_repathTimer.HasStarted() || m_repathTimer.IsElapsed() ) + { + CNEOBotPathCompute( me, m_path, m_targetPos, FASTEST_ROUTE ); + m_repathTimer.Start( RandomFloat( 1.0f, 2.0f ) ); + } + } + else + { + m_path.Update( me ); + } + + return Continue(); +} + + +//--------------------------------------------------------------------------------------------- +void CNEOBotDetpackDeploy::OnEnd( CNEOBot *me, Action< CNEOBot > *nextAction ) +{ + if ( m_bPushedWeapon ) + { + me->PopRequiredWeapon(); + m_bPushedWeapon = false; + } + me->StartLookingAroundForEnemies(); + me->ClearAttribute( CNEOBot::IGNORE_ENEMIES ); + + if ( m_hDetpackWeapon && m_hDetpackWeapon->m_bThisDetpackHasBeenThrown ) + { + me->EquipBestWeaponForThreat( me->GetVisionInterface()->GetPrimaryKnownThreat( true ) ); + } +} + + +//--------------------------------------------------------------------------------------------- +ActionResult CNEOBotDetpackDeploy::OnSuspend( CNEOBot *me, Action *interruptingAction ) +{ + if (m_nextAction != nullptr) + { + return ChangeTo( m_nextAction, "Detpack deploy suspend cancelled, transitioning to next action" ); + } + + return Done( "Detpack deploy suspended, situation will likely become stale." ); + // OnEnd will get called after Done +} + +//--------------------------------------------------------------------------------------------- +ActionResult CNEOBotDetpackDeploy::OnResume( CNEOBot *me, Action *interruptingAction ) +{ + if (m_nextAction != nullptr) + { + return ChangeTo( m_nextAction, "Detpack deploy resume cancelled, transitioning to next action" ); + } + + return Done( "Detpack deploy resumed, situation is likely stale." ); + // OnEnd will get called after Done +} + +//--------------------------------------------------------------------------------------------- +EventDesiredResult< CNEOBot > CNEOBotDetpackDeploy::OnStuck( CNEOBot *me ) +{ + if (m_nextAction != nullptr) + { + return TryChangeTo( m_nextAction, RESULT_CRITICAL, "Detpack deploy stuck, transitioning to next action" ); + } + + return TryDone( RESULT_CRITICAL, "Detpack deploy stuck, situation will likely become stale." ); + // OnEnd will get called after Done +} + +//--------------------------------------------------------------------------------------------- +EventDesiredResult< CNEOBot > CNEOBotDetpackDeploy::OnMoveToSuccess( CNEOBot *me, const Path *path ) +{ + return TryContinue(); +} + +//--------------------------------------------------------------------------------------------- +EventDesiredResult< CNEOBot > CNEOBotDetpackDeploy::OnMoveToFailure( CNEOBot *me, const Path *path, MoveToFailureType reason ) +{ + if (m_nextAction != nullptr) + { + return TryChangeTo( m_nextAction, RESULT_CRITICAL, "Detpack deploy move to failure, transitioning to next action" ); + } + + return TryDone( RESULT_CRITICAL, "Detpack deploy move to failure, situation will likely become stale." ); + // OnEnd will get called after Done +} diff --git a/src/game/server/neo/bot/behavior/neo_bot_detpack_deploy.h b/src/game/server/neo/bot/behavior/neo_bot_detpack_deploy.h new file mode 100644 index 000000000..3f0c91ba4 --- /dev/null +++ b/src/game/server/neo/bot/behavior/neo_bot_detpack_deploy.h @@ -0,0 +1,35 @@ +#pragma once + +#include "bot/neo_bot.h" + +class CWeaponDetpack; + +//-------------------------------------------------------------------------------------------------------- +class CNEOBotDetpackDeploy : public Action< CNEOBot > +{ +public: + CNEOBotDetpackDeploy( const Vector &targetPos, Action< CNEOBot > *nextAction = nullptr ); + + virtual ActionResult< CNEOBot > OnStart( CNEOBot *me, Action< CNEOBot > *priorAction ) override; + virtual ActionResult< CNEOBot > Update( CNEOBot *me, float interval ) override; + virtual ActionResult< CNEOBot > OnSuspend( CNEOBot *me, Action< CNEOBot > *interruptingAction ) override; + virtual ActionResult< CNEOBot > OnResume( CNEOBot *me, Action< CNEOBot > *interruptingAction ) override; + virtual void OnEnd( CNEOBot *me, Action< CNEOBot > *nextAction ) override; + + virtual EventDesiredResult< CNEOBot > OnStuck( CNEOBot *me ) override; + virtual EventDesiredResult< CNEOBot > OnMoveToSuccess( CNEOBot *me, const Path *path ) override; + virtual EventDesiredResult< CNEOBot > OnMoveToFailure( CNEOBot *me, const Path *path, MoveToFailureType reason ) override; + + virtual const char *GetName( void ) const override { return "DetpackDeploy"; } + +private: + bool m_bPushedWeapon; + float m_flDeployDistSq; + Action< CNEOBot > *m_nextAction; + CHandle< CWeaponDetpack > m_hDetpackWeapon; + CountdownTimer m_expiryTimer; + CountdownTimer m_losTimer; + CountdownTimer m_repathTimer; + PathFollower m_path; + Vector m_targetPos; +}; diff --git a/src/game/server/neo/bot/behavior/neo_bot_detpack_trigger.cpp b/src/game/server/neo/bot/behavior/neo_bot_detpack_trigger.cpp new file mode 100644 index 000000000..1ebb6173d --- /dev/null +++ b/src/game/server/neo/bot/behavior/neo_bot_detpack_trigger.cpp @@ -0,0 +1,82 @@ +#include "cbase.h" +#include "bot/neo_bot.h" +#include "bot/behavior/neo_bot_detpack_trigger.h" +#include "weapon_detpack.h" + +//--------------------------------------------------------------------------------------------- +CNEOBotDetpackTrigger::CNEOBotDetpackTrigger( void ) +{ + m_hDetpackWeapon = nullptr; + m_bPushedWeapon = false; +} + +//--------------------------------------------------------------------------------------------- +ActionResult< CNEOBot > CNEOBotDetpackTrigger::OnStart( CNEOBot *me, Action< CNEOBot > *priorAction ) +{ + m_hDetpackWeapon = assert_cast( me->Weapon_OwnsThisType( "weapon_remotedet" ) ); + if ( m_hDetpackWeapon ) + { + me->PushRequiredWeapon( m_hDetpackWeapon ); + m_bPushedWeapon = true; + } + else + { + return Done( "No detpack weapon found" ); + } + + // Ignore enemy to prevent weapon handling interference with detpack trigger + me->StopLookingAroundForEnemies(); + me->SetAttribute( CNEOBot::IGNORE_ENEMIES ); + + m_expiryTimer.Start( 5.0f ); + + return Continue(); +} + +//--------------------------------------------------------------------------------------------- +ActionResult< CNEOBot > CNEOBotDetpackTrigger::Update( CNEOBot *me, float interval ) +{ + if ( m_expiryTimer.IsElapsed() ) + { + return Done( "Detpack trigger timer expired" ); + } + + if ( !m_hDetpackWeapon || !m_hDetpackWeapon->m_bThisDetpackHasBeenThrown || m_hDetpackWeapon->m_bRemoteHasBeenTriggered ) + { + return Done( "Detpack triggered or invalid" ); + } + + if ( me->GetActiveWeapon() == m_hDetpackWeapon && gpGlobals->curtime >= m_hDetpackWeapon->m_flNextPrimaryAttack ) + { + me->PressFireButton(); + } + + return Continue(); +} + +//--------------------------------------------------------------------------------------------- +void CNEOBotDetpackTrigger::OnEnd( CNEOBot *me, Action< CNEOBot > *nextAction ) +{ + // Restore looking and weapon handling behaviors + if ( m_bPushedWeapon ) + { + me->PopRequiredWeapon(); + m_bPushedWeapon = false; + } + me->StartLookingAroundForEnemies(); + me->ClearAttribute( CNEOBot::IGNORE_ENEMIES ); +} + +//--------------------------------------------------------------------------------------------- +ActionResult CNEOBotDetpackTrigger::OnSuspend( CNEOBot *me, Action *interruptingAction ) +{ + return Done( "OnSuspend: Cancel out of detpack trigger behavior, situation will likely become stale." ); + // OnEnd will get called after Done +} + +//--------------------------------------------------------------------------------------------- +ActionResult CNEOBotDetpackTrigger::OnResume( CNEOBot *me, Action *interruptingAction ) +{ + return Done( "OnResume: Cancel out of detpack trigger behavior, situation is likely stale." ); + // OnEnd will get called after Done +} diff --git a/src/game/server/neo/bot/behavior/neo_bot_detpack_trigger.h b/src/game/server/neo/bot/behavior/neo_bot_detpack_trigger.h new file mode 100644 index 000000000..ebd1b6abb --- /dev/null +++ b/src/game/server/neo/bot/behavior/neo_bot_detpack_trigger.h @@ -0,0 +1,26 @@ +#pragma once + +#include "bot/neo_bot.h" + +class CWeaponDetpack; + +//----------------------------------------------------------------------------- +class CNEOBotDetpackTrigger : public Action< CNEOBot > +{ +public: + CNEOBotDetpackTrigger( void ); + + virtual ActionResult< CNEOBot > OnStart( CNEOBot *me, Action< CNEOBot > *priorAction ) override; + virtual ActionResult< CNEOBot > Update( CNEOBot *me, float interval ) override; + virtual void OnEnd( CNEOBot *me, Action< CNEOBot > *nextAction ) override; + + virtual ActionResult OnSuspend( CNEOBot *me, Action *interruptingAction ) override; + virtual ActionResult OnResume( CNEOBot *me, Action *interruptingAction ) override; + + virtual const char *GetName( void ) const override { return "DetpackTrigger"; } + +private: + bool m_bPushedWeapon; + CHandle< CWeaponDetpack > m_hDetpackWeapon; + CountdownTimer m_expiryTimer; +}; diff --git a/src/game/server/neo/bot/behavior/neo_bot_tactical_monitor.cpp b/src/game/server/neo/bot/behavior/neo_bot_tactical_monitor.cpp index 78e8be610..f7556f5d9 100644 --- a/src/game/server/neo/bot/behavior/neo_bot_tactical_monitor.cpp +++ b/src/game/server/neo/bot/behavior/neo_bot_tactical_monitor.cpp @@ -8,6 +8,7 @@ #include "bot/neo_bot.h" #include "bot/neo_bot_manager.h" +#include "bot/behavior/neo_bot_detpack_trigger.h" #include "bot/behavior/neo_bot_tactical_monitor.h" #include "bot/behavior/neo_bot_scenario_monitor.h" @@ -26,6 +27,9 @@ #include "bot/behavior/nav_entities/neo_bot_nav_ent_move_to.h" #include "bot/behavior/nav_entities/neo_bot_nav_ent_wait.h" #include "neo/neo_player_shared.h" +#include "neo_detpack.h" +#include "weapon_detpack.h" +#include "weapon_ghost.h" #include "nav_mesh.h" ConVar neo_bot_force_jump( "neo_bot_force_jump", "0", FCVAR_CHEAT, "Force bots to continuously jump" ); @@ -85,6 +89,114 @@ ActionResult< CNEOBot > CNEOBotTacticalMonitor::OnStart( CNEOBot *me, Action< CN } +//----------------------------------------------------------------------------------------- +ActionResult< CNEOBot > CNEOBotTacticalMonitor::MonitorArmedDetpack( CNEOBot *me ) +{ + if ( !m_detpackCheckTimer.IsElapsed() ) + { + return Continue(); + } + m_detpackCheckTimer.Start( 0.2f ); + + CWeaponDetpack *pDetWeapon = assert_cast( me->Weapon_OwnsThisType( "weapon_remotedet" ) ); + if ( !pDetWeapon || !pDetWeapon->m_bThisDetpackHasBeenThrown || pDetWeapon->m_bRemoteHasBeenTriggered ) + { + return Continue(); + } + + CBaseEntity *pDetpackEnt = pDetWeapon->GetDetpackEntity(); + if ( !pDetpackEnt ) + { + return Continue(); + } + + const Vector vecDetpackPos = pDetpackEnt->GetAbsOrigin(); + + // Check if I am too close to the detpack + if ( me->GetAbsOrigin().DistToSqr( vecDetpackPos ) <= Square( NEO_DETPACK_DAMAGE_RADIUS ) ) + { + return Continue(); + } + + float flThresholdMultiplier; + switch ( me->GetDifficulty() ) + { + case CNEOBot::EASY: + flThresholdMultiplier = 1.05f; + break; + case CNEOBot::NORMAL: + flThresholdMultiplier = 0.95f; + break; + case CNEOBot::HARD: + flThresholdMultiplier = 0.85f; + break; + case CNEOBot::EXPERT: + flThresholdMultiplier = 0.75f; + break; + default: + flThresholdMultiplier = 0.95f; + break; + } + + const float flMaxRadiusSq = Square( NEO_DETPACK_DAMAGE_RADIUS * flThresholdMultiplier ); + bool bShouldDetonate = false; + + // Check if any known threat or teammate is in range + CUtlVector< CKnownEntity > knownVector; + me->GetVisionInterface()->CollectKnownEntities( &knownVector ); + bool bIsTeamplay = NEORules()->IsTeamplay(); + + for ( int i = 0; i < knownVector.Count(); ++i ) + { + if ( knownVector[i].IsObsolete() ) + { + continue; + } + + CBaseEntity *pEntity = knownVector[i].GetEntity(); + if ( !pEntity ) + { + continue; + } + + if ( vecDetpackPos.DistToSqr( knownVector[i].GetLastKnownPosition() ) <= flMaxRadiusSq ) + { + if ( bIsTeamplay && me->InSameTeam( pEntity ) ) + { + // Teammate in blast radius + return Continue(); + } + + // Enemy in range. + bShouldDetonate = true; + } + } + + // Check if ghost carrier is in range + if ( !bShouldDetonate ) + { + if ( CWeaponGhost *pGhost = NEORules()->m_pGhost ) + { + CBaseCombatCharacter *pGhostOwner = pGhost->GetOwner(); + if ( pGhostOwner && !me->InSameTeam( pGhostOwner ) ) + { + if ( vecDetpackPos.DistToSqr( pGhostOwner->GetAbsOrigin() ) <= flMaxRadiusSq ) + { + bShouldDetonate = true; + } + } + } + } + + if ( bShouldDetonate ) + { + return SuspendFor( new CNEOBotDetpackTrigger(), "Triggering detpack!" ); + } + + return Continue(); +} + + #ifndef NEO // NEO TODO (Adam) Monitor the remote detpack //----------------------------------------------------------------------------------------- void CNEOBotTacticalMonitor::MonitorArmedStickyBombs( CNEOBot *me ) @@ -311,6 +423,12 @@ ActionResult< CNEOBot > CNEOBotTacticalMonitor::Update( CNEOBot *me, float inter } #endif + ActionResult< CNEOBot > detpackResult = MonitorArmedDetpack( me ); + if ( detpackResult.IsRequestingChange() ) + { + return detpackResult; + } + #if 0 // NEO TODO (Adam) detonate remote detpacks // detonate sticky bomb traps when victims are near MonitorArmedStickyBombs( me ); diff --git a/src/game/server/neo/bot/behavior/neo_bot_tactical_monitor.h b/src/game/server/neo/bot/behavior/neo_bot_tactical_monitor.h index 83634acfc..0cfe08a0d 100644 --- a/src/game/server/neo/bot/behavior/neo_bot_tactical_monitor.h +++ b/src/game/server/neo/bot/behavior/neo_bot_tactical_monitor.h @@ -33,6 +33,8 @@ class CNEOBotTacticalMonitor : public Action< CNEOBot > CountdownTimer m_attentionTimer; std::unique_ptr m_pIgnoredWeapons; + CountdownTimer m_detpackCheckTimer; + ActionResult< CNEOBot > MonitorArmedDetpack(CNEOBot *me); #if 0 CountdownTimer m_stickyBombCheckTimer; void MonitorArmedStickyBombs(CNEOBot* me); diff --git a/src/game/shared/neo/neo_gamerules.h b/src/game/shared/neo/neo_gamerules.h index 7d3045be3..af67c7686 100644 --- a/src/game/shared/neo/neo_gamerules.h +++ b/src/game/shared/neo/neo_gamerules.h @@ -86,6 +86,7 @@ class CNEO_Player; class CWeaponGhost; class CNEOBotCtgLoneWolf; class CNEOBotCtgLoneWolfAmbush; +class CNEOBotCtgLoneWolfDetpack; class CNEOBotCtgLoneWolfSeek; class CNEOBotSeekAndDestroy; diff --git a/src/game/shared/neo/weapons/weapon_detpack.cpp b/src/game/shared/neo/weapons/weapon_detpack.cpp index 8228525a9..510cdc1ef 100644 --- a/src/game/shared/neo/weapons/weapon_detpack.cpp +++ b/src/game/shared/neo/weapons/weapon_detpack.cpp @@ -19,6 +19,7 @@ #include "te_effect_dispatch.h" #include "grenade_frag.h" #include "eventqueue.h" +#include "soundent.h" #endif #include "effect_dispatch_data.h" @@ -251,7 +252,7 @@ void CWeaponDetpack::ItemPostFrame(void) pOwner->DoAnimationEvent(PLAYERANIMEVENT_ATTACK_PRIMARY); // NEO NOTE (Rain): Why 0.9? Because we want the explosion to occur after 2.666... seconds of detpack arming, - // plus 1.333... seconds of the trigger, for a total of 4 seconds delay. And we just happen to need 0.9 seconds + // plus ~1.333... seconds of the trigger, for a total of 4 seconds delay. And we just happen to need 0.9 seconds // here to reach that. There's probably some nicer way to arrive at these values, but that's the explanation // for this magic value. m_flNextPrimaryAttack = gpGlobals->curtime + 0.9; @@ -304,6 +305,10 @@ void CWeaponDetpack::TossDetpack(CBasePlayer* pPlayer) { Assert(false); } + + // Notify bots after pressing keypad since reacting immediately to press fire is unforgiving + // especially since the sound clip has some silence at the beginning + CSoundEnt::InsertSound( SOUND_COMBAT, pPlayer->GetAbsOrigin(), 256, 0.2, pPlayer, SOUNDENT_CHANNEL_WEAPON ); #endif if (GetOwner()->IsPlayer()) // NEO NOTE (Adam) if else taken from CBaseCombatWeapon::Equip, this must be what was fixing the viewmodel previously after dropping and picking up the detremote { diff --git a/src/game/shared/neo/weapons/weapon_detpack.h b/src/game/shared/neo/weapons/weapon_detpack.h index 0a7938c6c..e46d6442d 100644 --- a/src/game/shared/neo/weapons/weapon_detpack.h +++ b/src/game/shared/neo/weapons/weapon_detpack.h @@ -53,6 +53,12 @@ class CWeaponDetpack : public CNEOBaseProjectile virtual float GetSpeedScale(void) const OVERRIDE { return 0.85f; } +#ifdef GAME_DLL + CNEODeployedDetpack* GetDetpackEntity() const { return m_pDetpack; } +#endif + + static float GetArmingTime() { return 2.66f; } // see Rain's comment in DecrementAmmo + bool CanDrop(void) OVERRIDE; virtual bool CanAim() final { return false; } virtual bool CanPerformSecondaryAttack() const override final { return false; }