📄 npc_sscanner.cpp
字号:
{
float myDecay = 9.5;
Decelerate( flInterval, myDecay );
// -------------------------------------
// If I have an enemy turn to face him
// -------------------------------------
if (GetEnemy())
{
TurnHeadToTarget(flInterval, GetEnemy()->GetLocalOrigin() );
}
}
MoveExecute_Alive(flInterval);
UpdateShields();
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Override base class activiites
// Input :
// Output :
//-----------------------------------------------------------------------------
Activity CNPC_SScanner::NPC_TranslateActivity( Activity eNewActivity )
{
if ( eNewActivity == ACT_IDLE)
{
if (m_nState == SSCANNER_OPEN)
{
return ACT_IDLE_ANGRY;
}
else
{
return ACT_IDLE;
}
}
return eNewActivity;
}
//------------------------------------------------------------------------------
// Purpose : Choose which entity to shield
// Input :
// Output :
//------------------------------------------------------------------------------
CBaseEntity* CNPC_SScanner::PickShieldEntity(void)
{
if (m_bShieldsDisabled)
{
return NULL;
}
// Don't pick every frame as it gets expensive
if (gpGlobals->curtime > m_fNextShieldCheckTime)
{
m_fNextShieldCheckTime = gpGlobals->curtime + 1.0;
CBaseEntity* pBestEntity = NULL;
float fBestDist = MAX_COORD_RANGE;
bool bBestLOS = false;
float fTestDist;
bool bTestLOS = false;;
AISquadIter_t iter;
for (CAI_BaseNPC *pSquadMember = m_pSquad->GetFirstMember( &iter ); pSquadMember; pSquadMember = m_pSquad->GetNextMember( &iter ) )
{
CAI_BaseNPC* pTestNPC = pSquadMember;
if (pTestNPC != NULL &&
pTestNPC != this &&
pTestNPC->Classify() != CLASS_SCANNER )
{
bTestLOS = pTestNPC->HasCondition( COND_HAVE_ENEMY_LOS);
fTestDist = (GetLocalOrigin() - pTestNPC->GetLocalOrigin()).Length();
// -----------------------------------------
// Test has LOS and best doesn't, pick test
// -----------------------------------------
if (bTestLOS && !bBestLOS)
{
// Skip if I can't see this entity
if (IsValidShieldTarget(pTestNPC) )
{
fBestDist = fTestDist;
pBestEntity = pTestNPC;
bBestLOS = bTestLOS;
}
}
// -----------------------------------------
// Best has LOS and test doesn't, skip
// -----------------------------------------
else if (!bTestLOS && bBestLOS)
{
continue;
}
// -----------------------------------------------
// Otherwise pick by distance
// -----------------------------------------------
if (fTestDist < fBestDist )
{
// Skip if I can't see this entity
if (IsValidShieldTarget(pTestNPC) )
{
fBestDist = fTestDist;
pBestEntity = pTestNPC;
bBestLOS = bTestLOS;
}
}
}
}
return pBestEntity;
}
else
{
return GetTarget();
}
}
//------------------------------------------------------------------------------
// Purpose : Override to set pissed level of sscanner
// Input :
// Output :
//------------------------------------------------------------------------------
void CNPC_SScanner::NPCThink(void)
{
// --------------------------------------------------
// COND_SSCANNER_PISSED_OFF
// --------------------------------------------------
float fHurtAge = gpGlobals->curtime - m_lastHurtTime;
if (fHurtAge > 5.0)
{
ClearCondition(COND_SSCANNER_PISSED_OFF);
m_bShieldsDisabled = false;
}
else
{
SetCondition(COND_SSCANNER_PISSED_OFF);
m_bShieldsDisabled = true;
}
BaseClass::NPCThink();
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CNPC_SScanner::PowerShield(void)
{
// -----------------------------
// Start the shield chase beam
// -----------------------------
if (!m_pShieldBeamL)
{
m_pShieldBeamL = CShieldBeam::ShieldBeamCreate( this, 2 );
m_pShieldBeamR = CShieldBeam::ShieldBeamCreate( this, 3 );
}
if (!m_pShieldBeamL->IsShieldBeamOn())
{
m_pShieldBeamL->ShieldBeamStart(this, GetTarget(), GetCurrentVelocity(), 500 );
m_pShieldBeamR->ShieldBeamStart(this, GetTarget(), GetCurrentVelocity(), 500 );
m_pShieldBeamL->m_vTailOffset = Vector(0,0,88);
m_pShieldBeamR->m_vTailOffset = Vector(0,0,88);
}
// -------------------------------------------------
// Start the shield when chaser reaches the shield
// -------------------------------------------------
if (m_pShieldBeamL->IsShieldBeamOn() && m_pShieldBeamL->ReachedTail())
{
if (!m_pShield)
{
m_pShield = (CScannerShield *)CreateEntityByName("scanner_shield" );
m_pShield->Spawn();
}
m_pShield->SetTarget(GetTarget());
m_pShieldBeamL->SetNoise(GetCurrentVelocity().Length());
m_pShieldBeamR->SetNoise(GetCurrentVelocity().Length());
}
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CNPC_SScanner::StopShield(void)
{
// -----------------------------
// Stop shield chase beam
// -----------------------------
if (m_pShieldBeamL)
{
m_pShieldBeamL->ShieldBeamStop();
}
if (m_pShieldBeamR)
{
m_pShieldBeamR->ShieldBeamStop();
}
// -----------------------------
// Stop the shield
// -----------------------------
if (m_pShield)
{
m_pShield->SetTarget(NULL);
}
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CNPC_SScanner::UpdateShields(void)
{
// -------------------------------------------------------
// Turn of shield and don't reset m_hTarget if in script
// -------------------------------------------------------
if (m_IdealNPCState != NPC_STATE_SCRIPT ||
m_NPCState != NPC_STATE_SCRIPT)
{
StopShield();
return;
}
// -------------------------------------------------------------------------
// If I'm not in a squad there's no one to shield
// -------------------------------------------------------------------------
if (!m_pSquad)
{
return;
}
// -------------------------------------------------------------------------
// If I'm dead, stop the shields
// -------------------------------------------------------------------------
if ( m_IdealNPCState == NPC_STATE_DEAD )
{
SetTarget( NULL );
StopShield();
}
// -------------------------------------------------------------------------
// Pick the best entity to shield
// -------------------------------------------------------------------------
CBaseEntity* pShielded = PickShieldEntity();
// -------------------------------------------------------------------------
// If there was no best entity stop the shields
// -------------------------------------------------------------------------
if (pShielded == NULL)
{
SetTarget( NULL );
StopShield();
return;
}
// -------------------------------------------------------------------------
// If I'm too far to shield set best entity as target but stop the shields
// -------------------------------------------------------------------------
float fDist = (GetLocalOrigin() - pShielded->GetLocalOrigin()).Length();
if (fDist > SSCANNER_MAX_SHEILD_DIST)
{
SetTarget( pShielded );
StopShield();
return;
}
// -------------------------------------------------------------------------
// If this is a new target, stop the shield
// -------------------------------------------------------------------------
if (m_pShieldBeamL &&
GetTarget() != pShielded &&
m_pShieldBeamL->IsShieldBeamOn() )
{
StopShield();
}
// -------------------------------------------------------------------------
// Reset my target entity and power the shield
// -------------------------------------------------------------------------
SetTarget( pShielded );
// -------------------------------------------------------------------------
// If I'm closed, stop the shields
// -------------------------------------------------------------------------
if ( m_nState == SSCANNER_CLOSED )
{
StopShield();
}
else
{
PowerShield();
}
/* DEBUG TOOL
if (GetTarget())
{
int blue = 0;
int red = 0;
if (GetTarget())
{
red = 255;
}
else
{
blue = 255;
}
NDebugOverlay::Cross3D(GetTarget()->GetLocalOrigin()+Vector(0,0,60),Vector(-15,-15,-15),Vector(5,5,5),red,0,blue,true,0.1);
NDebugOverlay::Cross3D(GetLocalOrigin()+Vector(0,0,60),Vector(-15,-15,-15),Vector(5,5,5),red,0,blue,true,0.1);
NDebugOverlay::Line(GetLocalOrigin(), GetTarget()->GetLocalOrigin(), red,0,blue, true, 0.1);
}
else
{
NDebugOverlay::Cross3D(GetLocalOrigin()+Vector(0,0,60),Vector(-15,-15,-15),Vector(5,5,5),0,255,0,true,0.1);
}
*/
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
void CNPC_SScanner::MoveToTarget(float flInterval, const Vector &MoveTarget)
{
const float myAccel = 300.0;
const float myDecay = 9.0;
TurnHeadToTarget( flInterval, MoveTarget );
MoveToLocation( flInterval, MoveTarget, myAccel, (2 * myAccel), myDecay );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
void CNPC_SScanner::MoveToEntity(float flInterval, CBaseEntity* pMoveTarget, float fMinRange, float fMaxRange)
{
// -----------------------------------------
// Make sure we have a move target
// -----------------------------------------
if (!pMoveTarget)
{
return;
}
// -----------------------------------------
// Keep within range of enemy
// -----------------------------------------
Vector vFlyDirection = vec3_origin;
Vector vEnemyDir = pMoveTarget->EyePosition() - GetAbsOrigin();
float fEnemyDist = VectorNormalize(vEnemyDir);
if (fEnemyDist < fMinRange)
{
vFlyDirection = -vEnemyDir;
}
else if (fEnemyDist > fMaxRange)
{
vFlyDirection = vEnemyDir;
}
// If I'm shielding someone see if I can go to cover
else if (SetShieldCoverPosition())
{
vFlyDirection = m_vCoverPosition - GetAbsOrigin();
VectorNormalize(vFlyDirection);
}
TurnHeadToTarget( flInterval, pMoveTarget->GetAbsOrigin() );
// -------------------------------------
// Set net velocity
// -------------------------------------
float myAccel = 500.0;
float myDecay = 0.35; // decay to 35% in 1 second
MoveInDirection(flInterval, vFlyDirection, myAccel, (2 * myAccel), myDecay);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
void CNPC_SScanner::PlayFlySound(void)
{
if (gpGlobals->curtime > m_fNextFlySoundTime)
{
EmitSound( "NPC_SScanner.FlySound" );
m_fNextFlySoundTime = gpGlobals->curtime + 1.0;
}
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
float CNPC_SScanner::MinGroundDist(void)
{
return SSCANNER_MIN_GROUND_DIST;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
void CNPC_SScanner::MoveExecute_Alive(float flInterval)
{
// ----------------------------------------------------------------------------------------
// Add time-coherent noise to the current velocity so that it never looks bolted in place.
// ----------------------------------------------------------------------------------------
AddNoiseToVelocity( 2.0 );
// -------------------------------------------
// Avoid obstacles
// -------------------------------------------
SetCurrentVelocity( GetCurrentVelocity() + VelocityToAvoidObstacles(flInterval) );
// ---------------------
// Limit overall speed
// ---------------------
LimitSpeed( 200 );
// If I'm right over the ground limit my banking so my blades
// don't sink into the floor
float floorZ = GetFloorZ(GetLocalOrigin());
if (abs(GetLocalOrigin().z - floorZ) < 36)
{
QAngle angles = GetLocalAngles();
if (angles.x < -20) angles.x = -20;
if (angles.x > 20) angles.x = 20;
if (angles.z < -20) angles.z = -20;
if (angles.z > 20) angles.z = 20;
SetLocalAngles( angles );
}
PlayFlySound();
WalkMove( GetCurrentVelocity() * flInterval, MASK_NPCSOLID );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CNPC_SScanner::Precache(void)
{
//
// Model.
//
engine->PrecacheModel("models/shield_scanner.mdl");
engine->PrecacheModel("models/scanner_shield.mdl");
engine->PrecacheModel("models/gibs/mortarsynth_gibs.mdl");
enginesound->PrecacheSound( "npc/waste_scanner/grenade_fire.wav");
enginesound->PrecacheSound( "npc/waste_scanner/hover.wav");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -