You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
704 lines
18 KiB
704 lines
18 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: Combine gun turret that emerges from a trapdoor in the ground. |
|
// |
|
//=============================================================================// |
|
#include "cbase.h" |
|
#include "npc_turret_ground.h" |
|
#include "ai_default.h" |
|
#include "ai_task.h" |
|
#include "ai_schedule.h" |
|
#include "ai_hull.h" |
|
#include "ai_senses.h" |
|
#include "ai_memory.h" |
|
#include "soundent.h" |
|
#include "game.h" |
|
#include "vstdlib/random.h" |
|
#include "engine/IEngineSound.h" |
|
#include "npcevent.h" |
|
#include "IEffects.h" |
|
#include "ammodef.h" |
|
#include "beam_shared.h" |
|
#include "explode.h" |
|
#include "te_effect_dispatch.h" |
|
|
|
#define GROUNDTURRET_BEAM_SPRITE "materials/effects/bluelaser2.vmt" |
|
|
|
#define GROUNDTURRET_VIEWCONE 60.0f // (degrees) |
|
#define GROUNDTURRET_RETIRE_TIME 7.0f |
|
|
|
ConVar ai_newgroundturret ( "ai_newgroundturret", "0" ); |
|
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
LINK_ENTITY_TO_CLASS( npc_turret_ground, CNPC_GroundTurret ); |
|
|
|
//--------------------------------------------------------- |
|
// Save/Restore |
|
//--------------------------------------------------------- |
|
BEGIN_DATADESC( CNPC_GroundTurret ) |
|
DEFINE_FIELD( m_iAmmoType, FIELD_INTEGER ), |
|
DEFINE_FIELD( m_pSmoke, FIELD_CLASSPTR ), |
|
DEFINE_FIELD( m_vecSpread, FIELD_VECTOR ), |
|
DEFINE_FIELD( m_bEnabled, FIELD_BOOLEAN ), |
|
DEFINE_FIELD( m_flTimeNextShoot, FIELD_TIME ), |
|
DEFINE_FIELD( m_flTimeLastSawEnemy, FIELD_TIME ), |
|
DEFINE_FIELD( m_iDeathSparks, FIELD_INTEGER ), |
|
DEFINE_FIELD( m_bHasExploded, FIELD_BOOLEAN ), |
|
DEFINE_FIELD( m_flSensingDist, FIELD_FLOAT ), |
|
DEFINE_FIELD( m_flTimeNextPing, FIELD_TIME ), |
|
DEFINE_FIELD( m_bSeeEnemy, FIELD_BOOLEAN ), |
|
DEFINE_FIELD( m_vecClosedPos, FIELD_POSITION_VECTOR ), |
|
DEFINE_FIELD( m_vecLightOffset, FIELD_POSITION_VECTOR ), |
|
|
|
DEFINE_THINKFUNC( DeathEffects ), |
|
|
|
DEFINE_OUTPUT( m_OnAreaClear, "OnAreaClear" ), |
|
|
|
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ), |
|
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ), |
|
|
|
// DEFINE_FIELD( m_ShotSounds, FIELD_SHORT ), |
|
END_DATADESC() |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CNPC_GroundTurret::Precache( void ) |
|
{ |
|
PrecacheModel( GROUNDTURRET_BEAM_SPRITE ); |
|
PrecacheModel( "models/combine_turrets/ground_turret.mdl" ); |
|
|
|
PrecacheScriptSound( "NPC_CeilingTurret.Deploy" ); |
|
m_ShotSounds = PrecacheScriptSound( "NPC_FloorTurret.ShotSounds" ); |
|
PrecacheScriptSound( "NPC_FloorTurret.Die" ); |
|
PrecacheScriptSound( "NPC_FloorTurret.Ping" ); |
|
PrecacheScriptSound( "DoSpark" ); |
|
|
|
BaseClass::Precache(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CNPC_GroundTurret::Spawn( void ) |
|
{ |
|
Precache(); |
|
|
|
UTIL_SetModel( this, "models/combine_turrets/ground_turret.mdl" ); |
|
|
|
SetNavType( NAV_FLY ); |
|
SetSolid( SOLID_VPHYSICS ); |
|
|
|
SetBloodColor( DONT_BLEED ); |
|
m_iHealth = 125; |
|
m_flFieldOfView = cos( ((GROUNDTURRET_VIEWCONE / 2.0f) * M_PI / 180.0f) ); |
|
m_NPCState = NPC_STATE_NONE; |
|
|
|
m_vecSpread.x = 0.5; |
|
m_vecSpread.y = 0.5; |
|
m_vecSpread.z = 0.5; |
|
|
|
CapabilitiesClear(); |
|
|
|
AddEFlags( EFL_NO_DISSOLVE ); |
|
|
|
NPCInit(); |
|
|
|
CapabilitiesAdd( bits_CAP_SIMPLE_RADIUS_DAMAGE ); |
|
|
|
m_iAmmoType = GetAmmoDef()->Index( "PISTOL" ); |
|
|
|
m_pSmoke = NULL; |
|
|
|
m_bHasExploded = false; |
|
m_bEnabled = false; |
|
|
|
if( ai_newgroundturret.GetBool() ) |
|
{ |
|
m_flSensingDist = 384; |
|
SetDistLook( m_flSensingDist ); |
|
} |
|
else |
|
{ |
|
m_flSensingDist = 2048; |
|
} |
|
|
|
if( !GetParent() ) |
|
{ |
|
DevMsg("ERROR! npc_ground_turret with no parent!\n"); |
|
UTIL_Remove(this); |
|
return; |
|
} |
|
|
|
m_flTimeNextShoot = gpGlobals->curtime; |
|
m_flTimeNextPing = gpGlobals->curtime; |
|
|
|
m_vecClosedPos = GetAbsOrigin(); |
|
|
|
StudioFrameAdvance(); |
|
|
|
Vector vecPos; |
|
|
|
GetAttachment( "eyes", vecPos ); |
|
SetViewOffset( vecPos - GetAbsOrigin() ); |
|
|
|
GetAttachment( "light", vecPos ); |
|
m_vecLightOffset = vecPos - GetAbsOrigin(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
//----------------------------------------------------------------------------- |
|
bool CNPC_GroundTurret::CreateVPhysics( void ) |
|
{ |
|
//Spawn our physics hull |
|
if ( !VPhysicsInitStatic() ) |
|
{ |
|
DevMsg( "npc_turret_ground unable to spawn physics object!\n" ); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
//----------------------------------------------------------------------------- |
|
void CNPC_GroundTurret::PrescheduleThink() |
|
{ |
|
if( UTIL_FindClientInPVS(edict()) ) |
|
{ |
|
SetNextThink( gpGlobals->curtime + 0.03f ); |
|
} |
|
else |
|
{ |
|
SetNextThink( gpGlobals->curtime + 0.1f ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
Class_T CNPC_GroundTurret::Classify( void ) |
|
{ |
|
if( !IsOpen() ) |
|
{ |
|
// NPC's should disregard me if I'm closed. |
|
return CLASS_NONE; |
|
} |
|
else |
|
{ |
|
return CLASS_COMBINE; |
|
} |
|
} |
|
|
|
//--------------------------------------------------------- |
|
//--------------------------------------------------------- |
|
void CNPC_GroundTurret::PostNPCInit() |
|
{ |
|
BaseClass::PostNPCInit(); |
|
} |
|
|
|
//--------------------------------------------------------- |
|
//--------------------------------------------------------- |
|
int CNPC_GroundTurret::OnTakeDamage_Alive( const CTakeDamageInfo &info ) |
|
{ |
|
if( !info.GetInflictor() ) |
|
{ |
|
return 0; |
|
} |
|
|
|
// Only take damage from self (kill input from my bullseye) or missiles. |
|
if( info.GetInflictor() != this && info.GetInflictor()->Classify() != CLASS_MISSILE ) |
|
{ |
|
return 0; |
|
} |
|
|
|
CTakeDamageInfo infoCopy = info; |
|
|
|
if( info.GetInflictor() == this ) |
|
{ |
|
// Taking damage from myself, make sure it's fatal. |
|
infoCopy.SetDamage( GetHealth() ); |
|
infoCopy.SetDamageType( DMG_REMOVENORAGDOLL | DMG_GENERIC ); |
|
} |
|
|
|
return BaseClass::OnTakeDamage_Alive( infoCopy ); |
|
} |
|
|
|
//--------------------------------------------------------- |
|
//--------------------------------------------------------- |
|
void CNPC_GroundTurret::Event_Killed( const CTakeDamageInfo &info ) |
|
{ |
|
BaseClass::Event_Killed( info ); |
|
|
|
if ( m_pSmoke != NULL ) |
|
return; |
|
|
|
m_pSmoke = SmokeTrail::CreateSmokeTrail(); |
|
|
|
if ( m_pSmoke ) |
|
{ |
|
m_pSmoke->m_SpawnRate = 18; |
|
m_pSmoke->m_ParticleLifetime = 3.0; |
|
m_pSmoke->m_StartSize = 8; |
|
m_pSmoke->m_EndSize = 32; |
|
m_pSmoke->m_SpawnRadius = 16; |
|
m_pSmoke->m_MinSpeed = 8; |
|
m_pSmoke->m_MaxSpeed = 32; |
|
m_pSmoke->m_Opacity = 0.6; |
|
|
|
m_pSmoke->m_StartColor.Init( 0.25f, 0.25f, 0.25f ); |
|
m_pSmoke->m_EndColor.Init( 0, 0, 0 ); |
|
m_pSmoke->SetLifetime( 30.0f ); |
|
m_pSmoke->FollowEntity( this ); |
|
} |
|
|
|
m_iDeathSparks = random->RandomInt( 6, 12 ); |
|
|
|
SetThink( &CNPC_GroundTurret::DeathEffects ); |
|
SetNextThink( gpGlobals->curtime + 1.5f ); |
|
} |
|
|
|
//--------------------------------------------------------- |
|
//--------------------------------------------------------- |
|
void CNPC_GroundTurret::DeathEffects() |
|
{ |
|
if( !m_bHasExploded ) |
|
{ |
|
//ExplosionCreate( GetAbsOrigin(), QAngle( 0, 0, 1 ), this, 150, 150, false ); |
|
CTakeDamageInfo info; |
|
DeathSound( info ); |
|
m_bHasExploded = true; |
|
SetNextThink( gpGlobals->curtime + 0.5 ); |
|
} |
|
else |
|
{ |
|
// Sparks |
|
EmitSound( "DoSpark" ); |
|
m_iDeathSparks--; |
|
|
|
if( m_iDeathSparks == 0 ) |
|
{ |
|
SetThink(NULL); |
|
return; |
|
} |
|
|
|
SetNextThink( gpGlobals->curtime + random->RandomFloat( 0.5, 2.5 ) ); |
|
} |
|
} |
|
|
|
//--------------------------------------------------------- |
|
//--------------------------------------------------------- |
|
void CNPC_GroundTurret::DeathSound( const CTakeDamageInfo &info ) |
|
{ |
|
EmitSound("NPC_FloorTurret.Die"); |
|
} |
|
|
|
//--------------------------------------------------------- |
|
//--------------------------------------------------------- |
|
void CNPC_GroundTurret::MakeTracer( const Vector &vecTracerSrc, const trace_t &tr, int iTracerType ) |
|
{ |
|
#if 1 |
|
//BaseClass::MakeTracer( vecTracerSrc, tr, iTracerType ); |
|
UTIL_Tracer( vecTracerSrc, tr.endpos, 0, TRACER_DONT_USE_ATTACHMENT, 5000, true, "AR2Tracer" ); |
|
#else |
|
CBeam *pBeam; |
|
int width = 2; |
|
|
|
pBeam = CBeam::BeamCreate( GROUNDTURRET_BEAM_SPRITE, width ); |
|
if ( !pBeam ) |
|
return; |
|
|
|
pBeam->SetStartPos( vecTracerSrc ); |
|
pBeam->SetEndPos( tr.endpos ); |
|
pBeam->SetWidth( width ); |
|
pBeam->SetEndWidth( width / 4.0f ); |
|
|
|
pBeam->SetBrightness( 100 ); |
|
pBeam->SetColor( 0, 145+random->RandomInt( -16, 16 ), 255 ); |
|
pBeam->RelinkBeam(); |
|
pBeam->LiveForTime( random->RandomFloat( 0.2f, 0.5f ) ); |
|
#endif |
|
} |
|
|
|
//--------------------------------------------------------- |
|
//--------------------------------------------------------- |
|
void CNPC_GroundTurret::GatherConditions() |
|
{ |
|
if( !IsEnabled() ) |
|
{ |
|
return; |
|
} |
|
|
|
if( !IsOpen() && !UTIL_FindClientInPVS( edict() ) ) |
|
{ |
|
return; |
|
} |
|
|
|
// Throw away old enemies so the turret can retire |
|
AIEnemiesIter_t iter; |
|
|
|
for( AI_EnemyInfo_t *pEMemory = GetEnemies()->GetFirst(&iter); pEMemory != NULL; pEMemory = GetEnemies()->GetNext(&iter) ) |
|
{ |
|
if( pEMemory->timeLastSeen < gpGlobals->curtime - GROUNDTURRET_RETIRE_TIME ) |
|
{ |
|
pEMemory->hEnemy = NULL; |
|
} |
|
} |
|
|
|
BaseClass::GatherConditions(); |
|
|
|
if( GetEnemy() && HasCondition(COND_SEE_ENEMY) ) |
|
{ |
|
m_flTimeLastSawEnemy = gpGlobals->curtime; |
|
} |
|
else |
|
{ |
|
if( gpGlobals->curtime - m_flTimeLastSawEnemy >= GROUNDTURRET_RETIRE_TIME ) |
|
{ |
|
m_OnAreaClear.FireOutput(this, this); |
|
m_flTimeLastSawEnemy = FLT_MAX; |
|
return; |
|
} |
|
} |
|
|
|
if( HasCondition( COND_SEE_ENEMY ) ) |
|
{ |
|
m_bSeeEnemy = true; |
|
} |
|
else |
|
{ |
|
m_bSeeEnemy = false; |
|
} |
|
|
|
if( GetEnemy() && m_bSeeEnemy && IsEnabled() ) |
|
{ |
|
if( m_flTimeNextShoot < gpGlobals->curtime ) |
|
{ |
|
Shoot(); |
|
} |
|
} |
|
} |
|
|
|
//--------------------------------------------------------- |
|
//--------------------------------------------------------- |
|
Vector CNPC_GroundTurret::EyePosition() |
|
{ |
|
if( ai_newgroundturret.GetBool() ) |
|
{ |
|
return GetAbsOrigin() + Vector( 0, 0, 6 ); |
|
} |
|
|
|
return GetAbsOrigin() + GetViewOffset(); |
|
} |
|
|
|
//--------------------------------------------------------- |
|
//--------------------------------------------------------- |
|
bool CNPC_GroundTurret::FVisible( CBaseEntity *pEntity, int traceMask, CBaseEntity **ppBlocker ) |
|
{ |
|
if ( BaseClass::FVisible( pEntity, traceMask, ppBlocker ) ) |
|
return true; |
|
if ( ( pEntity->GetAbsOrigin().AsVector2D() - GetAbsOrigin().AsVector2D() ).LengthSqr() < Square(10*12) && |
|
FInViewCone( pEntity->GetAbsOrigin() ) && |
|
BaseClass::FVisible( pEntity->GetAbsOrigin() + Vector( 0, 0, 1 ), traceMask, ppBlocker ) ) |
|
return true; |
|
return false; |
|
} |
|
|
|
//--------------------------------------------------------- |
|
//--------------------------------------------------------- |
|
bool CNPC_GroundTurret::QuerySeeEntity( CBaseEntity *pEntity, bool bOnlyHateOrFearIfNPC) |
|
{ |
|
float flDist; |
|
|
|
flDist = (pEntity->GetAbsOrigin() - EyePosition()).Length2DSqr(); |
|
|
|
if( flDist <= m_flSensingDist * m_flSensingDist ) |
|
{ |
|
return BaseClass::QuerySeeEntity(pEntity, bOnlyHateOrFearIfNPC); |
|
} |
|
|
|
return false; |
|
} |
|
|
|
//--------------------------------------------------------- |
|
//--------------------------------------------------------- |
|
bool CNPC_GroundTurret::IsEnabled() |
|
{ |
|
if( ai_newgroundturret.GetBool() ) |
|
{ |
|
return true; |
|
} |
|
|
|
return m_bEnabled; |
|
} |
|
|
|
//--------------------------------------------------------- |
|
//--------------------------------------------------------- |
|
bool CNPC_GroundTurret::IsOpen() |
|
{ |
|
// The method is hacky but in the end, this does actually give |
|
// us a pretty good idea if the turret is open or closed. |
|
return( fabs(GetAbsOrigin().z - m_vecClosedPos.z ) > 1.0f ); |
|
} |
|
|
|
//--------------------------------------------------------- |
|
//--------------------------------------------------------- |
|
void CNPC_GroundTurret::StartTask( const Task_t *pTask ) |
|
{ |
|
switch( pTask->iTask ) |
|
{ |
|
case TASK_GROUNDTURRET_SCAN: |
|
Scan(); |
|
break; |
|
|
|
default: |
|
BaseClass::StartTask( pTask ); |
|
break; |
|
} |
|
} |
|
|
|
//--------------------------------------------------------- |
|
//--------------------------------------------------------- |
|
void CNPC_GroundTurret::RunTask( const Task_t *pTask ) |
|
{ |
|
switch( pTask->iTask ) |
|
{ |
|
case TASK_GROUNDTURRET_SCAN: |
|
Scan(); |
|
break; |
|
|
|
default: |
|
BaseClass::RunTask( pTask ); |
|
break; |
|
} |
|
} |
|
|
|
//--------------------------------------------------------- |
|
//--------------------------------------------------------- |
|
int CNPC_GroundTurret::SelectSchedule( void ) |
|
{ |
|
return SCHED_GROUND_TURRET_IDLE; |
|
} |
|
|
|
//--------------------------------------------------------- |
|
//--------------------------------------------------------- |
|
int CNPC_GroundTurret::TranslateSchedule( int scheduleType ) |
|
{ |
|
switch( scheduleType ) |
|
{ |
|
case SCHED_IDLE_STAND: |
|
return SCHED_GROUND_TURRET_IDLE; |
|
break; |
|
} |
|
|
|
return BaseClass::TranslateSchedule( scheduleType ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Override base class activiites |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
Activity CNPC_GroundTurret::NPC_TranslateActivity( Activity activity ) |
|
{ |
|
return ACT_IDLE; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
//----------------------------------------------------------------------------- |
|
void CNPC_GroundTurret::Shoot() |
|
{ |
|
FireBulletsInfo_t info; |
|
|
|
Vector vecSrc = EyePosition(); |
|
Vector vecDir; |
|
|
|
GetVectors( &vecDir, NULL, NULL ); |
|
|
|
for( int i = 0 ; i < 1 ; i++ ) |
|
{ |
|
info.m_vecSrc = vecSrc; |
|
|
|
if( i > 0 || !GetEnemy()->IsPlayer() ) |
|
{ |
|
// Subsequent shots or shots at non-players random |
|
GetVectors( &info.m_vecDirShooting, NULL, NULL ); |
|
info.m_vecSpread = m_vecSpread; |
|
} |
|
else |
|
{ |
|
// First shot is at the enemy. |
|
info.m_vecDirShooting = GetActualShootTrajectory( vecSrc ); |
|
info.m_vecSpread = VECTOR_CONE_PRECALCULATED; |
|
} |
|
|
|
info.m_iTracerFreq = 1; |
|
info.m_iShots = 1; |
|
info.m_pAttacker = this; |
|
info.m_flDistance = MAX_COORD_RANGE; |
|
info.m_iAmmoType = m_iAmmoType; |
|
|
|
FireBullets( info ); |
|
} |
|
|
|
// Do the AR2 muzzle flash |
|
CEffectData data; |
|
data.m_nEntIndex = entindex(); |
|
data.m_nAttachmentIndex = LookupAttachment( "eyes" ); |
|
data.m_flScale = 1.0f; |
|
data.m_fFlags = MUZZLEFLASH_COMBINE; |
|
DispatchEffect( "MuzzleFlash", data ); |
|
|
|
EmitSound( "NPC_FloorTurret.ShotSounds", m_ShotSounds ); |
|
|
|
if( IsX360() ) |
|
{ |
|
m_flTimeNextShoot = gpGlobals->curtime + 0.2; |
|
} |
|
else |
|
{ |
|
m_flTimeNextShoot = gpGlobals->curtime + 0.09; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
//----------------------------------------------------------------------------- |
|
void CNPC_GroundTurret::ProjectBeam( const Vector &vecStart, const Vector &vecDir, int width, int brightness, float duration ) |
|
{ |
|
CBeam *pBeam; |
|
pBeam = CBeam::BeamCreate( GROUNDTURRET_BEAM_SPRITE, width ); |
|
if ( !pBeam ) |
|
return; |
|
|
|
trace_t tr; |
|
AI_TraceLine( vecStart, vecStart + vecDir * m_flSensingDist, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); |
|
|
|
pBeam->SetStartPos( tr.endpos ); |
|
pBeam->SetEndPos( tr.startpos ); |
|
pBeam->SetWidth( width ); |
|
pBeam->SetEndWidth( 0.1 ); |
|
pBeam->SetFadeLength( 16 ); |
|
|
|
pBeam->SetBrightness( brightness ); |
|
pBeam->SetColor( 0, 145+random->RandomInt( -16, 16 ), 255 ); |
|
pBeam->RelinkBeam(); |
|
pBeam->LiveForTime( duration ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
//----------------------------------------------------------------------------- |
|
void CNPC_GroundTurret::Scan() |
|
{ |
|
if( m_bSeeEnemy ) |
|
{ |
|
// Using a bool for this check because the condition gets wiped out by changing schedules. |
|
return; |
|
} |
|
|
|
if( IsOpeningOrClosing() ) |
|
{ |
|
// Moving. |
|
return; |
|
} |
|
|
|
if( !IsOpen() ) |
|
{ |
|
// Closed |
|
return; |
|
} |
|
|
|
if( !UTIL_FindClientInPVS(edict()) ) |
|
{ |
|
return; |
|
} |
|
|
|
if( gpGlobals->curtime >= m_flTimeNextPing ) |
|
{ |
|
EmitSound( "NPC_FloorTurret.Ping" ); |
|
m_flTimeNextPing = gpGlobals->curtime + 1.0f; |
|
} |
|
|
|
QAngle scanAngle; |
|
Vector forward; |
|
Vector vecEye = GetAbsOrigin() + m_vecLightOffset; |
|
|
|
// Draw the outer extents |
|
scanAngle = GetAbsAngles(); |
|
scanAngle.y += (GROUNDTURRET_VIEWCONE / 2.0f); |
|
AngleVectors( scanAngle, &forward, NULL, NULL ); |
|
ProjectBeam( vecEye, forward, 1, 30, 0.1 ); |
|
|
|
scanAngle = GetAbsAngles(); |
|
scanAngle.y -= (GROUNDTURRET_VIEWCONE / 2.0f); |
|
AngleVectors( scanAngle, &forward, NULL, NULL ); |
|
ProjectBeam( vecEye, forward, 1, 30, 0.1 ); |
|
|
|
// Draw a sweeping beam |
|
scanAngle = GetAbsAngles(); |
|
scanAngle.y += (GROUNDTURRET_VIEWCONE / 2.0f) * sin( gpGlobals->curtime * 3.0f ); |
|
|
|
AngleVectors( scanAngle, &forward, NULL, NULL ); |
|
ProjectBeam( vecEye, forward, 1, 30, 0.3 ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
//----------------------------------------------------------------------------- |
|
void CNPC_GroundTurret::InputEnable( inputdata_t &inputdata ) |
|
{ |
|
m_bEnabled = true; |
|
|
|
// Because the turret might not ever ACQUIRE an enemy, we need to arrange to |
|
// retire after a few seconds. |
|
m_flTimeLastSawEnemy = gpGlobals->curtime; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
//----------------------------------------------------------------------------- |
|
void CNPC_GroundTurret::InputDisable( inputdata_t &inputdata ) |
|
{ |
|
m_bEnabled = false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
// Schedules |
|
// |
|
//----------------------------------------------------------------------------- |
|
|
|
AI_BEGIN_CUSTOM_NPC( npc_groundturret, CNPC_GroundTurret ) |
|
|
|
DECLARE_TASK( TASK_GROUNDTURRET_SCAN ); |
|
|
|
DEFINE_SCHEDULE |
|
( |
|
SCHED_GROUND_TURRET_IDLE, |
|
|
|
" Tasks " |
|
" TASK_SET_ACTIVITY ACTIVITY:ACT_IDLE" |
|
" TASK_GROUNDTURRET_SCAN 0" |
|
"" |
|
" Interrupts " |
|
" COND_NEW_ENEMY" |
|
" COND_SEE_ENEMY" |
|
" COND_LOST_ENEMY" |
|
) |
|
|
|
DEFINE_SCHEDULE |
|
( |
|
SCHED_GROUND_TURRET_ATTACK, |
|
|
|
" Tasks " |
|
" TASK_WAIT_INDEFINITE 0" |
|
"" |
|
" Interrupts " |
|
" COND_NEW_ENEMY" |
|
" COND_LOST_ENEMY" |
|
" COND_SEE_ENEMY" |
|
) |
|
|
|
AI_END_CUSTOM_NPC() |
|
|
|
|