📄 npc_roller.cpp
字号:
}
//---------------------------------------------------------
//---------------------------------------------------------
void CNPC_Roller::MarcoSound( void )
{
if( gpGlobals->curtime < m_flTimeMarcoSound )
{
return;
}
EmitSound( "NPC_Roller.Marco" );
// Look for all the other rollers in the effective radius and tell them to polo me.
CBaseEntity *pEntity = gEntList.FindEntityByClassname( NULL, "npc_roller" );
while( pEntity )
{
if( UTIL_DistApprox( GetAbsOrigin(), pEntity->GetAbsOrigin() ) <= ROLLER_MARCOPOLO_DIST )
{
CNPC_Roller *pRoller;
pRoller = dynamic_cast<CNPC_Roller *>(pEntity);
if( pRoller && pRoller != this )
{
// Don't interfere with a roller that's
// supposed to be replying to someone else.
if( pRoller->m_flTimePoloSound == TIME_NEVER )
{
// Tell this Roller to polo in a couple seconds.
pRoller->m_flTimePoloSound = gpGlobals->curtime + 1 + random->RandomFloat( 0, 2 );
// Tell him also not to marco for quite some time.
pRoller->m_flTimeMarcoSound = gpGlobals->curtime + ROLLER_MARCO_FREQUENCY * 2;
}
}
}
pEntity = gEntList.FindEntityByClassname( pEntity, "npc_roller" );
}
m_flTimeMarcoSound = gpGlobals->curtime + ROLLER_MARCO_FREQUENCY;
}
//---------------------------------------------------------
//---------------------------------------------------------
void CNPC_Roller::PoloSound( void )
{
if( gpGlobals->curtime < m_flTimePoloSound )
{
return;
}
EmitSound( "NPC_Roller.Polo" );
m_flTimePoloSound = TIME_NEVER;
}
//---------------------------------------------------------
//---------------------------------------------------------
void CNPC_Roller::PrescheduleThink( void )
{
BaseClass::PrescheduleThink();
#if 0
MarcoSound();
PoloSound();
#endif
}
//---------------------------------------------------------
//---------------------------------------------------------
int CNPC_Roller::SelectSchedule ( void )
{
if( m_fHACKJustSpawned )
{
m_fHACKJustSpawned = false;
return SCHED_ROLLER_WAIT_FOR_PHYSICS;
}
switch( m_NPCState )
{
case NPC_STATE_COMBAT:
if( HasCondition( COND_ROLLER_PHYSICS ) )
{
return SCHED_ROLLER_WAIT_FOR_PHYSICS;
}
break;
default:
if( HasCondition( COND_ROLLER_PHYSICS ) )
{
return SCHED_ROLLER_WAIT_FOR_PHYSICS;
}
return SCHED_IDLE_STAND;
break;
}
return SCHED_IDLE_STAND;
}
//---------------------------------------------------------
//---------------------------------------------------------
int CNPC_Roller::TranslateSchedule( int scheduleType )
{
switch( scheduleType )
{
case SCHED_CHASE_ENEMY_FAILED:
case SCHED_FAIL:
if( m_iFail > ROLLER_NUM_FAILS )
{
// If the roller has failed a lot, try to unstick him.
// Usually by rolling backwards.
return SCHED_ROLLER_UNSTICK;
}
else
{
return SCHED_FAIL;
}
break;
case SCHED_IDLE_STAND:
// Don't stand around. Patrol.
return SCHED_ROLLER_PATROL;
break;
}
return BaseClass::TranslateSchedule( scheduleType );
}
//---------------------------------------------------------
//---------------------------------------------------------
void CNPC_Roller::StartTask( const Task_t *pTask )
{
switch( pTask->iTask )
{
case TASK_ROLLER_ON:
PowerOn();
TaskComplete();
break;
case TASK_ROLLER_OFF:
PowerOff();
TaskComplete();
break;
case TASK_ROLLER_WAIT_FOR_PHYSICS:
// Stop rolling.
m_flWaitFinished = gpGlobals->curtime;
m_RollerController.m_vecAngular = vec3_origin;
PowerOff();
break;
case TASK_ROLLER_FIND_PATROL_NODE:
m_pHintNode = CAI_Hint::FindHint( this, HINT_ROLLER_PATROL_POINT, 0, 1024 );
if(!m_pHintNode)
{
TaskFail("Couldn't find roller patrol node");
}
else
{
TaskComplete();
}
break;
case TASK_ROLLER_UNSTICK:
Unstick();
if( m_vecUnstickDirection == vec3_origin )
{
TaskComplete();
}
else
{
VPhysicsGetObject()->Wake();
PowerOn();
// Cut back on the fail count, but not all the way.
// Only a successful opportunity move sets this to 0.
m_iFail /= 2;
m_flWaitFinished = gpGlobals->curtime + 2;
}
break;
case TASK_WALK_PATH:
case TASK_RUN_PATH:
// Make sure the controller isn't turned off.
m_iFail = 0; // Successfully starting to move.
VPhysicsGetObject()->Wake();
PowerOn();
break;
case TASK_ROLLER_ISSUE_CODE:
m_iCodeProgress = 0;
m_flWaitFinished = gpGlobals->curtime;
break;
default:
BaseClass::StartTask( pTask );
break;
}
}
//---------------------------------------------------------
//---------------------------------------------------------
void CNPC_Roller::RunTask( const Task_t *pTask )
{
switch( pTask->iTask )
{
case TASK_ROLLER_UNSTICK:
{
float yaw = UTIL_VecToYaw( m_vecUnstickDirection );
Vector vecRight;
AngleVectors( QAngle( 0, yaw, 0 ), NULL, &vecRight, NULL );
m_RollerController.m_vecAngular = WorldToLocalRotation( SetupMatrixAngles(GetLocalAngles()), vecRight, m_flForwardSpeed );
}
if( gpGlobals->curtime > m_flWaitFinished )
{
TaskComplete();
}
break;
case TASK_ROLLER_WAIT_FOR_PHYSICS:
{
Vector vecVelocity;
VPhysicsGetObject()->GetVelocity( &vecVelocity, NULL );
if( VPhysicsGetObject()->IsAsleep() )
{
TaskComplete();
}
}
break;
case TASK_RUN_PATH:
case TASK_WALK_PATH:
// Start turning early
if( (GetLocalOrigin() - GetNavigator()->GetCurWaypointPos() ).Length() <= 64 )
{
if( GetNavigator()->CurWaypointIsGoal() )
{
// Hit the brakes a bit.
float yaw = UTIL_VecToYaw( GetNavigator()->GetCurWaypointPos() - GetLocalOrigin() );
Vector vecRight;
AngleVectors( QAngle( 0, yaw, 0 ), NULL, &vecRight, NULL );
m_RollerController.m_vecAngular += WorldToLocalRotation( SetupMatrixAngles(GetLocalAngles()), vecRight, -m_flForwardSpeed * 5 );
TaskComplete();
return;
}
GetNavigator()->AdvancePath();
}
{
float yaw = UTIL_VecToYaw( GetNavigator()->GetCurWaypointPos() - GetLocalOrigin() );
Vector vecRight;
Vector vecToPath; // points at the path
AngleVectors( QAngle( 0, yaw, 0 ), &vecToPath, &vecRight, NULL );
// figure out if the roller is turning. If so, cut the throttle a little.
float flDot;
Vector vecVelocity;
VPhysicsGetObject()->GetVelocity( &vecVelocity, NULL );
VectorNormalize( vecVelocity );
vecVelocity.z = 0;
flDot = DotProduct( vecVelocity, vecToPath );
m_RollerController.m_vecAngular = vec3_origin;
if( flDot > 0.25 && flDot < 0.7 )
{
// Feed a little torque backwards into the axis perpendicular to the velocity.
// This will help get rid of momentum that would otherwise make us overshoot our goal.
Vector vecCompensate;
vecCompensate.x = vecVelocity.y;
vecCompensate.y = -vecVelocity.x;
vecCompensate.z = 0;
m_RollerController.m_vecAngular = WorldToLocalRotation( SetupMatrixAngles(GetLocalAngles()), vecCompensate, m_flForwardSpeed * -0.75 );
}
m_RollerController.m_vecAngular += WorldToLocalRotation( SetupMatrixAngles(GetLocalAngles()), vecRight, m_flForwardSpeed );
}
break;
case TASK_ROLLER_ISSUE_CODE:
if( gpGlobals->curtime >= m_flWaitFinished )
{
if( m_iCodeProgress == ROLLER_CODE_DIGITS )
{
TaskComplete();
}
else
{
m_flWaitFinished = gpGlobals->curtime + ROLLER_TONE_TIME;
CPASAttenuationFilter filter( this );
EmitSound( filter, entindex(), CHAN_BODY, pCodeSounds[ m_iAccessCode[ m_iCodeProgress ] ], 1.0, ATTN_NORM );
m_iCodeProgress++;
}
}
break;
default:
BaseClass::RunTask( pTask );
break;
}
}
//---------------------------------------------------------
//---------------------------------------------------------
bool CNPC_Roller::IsBlocked( const Vector &vecCheck )
{
trace_t tr;
return false;
#if 0
NDebugOverlay::Line( GetLocalOrigin(), GetLocalOrigin() + vecCheck, 255,255,0, true, 0.1 );
Vector vecRight;
Vector vecForward;
AngleVectors( GetLocalAngles(), &vecForward, &vecRight, NULL );
NDebugOverlay::Line( GetLocalOrigin() + vecRight * 32, GetLocalOrigin() + vecRight * -32, 0,255,0, true, 0.1 );
#endif ROLLER_DEBUG
AI_TraceLine( GetAbsOrigin(), GetAbsOrigin() + vecCheck, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
return ( tr.fraction != 1.0 );
}
//---------------------------------------------------------
//---------------------------------------------------------
bool CNPC_Roller::IsBlockedForward( void )
{
Vector vecLinear;
VPhysicsGetObject()->GetVelocity( &vecLinear, NULL );
VectorNormalize( vecLinear );
vecLinear *= ROLLER_CHECK_DIST;
return IsBlocked( vecLinear );
}
//---------------------------------------------------------
//---------------------------------------------------------
bool CNPC_Roller::IsBlockedBackward( void )
{
Vector vecLinear;
VPhysicsGetObject()->GetVelocity( &vecLinear, NULL );
VectorNormalize( vecLinear );
vecLinear *= ROLLER_CHECK_DIST;
return IsBlocked( vecLinear );
}
//---------------------------------------------------------
//---------------------------------------------------------
int CNPC_Roller::VPhysicsTakeDamage( const CTakeDamageInfo &info )
{
if( RollerPhysicsDamageMask() & info.GetDamageType() )
{
SetCondition( COND_ROLLER_PHYSICS );
}
return BaseClass::VPhysicsTakeDamage( info );
}
//---------------------------------------------------------
//---------------------------------------------------------
bool CNPC_Roller::OverrideMove( float flInterval )
{
// Do nothing
return true;
}
//---------------------------------------------------------
//---------------------------------------------------------
void CNPC_Roller::TaskFail( AI_TaskFailureCode_t code )
{
const Task_t *pTask = GetTask();
if( pTask )
{
Msg( "Failed to: %s\n", TaskName( pTask->iTask ) );
switch( pTask->iTask )
{
case TASK_WALK_PATH:
case TASK_RUN_PATH:
case TASK_GET_PATH_TO_ENEMY:
case TASK_GET_PATH_TO_ENEMY_LKP:
case TASK_GET_PATH_TO_HINTNODE:
m_iFail++;
break;
}
}
BaseClass::TaskFail( code );
}
//-----------------------------------------------------------------------------
//
// Schedules
//
//-----------------------------------------------------------------------------
//=========================================================
// Patrol - roll around from hint node to hint node.
//=========================================================
AI_DEFINE_SCHEDULE
(
SCHED_ROLLER_PATROL,
" Tasks"
" TASK_ROLLER_FIND_PATROL_NODE 0"
" TASK_GET_PATH_TO_HINTNODE 0"
" TASK_WALK_PATH 0"
" "
" Interrupts"
" COND_NEW_ENEMY"
" COND_ROLLER_PHYSICS"
" COND_CAN_RANGE_ATTACK1"
);
//=========================================================
// Unstick - try to get unstuck.
//=========================================================
AI_DEFINE_SCHEDULE
(
SCHED_ROLLER_UNSTICK,
" Tasks"
" TASK_ROLLER_UNSTICK 0"
" "
" Interrupts"
" COND_ROLLER_PHYSICS"
);
//=========================================================
// WAIT_FOR_PHYSICS
//
// Don't do ANYTHING until done simulating.
//=========================================================
AI_DEFINE_SCHEDULE
(
SCHED_ROLLER_WAIT_FOR_PHYSICS,
" Tasks"
" TASK_ROLLER_WAIT_FOR_PHYSICS 0"
" "
" Interrupts"
);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -