aboutsummaryrefslogtreecommitdiff
path: root/sp/src/game/server/hl2/npc_launcher.cpp
diff options
context:
space:
mode:
authorJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
committerJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
commit39ed87570bdb2f86969d4be821c94b722dc71179 (patch)
treeabc53757f75f40c80278e87650ea92808274aa59 /sp/src/game/server/hl2/npc_launcher.cpp
downloadsource-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz
source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip
First version of the SOurce SDK 2013
Diffstat (limited to 'sp/src/game/server/hl2/npc_launcher.cpp')
-rw-r--r--sp/src/game/server/hl2/npc_launcher.cpp413
1 files changed, 413 insertions, 0 deletions
diff --git a/sp/src/game/server/hl2/npc_launcher.cpp b/sp/src/game/server/hl2/npc_launcher.cpp
new file mode 100644
index 00000000..098c6b4e
--- /dev/null
+++ b/sp/src/game/server/hl2/npc_launcher.cpp
@@ -0,0 +1,413 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "ai_basenpc.h"
+#include "ai_senses.h"
+#include "ai_squad.h"
+#include "grenade_homer.h"
+#include "grenade_pathfollower.h"
+#include "explode.h"
+#include "ndebugoverlay.h"
+#include "engine/IEngineSound.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#define LAUNCHER_REST_TIME 3
+
+
+//------------------------------------
+// Spawnflags
+//------------------------------------
+#define SF_LAUNCHER_CHECK_LOS (1 << 16)
+
+
+//=========================================================
+// >> CNPC_Launcher
+//=========================================================
+class CNPC_Launcher : public CAI_BaseNPC
+{
+ DECLARE_CLASS( CNPC_Launcher, CAI_BaseNPC );
+
+public:
+ int m_nStartOn;
+ string_t m_sMissileModel;
+ string_t m_sLaunchSound;
+ string_t m_sFlySound;
+ int m_nSmokeTrail;
+ bool m_bSmokeLaunch;
+ int m_nLaunchDelay;
+ float m_flLaunchSpeed;
+ string_t m_sPathCornerName; // If following a path
+ float m_flHomingSpeed;
+ int m_nHomingStrength;
+ float m_flHomingDelay; // How long before homing starts
+ float m_flHomingRampUp; // How much time to ramp up to full homing
+ float m_flHomingDuration; // How long does homing last
+ float m_flHomingRampDown; // How long to ramp down to no homing
+ float m_flMissileGravity;
+ float m_flMinAttackDist;
+ float m_flMaxAttackDist;
+ float m_flSpinMagnitude;
+ float m_flSpinSpeed;
+ float m_flDamage;
+ float m_flDamageRadius;
+
+ // ----------------
+ // Outputs
+ // ----------------
+ COutputEvent m_OnLaunch; // Triggered when missile is launched.
+
+ // ----------------
+ // Inputs
+ // ----------------
+ void InputTurnOn( inputdata_t &inputdata );
+ void InputTurnOff( inputdata_t &inputdata );
+ void InputLOSCheckOn( inputdata_t &inputdata );
+ void InputLOSCheckOff( inputdata_t &inputdata );
+ void InputSetEnemy( inputdata_t &inputdata );
+ void InputClearEnemy( inputdata_t &inputdata );
+ void InputFireOnce( inputdata_t &inputdata );
+
+ void LauncherTurnOn(void);
+
+ void Precache( void );
+ void Spawn( void );
+ Class_T Classify( void );
+ bool IsValidEnemy(CBaseEntity *pTarget );
+ void LaunchGrenade(CBaseEntity* pLauncher );
+ void LauncherThink(void );
+ bool FInViewCone( CBaseEntity *pEntity );
+
+ int DrawDebugTextOverlays(void);
+
+ DECLARE_DATADESC();
+};
+
+
+BEGIN_DATADESC( CNPC_Launcher )
+
+ // Inputs
+ DEFINE_KEYFIELD( m_nStartOn, FIELD_INTEGER, "StartOn" ),
+ DEFINE_KEYFIELD( m_sMissileModel, FIELD_STRING, "MissileModel" ),
+ DEFINE_KEYFIELD( m_sLaunchSound, FIELD_STRING, "LaunchSound" ),
+ DEFINE_KEYFIELD( m_sFlySound, FIELD_STRING, "FlySound" ),
+ DEFINE_KEYFIELD( m_nSmokeTrail, FIELD_INTEGER, "SmokeTrail" ),
+ DEFINE_KEYFIELD( m_bSmokeLaunch, FIELD_BOOLEAN, "LaunchSmoke" ),
+ DEFINE_KEYFIELD( m_nLaunchDelay, FIELD_INTEGER, "LaunchDelay" ),
+ DEFINE_KEYFIELD( m_flLaunchSpeed, FIELD_FLOAT, "LaunchSpeed" ),
+ DEFINE_KEYFIELD( m_sPathCornerName, FIELD_STRING, "PathCornerName" ),
+ DEFINE_KEYFIELD( m_flHomingSpeed, FIELD_FLOAT, "HomingSpeed" ),
+ DEFINE_KEYFIELD( m_nHomingStrength, FIELD_INTEGER, "HomingStrength" ),
+ DEFINE_KEYFIELD( m_flHomingDelay, FIELD_FLOAT, "HomingDelay" ),
+ DEFINE_KEYFIELD( m_flHomingRampUp, FIELD_FLOAT, "HomingRampUp" ),
+ DEFINE_KEYFIELD( m_flHomingDuration, FIELD_FLOAT, "HomingDuration" ),
+ DEFINE_KEYFIELD( m_flHomingRampDown, FIELD_FLOAT, "HomingRampDown" ),
+ DEFINE_KEYFIELD( m_flGravity, FIELD_FLOAT, "Gravity" ),
+ DEFINE_KEYFIELD( m_flMinAttackDist, FIELD_FLOAT, "MinRange" ),
+ DEFINE_KEYFIELD( m_flMaxAttackDist, FIELD_FLOAT, "MaxRange" ),
+ DEFINE_KEYFIELD( m_flSpinMagnitude, FIELD_FLOAT, "SpinMagnitude" ),
+ DEFINE_KEYFIELD( m_flSpinSpeed, FIELD_FLOAT, "SpinSpeed" ),
+ DEFINE_KEYFIELD( m_flDamage, FIELD_FLOAT, "Damage" ),
+ DEFINE_KEYFIELD( m_flDamageRadius, FIELD_FLOAT, "DamageRadius" ),
+ DEFINE_FIELD( m_flMissileGravity, FIELD_FLOAT ),
+
+ DEFINE_INPUTFUNC( FIELD_VOID, "TurnOn", InputTurnOn ),
+ DEFINE_INPUTFUNC( FIELD_VOID, "TurnOff", InputTurnOff ),
+ DEFINE_INPUTFUNC( FIELD_VOID, "LOSCheckOn", InputLOSCheckOn ),
+ DEFINE_INPUTFUNC( FIELD_VOID, "LOSCheckOn", InputLOSCheckOn ),
+ DEFINE_INPUTFUNC( FIELD_VOID, "FireOnce", InputFireOnce ),
+ DEFINE_INPUTFUNC( FIELD_EHANDLE, "SetEnemyEntity", InputSetEnemy ),
+ DEFINE_INPUTFUNC( FIELD_VOID, "ClearEnemyEntity", InputClearEnemy ),
+
+ DEFINE_OUTPUT( m_OnLaunch, "OnLaunch" ),
+
+ // Function Pointers
+ DEFINE_THINKFUNC( LauncherThink ),
+
+END_DATADESC()
+
+LINK_ENTITY_TO_CLASS( npc_launcher, CNPC_Launcher );
+
+
+// ===================
+// Input Functions
+// ===================
+void CNPC_Launcher::InputTurnOn( inputdata_t &inputdata )
+{
+ LauncherTurnOn();
+}
+
+void CNPC_Launcher::InputTurnOff( inputdata_t &inputdata )
+{
+ SetThink(NULL);
+}
+
+void CNPC_Launcher::InputLOSCheckOn( inputdata_t &inputdata )
+{
+ m_spawnflags |= SF_LAUNCHER_CHECK_LOS;
+}
+
+void CNPC_Launcher::InputLOSCheckOff( inputdata_t &inputdata )
+{
+ m_spawnflags &= ~SF_LAUNCHER_CHECK_LOS;
+}
+
+void CNPC_Launcher::InputSetEnemy( inputdata_t &inputdata )
+{
+ SetEnemy( inputdata.value.Entity().Get() );
+}
+
+void CNPC_Launcher::InputClearEnemy( inputdata_t &inputdata )
+{
+ SetEnemy( NULL );
+}
+
+void CNPC_Launcher::InputFireOnce( inputdata_t &inputdata )
+{
+ m_flNextAttack = 0;
+
+ // If I using path following missiles just launch
+ if (m_sPathCornerName != NULL_STRING)
+ {
+ LaunchGrenade(NULL);
+ }
+ // Otherwise only launch if I have an enemy
+ else
+ {
+ LauncherThink();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CNPC_Launcher::Precache( void )
+{
+ // This is a dummy model that is never used!
+ PrecacheModel("models/player.mdl");
+ PrecacheModel(STRING(m_sMissileModel));
+ PrecacheScriptSound( STRING(m_sLaunchSound));
+ PrecacheScriptSound( STRING(m_sFlySound));
+
+ UTIL_PrecacheOther( "grenade_homer");
+ BaseClass::Precache();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CNPC_Launcher::LauncherTurnOn(void)
+{
+ SetThink(&CNPC_Launcher::LauncherThink);
+ SetNextThink( gpGlobals->curtime );
+ m_flNextAttack = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CNPC_Launcher::Spawn( void )
+{
+ Precache();
+
+ // This is a dummy model that is never used!
+ SetModel( "models/player.mdl" );
+
+ UTIL_SetSize(this, vec3_origin, vec3_origin);
+
+ m_takedamage = DAMAGE_NO;
+
+ if (m_nHomingStrength > 100)
+ {
+ m_nHomingStrength = 100;
+ Warning("WARNING: NPC_Launcher Homing Strength must be between 0 and 100\n");
+ }
+
+ SetSolid( SOLID_NONE );
+ SetMoveType( MOVETYPE_NONE );
+ SetBloodColor( DONT_BLEED );
+ AddEffects( EF_NODRAW );
+
+ AddFlag( FL_NPC );
+
+ CapabilitiesAdd( bits_CAP_SQUAD );
+
+ InitRelationshipTable();
+
+ if (m_nStartOn)
+ {
+ LauncherTurnOn();
+ }
+
+ // -------------------------------------------------------
+ // If I form squads add me to a squad
+ // -------------------------------------------------------
+ // @TODO (toml 12-05-02): RECONCILE WITH SAVE/RESTORE
+ if (!m_pSquad)
+ {
+ m_pSquad = g_AI_SquadManager.FindCreateSquad(this, m_SquadName);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+Class_T CNPC_Launcher::Classify( void )
+{
+ return CLASS_NONE;
+}
+
+//------------------------------------------------------------------------------
+// Purpose:
+//------------------------------------------------------------------------------
+void CNPC_Launcher::LaunchGrenade( CBaseEntity* pEnemy )
+{
+ // If a path following missile, create a path following missile
+ if (m_sPathCornerName != NULL_STRING)
+ {
+ CGrenadePathfollower *pGrenade = CGrenadePathfollower::CreateGrenadePathfollower( m_sMissileModel, m_sFlySound, GetAbsOrigin(), vec3_angle, edict() );
+ pGrenade->SetDamage(m_flDamage);
+ pGrenade->SetDamageRadius(m_flDamageRadius);
+ pGrenade->Launch(m_flLaunchSpeed,m_sPathCornerName);
+ }
+ else
+ {
+ Vector vUp;
+ AngleVectors( GetAbsAngles(), NULL, NULL, &vUp );
+ Vector vLaunchVelocity = (vUp * m_flLaunchSpeed);
+
+ CGrenadeHomer *pGrenade = CGrenadeHomer::CreateGrenadeHomer( m_sMissileModel, m_sFlySound, GetAbsOrigin(), vec3_angle, edict() );
+ pGrenade->Spawn( );
+ pGrenade->SetSpin(m_flSpinMagnitude,m_flSpinSpeed);
+ pGrenade->SetHoming((0.01*m_nHomingStrength),m_flHomingDelay,m_flHomingRampUp,m_flHomingDuration,m_flHomingRampDown);
+ pGrenade->SetDamage(m_flDamage);
+ pGrenade->SetDamageRadius(m_flDamageRadius);
+ pGrenade->Launch(this,pEnemy,vLaunchVelocity,m_flHomingSpeed,GetGravity(),m_nSmokeTrail);
+ }
+
+ CPASAttenuationFilter filter( this, 0.3 );
+
+ EmitSound_t ep;
+ ep.m_nChannel = CHAN_WEAPON;
+ ep.m_pSoundName = STRING(m_sLaunchSound);
+ ep.m_SoundLevel = SNDLVL_NORM;
+
+ EmitSound( filter, entindex(), ep );
+
+ if (m_bSmokeLaunch)
+ {
+ UTIL_Smoke(GetAbsOrigin(), random->RandomInt(20,30), random->RandomInt(10,15));
+ }
+ m_flNextAttack = gpGlobals->curtime + LAUNCHER_REST_TIME;
+
+}
+
+//------------------------------------------------------------------------------
+// Purpose : Launcher sees 360 degrees
+//------------------------------------------------------------------------------
+bool CNPC_Launcher::FInViewCone( CBaseEntity *pEntity )
+{
+ return true;
+}
+
+//------------------------------------------------------------------------------
+// Purpose : Override base class to check range and visibility
+//------------------------------------------------------------------------------
+bool CNPC_Launcher::IsValidEnemy( CBaseEntity *pTarget )
+{
+ // ---------------------------------
+ // Check range
+ // ---------------------------------
+ float flTargetDist = (GetAbsOrigin() - pTarget->GetAbsOrigin()).Length();
+ if (flTargetDist < m_flMinAttackDist)
+ {
+ return false;
+ }
+ if (flTargetDist > m_flMaxAttackDist)
+ {
+ return false;
+ }
+
+ if (!FBitSet (m_spawnflags, SF_LAUNCHER_CHECK_LOS))
+ {
+ return true;
+ }
+ // ------------------------------------------------------
+ // Make sure I can see the target from above my position
+ // ------------------------------------------------------
+ trace_t tr;
+
+ // Trace from launch position to target position.
+ // Use position above actual barral based on vertical launch speed
+ Vector vStartPos = GetAbsOrigin() + Vector(0,0,0.2*m_flLaunchSpeed);
+ Vector vEndPos = pTarget->GetAbsOrigin();
+ AI_TraceLine( vStartPos, vEndPos, MASK_SHOT, pTarget, COLLISION_GROUP_NONE, &tr );
+
+ if (tr.fraction == 1.0)
+ {
+ return true;
+ }
+ return false;
+}
+
+//------------------------------------------------------------------------------
+// Purpose :
+//------------------------------------------------------------------------------
+void CNPC_Launcher::LauncherThink( void )
+{
+ if (gpGlobals->curtime > m_flNextAttack)
+ {
+ // If enemy was set, fire at enemy
+ if (GetEnemy())
+ {
+ LaunchGrenade(GetEnemy());
+ m_OnLaunch.FireOutput(GetEnemy(), this);
+ m_flNextAttack = gpGlobals->curtime + m_nLaunchDelay;
+ }
+ // Otherwise look for enemy to fire at
+ else
+ {
+ GetSenses()->Look(m_flMaxAttackDist);
+ CBaseEntity* pBestEnemy = BestEnemy();
+
+ if (pBestEnemy)
+ {
+ LaunchGrenade(pBestEnemy);
+ m_OnLaunch.FireOutput(pBestEnemy, this);
+ m_flNextAttack = gpGlobals->curtime + m_nLaunchDelay;
+ }
+ }
+ }
+ SetNextThink( gpGlobals->curtime + 0.1f );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Draw any debug text overlays
+// Output : Current text offset from the top
+//-----------------------------------------------------------------------------
+int CNPC_Launcher::DrawDebugTextOverlays(void)
+{
+ int text_offset = BaseClass::DrawDebugTextOverlays();
+
+ if (m_debugOverlays & OVERLAY_TEXT_BIT)
+ {
+ char tempstr[512];
+ Q_snprintf(tempstr,sizeof(tempstr),"State: %s", (m_pfnThink) ? "On" : "Off" );
+ EntityText(text_offset,tempstr,0);
+ text_offset++;
+
+ Q_snprintf(tempstr,sizeof(tempstr),"LOS: %s", (FBitSet (m_spawnflags, SF_LAUNCHER_CHECK_LOS)) ? "On" : "Off" );
+ EntityText(text_offset,tempstr,0);
+ text_offset++;
+ }
+ return text_offset;
+}