📄 hl1_npc_turret.cpp
字号:
{
if (gpGlobals->curtime > m_flLastSight)
{
SetEnemy( NULL );
m_flLastSight = gpGlobals->curtime + m_flMaxWait;
SetThink(&CNPC_BaseTurret::SearchThink);
return;
}
}
}
Vector vecMid = GetAbsOrigin() + GetViewOffset();
Vector vecMidEnemy = GetEnemy()->BodyTarget( vecMid, false );
// Look for our current enemy
int fEnemyVisible = FBoxVisible(this, GetEnemy(), vecMidEnemy );
//We want to look at the enemy's eyes so we don't jitter
Vector vecDirToEnemyEyes = vecMidEnemy - vecMid;
float flDistToEnemy = vecDirToEnemyEyes.Length();
VectorNormalize( vecDirToEnemyEyes );
QAngle vecAnglesToEnemy;
VectorAngles( vecDirToEnemyEyes, vecAnglesToEnemy );
// Current enmey is not visible.
if (!fEnemyVisible || (flDistToEnemy > TURRET_RANGE))
{
if (!m_flLastSight)
m_flLastSight = gpGlobals->curtime + 0.5;
else
{
// Should we look for a new target?
if (gpGlobals->curtime > m_flLastSight)
{
SetEnemy( NULL );
m_flLastSight = gpGlobals->curtime + m_flMaxWait;
SetThink(&CNPC_BaseTurret::SearchThink);
return;
}
}
fEnemyVisible = 0;
}
else
{
m_vecLastSight = vecMidEnemy;
}
//ALERT( at_console, "%.0f %.0f : %.2f %.2f %.2f\n",
// m_vecCurAngles.x, m_vecCurAngles.y,
// gpGlobals->v_forward.x, gpGlobals->v_forward.y, gpGlobals->v_forward.z );
Vector vecLOS = vecDirToEnemyEyes; //vecMid - m_vecLastSight;
VectorNormalize( vecLOS );
Vector vecMuzzle, vecMuzzleDir;
QAngle vecMuzzleAng;
GetAttachment( 1, vecMuzzle, vecMuzzleAng );
AngleVectors( vecMuzzleAng, &vecMuzzleDir );
// Is the Gun looking at the target
if (DotProduct(vecLOS, vecMuzzleDir) <= 0.866) // 30 degree slop
fAttack = FALSE;
else
fAttack = TRUE;
//forward
// NDebugOverlay::Line(vecMuzzle, vecMid + ( vecMuzzleDir * 200 ), 255,0,0, false, 0.1);
//LOS
// NDebugOverlay::Line(vecMuzzle, vecMid + ( vecLOS * 200 ), 0,0,255, false, 0.1);
// fire the gun
if (m_iSpin && ((fAttack) || (m_fBeserk)))
{
Vector vecOrigin;
QAngle vecAngles;
GetAttachment( 1, vecOrigin, vecAngles );
Shoot(vecOrigin, vecMuzzleDir );
SetTurretAnim(TURRET_ANIM_FIRE);
}
else
{
SetTurretAnim(TURRET_ANIM_SPIN);
}
//move the gun
if (m_fBeserk)
{
if (random->RandomInt(0,9) == 0)
{
m_vecGoalAngles.y = random->RandomFloat(0,360);
m_vecGoalAngles.x = random->RandomFloat(0,90) - 90 * m_iOrientation;
CTakeDamageInfo info;
info.SetAttacker(this);
info.SetInflictor(this);
info.SetDamage( 1 );
info.SetDamageType( DMG_GENERIC );
TakeDamage( info ); // don't beserk forever
return;
}
}
else if (fEnemyVisible)
{
if (vecAnglesToEnemy.y > 360)
vecAnglesToEnemy.y -= 360;
if (vecAnglesToEnemy.y < 0)
vecAnglesToEnemy.y += 360;
//ALERT(at_console, "[%.2f]", vec.x);
if (vecAnglesToEnemy.x < -180)
vecAnglesToEnemy.x += 360;
if (vecAnglesToEnemy.x > 180)
vecAnglesToEnemy.x -= 360;
// now all numbers should be in [1...360]
// pin to turret limitations to [-90...14]
if (m_iOrientation == TURRET_ORIENTATION_FLOOR)
{
if (vecAnglesToEnemy.x > 90)
vecAnglesToEnemy.x = 90;
else if (vecAnglesToEnemy.x < m_iMinPitch)
vecAnglesToEnemy.x = m_iMinPitch;
}
else
{
if (vecAnglesToEnemy.x < -90)
vecAnglesToEnemy.x = -90;
else if (vecAnglesToEnemy.x > -m_iMinPitch)
vecAnglesToEnemy.x = -m_iMinPitch;
}
//DevMsg( 1, "->[%.2f]\n", vec.x);
m_vecGoalAngles.y = vecAnglesToEnemy.y;
m_vecGoalAngles.x = vecAnglesToEnemy.x;
}
SpinUpCall();
MoveTurret();
}
//=========================================================
// SearchThink
// This search function will sit with the turret deployed and look for a new target.
// After a set amount of time, the barrel will spin down. After m_flMaxWait, the turret will
// retact.
//=========================================================
void CNPC_BaseTurret::SearchThink(void)
{
// ensure rethink
SetTurretAnim(TURRET_ANIM_SPIN);
StudioFrameAdvance( );
SetNextThink( gpGlobals->curtime + 0.1 );
if (m_flSpinUpTime == 0 && m_flMaxSpin)
m_flSpinUpTime = gpGlobals->curtime + m_flMaxSpin;
Ping( );
CBaseEntity *pEnemy = GetEnemy();
// If we have a target and we're still healthy
if (pEnemy != NULL)
{
if (!pEnemy->IsAlive() )
pEnemy = NULL;// Dead enemy forces a search for new one
}
// Acquire Target
if (pEnemy == NULL)
{
GetSenses()->Look(TURRET_RANGE);
pEnemy = BestEnemy();
if ( pEnemy && !FVisible( pEnemy ) )
pEnemy = NULL;
}
// If we've found a target, spin up the barrel and start to attack
if (pEnemy != NULL)
{
m_flLastSight = 0;
m_flSpinUpTime = 0;
SetThink(&CNPC_BaseTurret::ActiveThink);
}
else
{
// Are we out of time, do we need to retract?
if (gpGlobals->curtime > m_flLastSight)
{
//Before we retrace, make sure that we are spun down.
m_flLastSight = 0;
m_flSpinUpTime = 0;
SetThink(&CNPC_BaseTurret::Retire);
}
// should we stop the spin?
else if ((m_flSpinUpTime) && (gpGlobals->curtime > m_flSpinUpTime))
{
SpinDownCall();
}
// generic hunt for new victims
m_vecGoalAngles.y = (m_vecGoalAngles.y + 0.1 * m_fTurnRate);
if (m_vecGoalAngles.y >= 360)
m_vecGoalAngles.y -= 360;
MoveTurret();
}
SetEnemy( pEnemy );
}
//=========================================================
// AutoSearchThink -
//=========================================================
void CNPC_BaseTurret::AutoSearchThink(void)
{
// ensure rethink
StudioFrameAdvance( );
SetNextThink( gpGlobals->curtime + 0.3 );
// If we have a target and we're still healthy
CBaseEntity *pEnemy = GetEnemy();
if (pEnemy != NULL)
{
if (!pEnemy->IsAlive() )
{
pEnemy = NULL;
}
}
// Acquire Target
if (pEnemy == NULL)
{
GetSenses()->Look( TURRET_RANGE );
pEnemy = BestEnemy();
if ( pEnemy && !FVisible( pEnemy ) )
pEnemy = NULL;
}
if (pEnemy != NULL)
{
SetThink(&CNPC_BaseTurret::Deploy);
CPASAttenuationFilter filter( this );
enginesound->EmitSound( filter, entindex(), CHAN_BODY, "turret/tu_alert.wav", TURRET_MACHINE_VOLUME, ATTN_NORM );
}
SetEnemy( pEnemy );
}
extern short g_sModelIndexSmoke;
//=========================================================
// TurretDeath - I die as I have lived, beyond my means
//=========================================================
void CNPC_BaseTurret::TurretDeath(void)
{
StudioFrameAdvance( );
SetNextThink( gpGlobals->curtime + 0.1 );
if (m_lifeState != LIFE_DEAD)
{
m_lifeState = LIFE_DEAD;
CPASAttenuationFilter filter( this );
switch( random->RandomInt(0,2) )
{
case 0:
enginesound->EmitSound( filter, entindex(), CHAN_BODY, "turret/tu_die.wav", TURRET_MACHINE_VOLUME, ATTN_NORM );
break;
case 1:
enginesound->EmitSound( filter, entindex(), CHAN_BODY, "turret/tu_die2.wav", TURRET_MACHINE_VOLUME, ATTN_NORM );
break;
case 2:
default:
enginesound->EmitSound( filter, entindex(), CHAN_BODY, "turret/tu_die3.wav", TURRET_MACHINE_VOLUME, ATTN_NORM );
break;
}
enginesound->StopSound( entindex(), CHAN_STATIC, "turret/tu_active2.wav" );
if (m_iOrientation == TURRET_ORIENTATION_FLOOR)
m_vecGoalAngles.x = -14;
else
m_vecGoalAngles.x = 90;//-90;
SetTurretAnim(TURRET_ANIM_DIE);
EyeOn( );
}
EyeOff( );
if (m_flDamageTime + random->RandomFloat( 0, 2 ) > gpGlobals->curtime)
{
// lots of smoke
Vector pos( random->RandomFloat( GetAbsMins().x, GetAbsMaxs().x ),
random->RandomFloat( GetAbsMins().y, GetAbsMaxs().y ),
GetAbsOrigin().z );
CBroadcastRecipientFilter filter;
te->Smoke( filter, 0.0, &pos,
g_sModelIndexSmoke,
2.5,
10 );
}
if (m_flDamageTime + random->RandomFloat( 0, 5 ) > gpGlobals->curtime)
{
Vector vecSrc = Vector( random->RandomFloat( GetAbsMins().x, GetAbsMaxs().x ), random->RandomFloat( GetAbsMins().y, GetAbsMaxs().y ), random->RandomFloat( GetAbsMins().z, GetAbsMaxs().z ) );
g_pEffects->Sparks( vecSrc );
}
if (IsSequenceFinished() && !MoveTurret() && m_flDamageTime + 5 < gpGlobals->curtime)
{
m_flPlaybackRate = 0;
SetThink( NULL );
}
}
//=========================================================
// Deploy - go active
//=========================================================
void CNPC_BaseTurret::Deploy(void)
{
SetNextThink( gpGlobals->curtime + 0.1 );
StudioFrameAdvance( );
if (GetSequence() != TURRET_ANIM_DEPLOY)
{
m_iOn = 1;
SetTurretAnim(TURRET_ANIM_DEPLOY);
CPASAttenuationFilter filter( this );
enginesound->EmitSound( filter, entindex(), CHAN_BODY, "turret/tu_deploy.wav", TURRET_MACHINE_VOLUME, ATTN_NORM );
m_OnActivate.FireOutput(this, this);
}
if (IsSequenceFinished())
{
Vector curmins, curmaxs;
curmins = WorldAlignMins();
curmaxs = WorldAlignMaxs();
curmaxs.z = m_iDeployHeight;
curmins.z = -m_iDeployHeight;
SetCollisionBounds( curmins, curmaxs );
Relink();
m_vecCurAngles.x = 0;
QAngle angles = GetAbsAngles();
if (m_iOrientation == TURRET_ORIENTATION_CEILING)
{
m_vecCurAngles.y = UTIL_AngleMod( angles.y + 180 );
}
else
{
m_vecCurAngles.y = UTIL_AngleMod( angles.y );
}
SetTurretAnim(TURRET_ANIM_SPIN);
m_flPlaybackRate = 0;
SetThink(&CNPC_BaseTurret::SearchThink);
}
m_flLastSight = gpGlobals->curtime + m_flMaxWait;
}
//=========================================================
// Retire - stop being active
//=========================================================
void CNPC_BaseTurret::Retire(void)
{
// make the turret level
m_vecGoalAngles.x = 0;
m_vecGoalAngles.y = m_flStartYaw;
SetNextThink( gpGlobals->curtime + 0.1 );
StudioFrameAdvance( );
EyeOff( );
if (!MoveTurret())
{
if (m_iSpin)
{
SpinDownCall();
}
else if (GetSequence() != TURRET_ANIM_RETIRE)
{
SetTurretAnim(TURRET_ANIM_RETIRE);
CPASAttenuationFilter filter( this );
enginesound->EmitSound( filter, entindex(), CHAN_BODY, "turret/tu_deploy.wav", TURRET_MACHINE_VOLUME, ATTN_NORM, 0, 120 );
m_OnDeactivate.FireOutput(this, this);
}
//else if (IsSequenceFinished())
else if( GetSequence() == TURRET_ANIM_RETIRE && m_flCycle <= 0.0 )
{
m_iOn = 0;
m_flLastSight = 0;
//SetTurretAnim(TURRET_ANIM_NONE);
Vector curmins, curmaxs;
curmins = WorldAlignMins();
curmaxs = WorldAlignMaxs();
curmaxs.z = m_iRetractHeight;
curmins.z = -m_iRetractHeight;
SetCollisionBounds( curmins, curmaxs );
Relink();
if (m_iAutoStart)
{
SetThink(&CNPC_BaseTurret::AutoSearchThink);
SetNextThink( gpGlobals->curtime + 0.1 );
}
else
{
SetThink( SUB_DoNothing );
}
}
}
else
{
SetTurretAnim(TURRET_ANIM_SPIN);
}
}
//=========================================================
// Ping - make the pinging noise every second while searching
//=========================================================
void CNPC_BaseTurret::Ping(void)
{
if (m_flPingTime == 0)
m_flPingTime = gpGlobals->curtime + 1;
else if (m_flPingTime <= gpGlobals->curtime)
{
m_flPingTime = gpGlobals->curtime + 1;
CPASAttenuationFilter filter( this );
enginesound->EmitSound( filter, entindex(), CHAN_ITEM, "turret/tu_ping.wav", 1, ATTN_NORM );
EyeOn( );
}
else if (m_eyeBrightness > 0)
{
EyeOff( );
}
}
//=========================================================
// MoveTurret - handle turret rotation
// returns 1 if the turret moved.
//=========================================================
int CNPC_BaseTurret::MoveTurret(void)
{
int bMoved = 0;
if (m_vecCurAngles.x != m_vecGoalAngles.x)
{
float flDir = m_vecGoalAngles.x > m_vecCurAngles.x ? 1 : -1 ;
m_vecCurAngles.x += 0.1 * m_fTurnRate * flDir;
// if we started below the goal, and now we're past, peg to goal
if (flDir == 1)
{
if (m_vecCurAngles.x > m_vecGoalAngles.x)
m_vecCurAngles.x = m_vecGoalAngles.x;
}
else
{
if (m_vecCurAngles.x < m_vecGoalAngles.x)
m_vecCurAngles.x = m_vecGoalAngles.x;
}
if (m_iOrientation == TURRET_ORIENTATION_FLOOR)
SetBoneController(1, m_vecCurAngles.x);
else
SetBoneController(1, -m_vecCurAngles.x);
bMoved = 1;
}
if (m_vecCurAngles.y != m_vecGoalAngles.y)
{
float flDir = m_vecGoalAngles.y > m_vecCurAngles.y ? 1 : -1 ;
float flDist = fabs(m_vecGoalAngles.y - m_vecCurAngles.y);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -