📄 npc_sscanner.cpp
字号:
engine->PrecacheModel("sprites/physbeam.vmt");
engine->PrecacheModel("sprites/glow01.vmt");
engine->PrecacheModel("sprites/physring1.vmt");
BaseClass::Precache();
}
//------------------------------------------------------------------------------
// Purpose:
//------------------------------------------------------------------------------
void CNPC_SScanner::Gib(void)
{
// Sparks
for (int i = 0; i < 4; i++)
{
Vector sparkPos = GetAbsOrigin();
sparkPos.x += random->RandomFloat(-12,12);
sparkPos.y += random->RandomFloat(-12,12);
sparkPos.z += random->RandomFloat(-12,12);
g_pEffects->Sparks(sparkPos);
}
// Smoke
UTIL_Smoke(GetAbsOrigin(), random->RandomInt(10, 15), 10);
// Light
CBroadcastRecipientFilter filter;
te->DynamicLight( filter, 0.0,
&GetAbsOrigin(), 255, 180, 100, 0, 100, 0.1, 0 );
// Throw scanner gibs
CGib::SpawnSpecificGibs( this, SSCANNER_GIB_COUNT, 800, 1000, "models/gibs/mortarsynth_gibs.mdl");
ExplosionCreate(GetAbsOrigin(), GetAbsAngles(), NULL, random->RandomInt(30, 40), 0, true);
UTIL_Remove(this);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pTask -
//-----------------------------------------------------------------------------
void CNPC_SScanner::RunTask( const Task_t *pTask )
{
switch ( pTask->iTask )
{
// If my enemy has moved significantly, update my path
case TASK_WAIT_FOR_MOVEMENT:
{
CBaseEntity *pEnemy = GetEnemy();
if (pEnemy && IsCurSchedule(SCHED_SSCANNER_CHASE_ENEMY) && GetNavigator()->IsGoalActive())
{
Vector flEnemyLKP = GetEnemyLKP();
if ((GetNavigator()->GetGoalPos() - pEnemy->EyePosition()).Length() > 40 )
{
GetNavigator()->UpdateGoalPos(pEnemy->EyePosition());
}
// If final position is enemy, exit my schedule (will go to attack hover)
if (GetNavigator()->IsGoalActive() &&
GetNavigator()->GetCurWaypointPos() == pEnemy->EyePosition())
{
TaskComplete();
GetNavigator()->ClearGoal(); // Stop moving
break;
}
}
if (m_nState == SSCANNER_OPEN)
{
GetNavigator()->SetMovementActivity(ACT_IDLE_ANGRY);
}
else
{
GetNavigator()->SetMovementActivity(ACT_IDLE);
}
BaseClass::RunTask(pTask);
break;
}
default:
{
BaseClass::RunTask(pTask);
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CNPC_SScanner::Spawn(void)
{
Precache();
SetModel( "models/shield_scanner.mdl");
SetHullType(HULL_SMALL_CENTERED);
SetHullSizeNormal();
SetSolid( SOLID_BBOX );
AddSolidFlags( FSOLID_NOT_STANDABLE );
// Make bounce so I bounce off the surfaces I hit, but turn gravity off
SetMoveType( MOVETYPE_STEP );
SetGravity(0.001);
m_iHealth = sk_sscanner_health.GetFloat();
SetViewOffset( Vector(0, 0, 10) ); // Position of the eyes relative to NPC's origin.
m_flFieldOfView = VIEW_FIELD_FULL;
m_NPCState = NPC_STATE_NONE;
SetNavType( NAV_FLY );
m_bloodColor = DONT_BLEED;
SetCurrentVelocity( Vector(0, 0, 0) );
m_vCurrentBanking = Vector(0, 0, 0);
AddFlag( FL_FLY );
CapabilitiesAdd( bits_CAP_MOVE_FLY );
CapabilitiesAdd( bits_CAP_SQUAD);
m_nState = SSCANNER_CLOSED;
m_bShieldsDisabled = false;
m_vLastPatrolDir = vec3_origin;
m_fNextFlySoundTime = 0;
m_fNextShieldCheckTime = 0;
SetNoiseMod( 2, 2, 2 );
m_fHeadYaw = 0;
NPCInit();
// Let this guy look far
m_flDistTooFar = 99999999.0;
SetDistLook( 4000.0 );
m_flSpeed = SSCANNER_MAX_SPEED;
}
void CNPC_SScanner::OnScheduleChange()
{
m_flSpeed = SSCANNER_MAX_SPEED;
BaseClass::OnScheduleChange();
}
//-----------------------------------------------------------------------------
// Purpose: Gets the appropriate next schedule based on current condition
// bits.
//-----------------------------------------------------------------------------
int CNPC_SScanner::SelectSchedule(void)
{
switch ( m_NPCState )
{
// -------------------------------------------------
// In idle attemp to pair up with a squad
// member that could use shielding
// -------------------------------------------------
case NPC_STATE_IDLE:
{
// --------------------------------------------------
// If I'm blocked find a path to my goal entity
// --------------------------------------------------
if (HasCondition( COND_SSCANNER_FLY_BLOCKED ) && (GetTarget() != NULL))
{
return SCHED_SSCANNER_CHASE_TARGET;
}
return SCHED_SSCANNER_HOVER;
break;
}
case NPC_STATE_DEAD:
case NPC_STATE_SCRIPT:
{
return BaseClass::SelectSchedule();
break;
}
default:
{
// --------------------------------------------------
// If I'm blocked find a path to my goal entity
// --------------------------------------------------
if (HasCondition( COND_SSCANNER_FLY_BLOCKED ))
{
if ((GetTarget() != NULL) && !HasCondition( COND_SSCANNER_PISSED_OFF))
{
return SCHED_SSCANNER_CHASE_TARGET;
}
}
// --------------------------------------------------
// If I have a live enemy
// --------------------------------------------------
if (GetEnemy() != NULL && GetEnemy()->IsAlive())
{
// --------------------------------------------------
// If I'm open
// --------------------------------------------------
if (m_nState == SSCANNER_OPEN)
{
if (GetTarget() == NULL )
{
return SCHED_SSCANNER_CLOSE;
}
else if (HasCondition( COND_SSCANNER_PISSED_OFF))
{
return SCHED_SSCANNER_CLOSE;
}
else
{
return SCHED_SSCANNER_HOVER;
}
}
else if (m_nState == SSCANNER_CLOSED)
{
if (GetTarget() != NULL )
{
float fDist = (GetAbsOrigin() - GetTarget()->GetAbsOrigin()).Length();
if (fDist <= SSCANNER_MAX_SHEILD_DIST)
{
return SCHED_SSCANNER_OPEN;
}
else
{
return SCHED_SSCANNER_HOVER;
}
}
else if (HasCondition( COND_SSCANNER_PISSED_OFF))
{
return SCHED_TAKE_COVER_FROM_ENEMY;
}
else
{
return SCHED_SSCANNER_HOVER;
}
}
else
{
return SCHED_SSCANNER_HOVER;
}
}
// --------------------------------------------------
// I have no enemy so patrol
// --------------------------------------------------
else if (GetEnemy() == NULL)
{
return SCHED_SSCANNER_PATROL;
}
// --------------------------------------------------
// I have no enemy so patrol
// --------------------------------------------------
else
{
return SCHED_SSCANNER_HOVER;
}
break;
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pTask -
//-----------------------------------------------------------------------------
void CNPC_SScanner::StartTask( const Task_t *pTask )
{
switch (pTask->iTask)
{
case TASK_SSCANNER_OPEN:
{
m_nState = SSCANNER_OPEN;
TaskComplete();
break;
}
case TASK_SSCANNER_CLOSE:
{
m_nState = SSCANNER_CLOSED;
TaskComplete();
break;
}
// Override so can find hint nodes that are much further away
case TASK_FIND_HINTNODE:
{
if (!m_pHintNode)
{
m_pHintNode = CAI_Hint::FindHint(this, HINT_NONE, pTask->flTaskData, 5000 );
}
if ( m_pHintNode )
{
TaskComplete();
}
else
{
// No hint node run from enemy
SetSchedule( SCHED_RUN_FROM_ENEMY );
}
break;
}
default:
{
BaseClass::StartTask(pTask);
}
}
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
bool CNPC_SScanner::IsValidShieldTarget(CBaseEntity *pEntity)
{
// Reject if already shielded by another squad member
AISquadIter_t iter;
for (CAI_BaseNPC *pSquadMember = m_pSquad->GetFirstMember( &iter ); pSquadMember; pSquadMember = m_pSquad->GetNextMember( &iter ) )
{
CNPC_SScanner *pScanner = dynamic_cast<CNPC_SScanner*>(pSquadMember);
if (pScanner &&
pScanner != this &&
pScanner->Classify() == CLASS_SCANNER )
{
if (pScanner->GetTarget() == pEntity)
{
// Reject unless I'm significantly closer
float fNPCDist = (pScanner->GetLocalOrigin() - pEntity->GetLocalOrigin()).Length();
float fMyDist = (GetLocalOrigin() - pEntity->GetLocalOrigin()).Length();
if ((fNPCDist - fMyDist) > 150 )
{
// Steal from other scanner
pScanner->StopShield();
pScanner->SetTarget( NULL );
return true;
}
return false;
}
}
}
return true;
}
//------------------------------------------------------------------------------
//
// Schedules
//
//------------------------------------------------------------------------------
//=========================================================
// > SCHED_SSCANNER_HOVER
//=========================================================
AI_DEFINE_SCHEDULE
(
SCHED_SSCANNER_HOVER,
" Tasks"
" TASK_RESET_ACTIVITY 0"
" TASK_PLAY_SEQUENCE ACTIVITY:ACT_IDLE"
" "
" Interrupts"
" COND_NEW_ENEMY"
" COND_SSCANNER_FLY_BLOCKED"
" COND_LIGHT_DAMAGE"
);
//=========================================================
// > SCHED_SSCANNER_OPEN
//=========================================================
AI_DEFINE_SCHEDULE
(
SCHED_SSCANNER_OPEN,
" Tasks"
" TASK_PLAY_SEQUENCE ACTIVITY:ACT_SSCANNER_OPEN"
" TASK_SSCANNER_OPEN 0"
" "
" Interrupts"
);
//=========================================================
// > SCHED_SSCANNER_CLOSE
//=========================================================
AI_DEFINE_SCHEDULE
(
SCHED_SSCANNER_CLOSE,
" Tasks"
" TASK_SSCANNER_CLOSE 0"
" TASK_PLAY_SEQUENCE ACTIVITY:ACT_SSCANNER_CLOSE"
" "
" Interrupts"
);
//=========================================================
// > SCHED_SSCANNER_PATROL
//=========================================================
AI_DEFINE_SCHEDULE
(
SCHED_SSCANNER_PATROL,
" Tasks"
" TASK_SET_TOLERANCE_DISTANCE 48"
" TASK_SET_ROUTE_SEARCH_TIME 5" // Spend 5 seconds trying to build a path if stuck
" TASK_GET_PATH_TO_RANDOM_NODE 2000"
" TASK_RUN_PATH 0"
" TASK_WAIT_FOR_MOVEMENT 0 "
" "
" Interrupts"
" COND_GIVE_WAY"
" COND_NEW_ENEMY"
" COND_SEE_ENEMY"
" COND_SEE_FEAR"
" COND_HEAR_COMBAT"
" COND_HEAR_DANGER"
" COND_HEAR_PLAYER"
" COND_LIGHT_DAMAGE"
" COND_HEAVY_DAMAGE"
" COND_PROVOKED"
);
//=========================================================
// > SCHED_SSCANNER_CHASE_ENEMY
//=========================================================
AI_DEFINE_SCHEDULE
(
SCHED_SSCANNER_CHASE_ENEMY,
" Tasks"
" TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_SSCANNER_PATROL"
" TASK_SET_TOLERANCE_DISTANCE 120"
" TASK_GET_PATH_TO_ENEMY 0"
" TASK_RUN_PATH 0"
" TASK_WAIT_FOR_MOVEMENT 0"
" "
" Interrupts"
" COND_ENEMY_DEAD"
" COND_SSCANNER_FLY_CLEAR"
);
//=========================================================
// > SCHED_SSCANNER_CHASE_TARGET
//=========================================================
AI_DEFINE_SCHEDULE
(
SCHED_SSCANNER_CHASE_TARGET,
" Tasks"
" TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_SSCANNER_HOVER"
" TASK_SET_TOLERANCE_DISTANCE 120"
" TASK_GET_PATH_TO_TARGET 0"
" TASK_RUN_PATH 0"
" TASK_WAIT_FOR_MOVEMENT 0"
" "
" "
" Interrupts"
" COND_SSCANNER_FLY_CLEAR"
" COND_SSCANNER_PISSED_OFF"
);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -