📄 hl1_npc_agrunt.cpp
字号:
// SetBlending( 0, angDir.x );
GetAttachment( "0", vecArmPos, angArmDir );
vecArmPos = vecArmPos + vecDirToEnemy * 32;
CPVSFilter filter( GetAbsOrigin() );
te->Sprite( filter, 0.0,
&vecArmPos, iAgruntMuzzleFlash, random->RandomFloat( 0.4, 0.8 ), 128 );
CBaseEntity *pHornet = CBaseEntity::Create( "hornet", vecArmPos, QAngle( 0, 0, 0 ), this );
Vector vForward;
AngleVectors( angDir, &vForward );
pHornet->SetAbsVelocity( vForward * 300 );
pHornet->SetOwnerEntity( this );
EmitSound( "Weapon_Hornetgun.Single" );
CHL1BaseNPC *pHornetMonster = (CHL1BaseNPC *)pHornet->MyNPCPointer();
if ( pHornetMonster )
{
pHornetMonster->SetEnemy( GetEnemy() );
}
}
break;
case AGRUNT_AE_LEFT_FOOT:
// left foot
{
CPASAttenuationFilter filter2( this );
switch ( random->RandomInt(0,1) )
{
case 0: enginesound->EmitSound( filter2, entindex(), CHAN_BODY, "player/pl_ladder2.wav", 1, ATTN_NORM, 0, 70 ); break;
case 1: enginesound->EmitSound( filter2, entindex(), CHAN_BODY, "player/pl_ladder4.wav", 1, ATTN_NORM, 0, 70 ); break;
}
}
break;
case AGRUNT_AE_RIGHT_FOOT:
// right foot
{
CPASAttenuationFilter filter3( this );
switch ( random->RandomInt(0,1))
{
case 0: enginesound->EmitSound( filter3, entindex(), CHAN_BODY, "player/pl_ladder1.wav", 1, ATTN_NORM, 0, 70 ); break;
case 1: enginesound->EmitSound( filter3, entindex(), CHAN_BODY, "player/pl_ladder3.wav", 1, ATTN_NORM, 0 ,70); break;
}
}
break;
case AGRUNT_AE_LEFT_PUNCH:
{
Vector vecMins = GetHullMins();
Vector vecMaxs = GetHullMaxs();
vecMins.z = vecMins.x;
vecMaxs.z = vecMaxs.x;
CBaseEntity *pHurt = CheckTraceHullAttack( AGRUNT_MELEE_DIST, vecMins, vecMaxs, sk_agrunt_dmg_punch.GetFloat(), DMG_CLUB );
CPASAttenuationFilter filter4( this );
if ( pHurt )
{
if ( pHurt->GetFlags() & ( FL_NPC | FL_CLIENT ) )
pHurt->ViewPunch( QAngle( -25, 8, 0) );
Vector vRight;
AngleVectors( GetAbsAngles(), NULL, &vRight, NULL );
// OK to use gpGlobals without calling MakeVectors, cause CheckTraceHullAttack called it above.
if ( pHurt->IsPlayer() )
{
// this is a player. Knock him around.
pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + vRight * 250 );
}
enginesound->EmitSound(filter4, entindex(), CHAN_WEAPON, pAttackHitSounds[ random->RandomInt(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + random->RandomInt(-5,5) );
Vector vecArmPos;
QAngle angArmAng;
GetAttachment( 0, vecArmPos, angArmAng );
SpawnBlood(vecArmPos, pHurt->BloodColor(), 25);// a little surface blood.
}
else
{
// Play a random attack miss sound
enginesound->EmitSound(filter4, entindex(), CHAN_WEAPON, pAttackMissSounds[ random->RandomInt(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + random->RandomInt(-5,5) );
}
}
break;
case AGRUNT_AE_RIGHT_PUNCH:
{
Vector vecMins = GetHullMins();
Vector vecMaxs = GetHullMaxs();
vecMins.z = vecMins.x;
vecMaxs.z = vecMaxs.x;
CBaseEntity *pHurt = CheckTraceHullAttack( AGRUNT_MELEE_DIST, vecMins, vecMaxs, sk_agrunt_dmg_punch.GetFloat(), DMG_CLUB );
CPASAttenuationFilter filter5( this );
if ( pHurt )
{
if ( pHurt->GetFlags() & ( FL_NPC | FL_CLIENT ) )
pHurt->ViewPunch( QAngle( 25, 8, 0) );
// OK to use gpGlobals without calling MakeVectors, cause CheckTraceHullAttack called it above.
if ( pHurt->IsPlayer() )
{
// this is a player. Knock him around.
Vector vRight;
AngleVectors( GetAbsAngles(), NULL, &vRight, NULL );
pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + vRight * -250 );
}
enginesound->EmitSound( filter5, entindex(), CHAN_WEAPON, pAttackHitSounds[ random->RandomInt(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + random->RandomInt(-5,5) );
Vector vecArmPos;
QAngle angArmAng;
GetAttachment( 0, vecArmPos, angArmAng );
SpawnBlood(vecArmPos, pHurt->BloodColor(), 25);// a little surface blood.
}
else
{
// Play a random attack miss sound
enginesound->EmitSound( filter5, entindex(), CHAN_WEAPON, pAttackMissSounds[ random->RandomInt(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + random->RandomInt(-5,5) );
}
}
break;
default:
BaseClass::HandleAnimEvent( pEvent );
break;
}
}
//=========================================================
// DieSound
//=========================================================
void CNPC_AlienGrunt::DeathSound ( void )
{
StopTalking();
CPASAttenuationFilter filter( this );
enginesound->EmitSound( filter, entindex(), CHAN_VOICE, pDieSounds[ random->RandomInt(0,ARRAYSIZE(pDieSounds)-1)], 1.0, ATTN_NORM );
}
//=========================================================
// AlertSound
//=========================================================
void CNPC_AlienGrunt::AlertSound ( void )
{
StopTalking();
CPASAttenuationFilter filter( this );
enginesound->EmitSound( filter, entindex(), CHAN_VOICE, pAlertSounds[random->RandomInt(0,ARRAYSIZE(pAlertSounds)-1)], 1.0, ATTN_NORM );
}
//=========================================================
// AttackSound
//=========================================================
void CNPC_AlienGrunt::AttackSound ( void )
{
StopTalking();
CPASAttenuationFilter filter( this );
enginesound->EmitSound( filter, entindex(), CHAN_VOICE, pAttackSounds[random->RandomInt(0,ARRAYSIZE(pAttackSounds)-1)], 1.0, ATTN_NORM );
}
//=========================================================
// PainSound
//=========================================================
void CNPC_AlienGrunt::PainSound ( void )
{
if ( m_flNextPainTime > gpGlobals->curtime )
{
return;
}
m_flNextPainTime = gpGlobals->curtime + 0.6;
StopTalking();
CPASAttenuationFilter filter( this );
enginesound->EmitSound( filter, entindex(), CHAN_VOICE, pPainSounds[random->RandomInt(0,ARRAYSIZE(pPainSounds)-1)], 1.0, ATTN_NORM );
}
//=========================================================
// ShouldSpeak - Should this agrunt be talking?
//=========================================================
bool CNPC_AlienGrunt::ShouldSpeak( void )
{
if ( m_flNextSpeakTime > gpGlobals->curtime )
{
// my time to talk is still in the future.
return FALSE;
}
if ( m_spawnflags & SF_NPC_GAG )
{
if ( m_NPCState != NPC_STATE_COMBAT )
{
// if gagged, don't talk outside of combat.
// if not going to talk because of this, put the talk time
// into the future a bit, so we don't talk immediately after
// going into combat
m_flNextSpeakTime = gpGlobals->curtime + 3;
return FALSE;
}
}
return TRUE;
}
//=========================================================
// PrescheduleThink
//=========================================================
void CNPC_AlienGrunt::PrescheduleThink ( void )
{
BaseClass::PrescheduleThink();
if ( ShouldSpeak() )
{
if ( m_flNextWordTime < gpGlobals->curtime )
{
int num = -1;
do
{
num = random->RandomInt( 0,ARRAYSIZE(pIdleSounds)-1 );
} while( num == m_iLastWord );
m_iLastWord = num;
// play a new sound
CPASAttenuationFilter filter( this );
enginesound->EmitSound( filter, entindex(), CHAN_VOICE, pIdleSounds[ num ], 1.0, ATTN_NORM );
// is this word our last?
if ( random->RandomInt( 1, 10 ) <= 1 )
{
// stop talking.
StopTalking();
}
else
{
m_flNextWordTime = gpGlobals->curtime + random->RandomFloat( 0.5, 1 );
}
}
}
}
//=========================================================
// FCanCheckAttacks - this is overridden for alien grunts
// because they can use their smart weapons against unseen
// enemies. Base class doesn't attack anyone it can't see.
//=========================================================
bool CNPC_AlienGrunt::FCanCheckAttacks ( void )
{
if ( !HasCondition( COND_ENEMY_TOO_FAR ) )
return true;
else
return false;
}
//=========================================================
// CheckMeleeAttack1 - alien grunts zap the crap out of
// any enemy that gets too close.
//=========================================================
int CNPC_AlienGrunt::MeleeAttack1Conditions ( float flDot, float flDist )
{
if ( flDist > AGRUNT_MELEE_DIST )
return COND_NONE;
if ( flDot < 0.6 )
return COND_NONE;
if ( HasCondition ( COND_SEE_ENEMY ) && GetEnemy() != NULL )
return COND_CAN_MELEE_ATTACK1;
return COND_NONE;
}
//=========================================================
// CheckRangeAttack1
//
// !!!LATER - we may want to load balance this. Several
// tracelines are done, so we may not want to do this every
// server frame. Definitely not while firing.
//=========================================================
int CNPC_AlienGrunt::RangeAttack1Conditions ( float flDot, float flDist )
{
if ( gpGlobals->curtime < m_flNextHornetAttackCheck )
{
if ( HasCondition( COND_SEE_ENEMY ) )
{
if ( m_fCanHornetAttack == true )
{
return COND_CAN_RANGE_ATTACK1;
}
else
{
return COND_NONE;
}
}
else
return COND_NONE;
}
if ( flDist < AGRUNT_MELEE_DIST )
return COND_NONE;
if ( flDist > 1024 )
return COND_NONE;
if ( flDot < 0.5 )
return COND_NONE;
if ( HasCondition( COND_SEE_ENEMY ) )
{
trace_t tr;
Vector vecArmPos;
QAngle angArmDir;
// verify that a shot fired from the gun will hit the enemy before the world.
// !!!LATER - we may wish to do something different for projectile weapons as opposed to instant-hit
GetAttachment( "0", vecArmPos, angArmDir );
UTIL_TraceLine( vecArmPos, GetEnemy()->BodyTarget( vecArmPos ), MASK_SOLID, this, COLLISION_GROUP_NONE, &tr);
if ( tr.fraction == 1.0 || tr.m_pEnt == GetEnemy() )
{
m_flNextHornetAttackCheck = gpGlobals->curtime + random->RandomFloat( 2, 5 );
m_fCanHornetAttack = true;
return COND_CAN_RANGE_ATTACK1;
}
}
m_flNextHornetAttackCheck = gpGlobals->curtime + 0.2;// don't check for half second if this check wasn't successful
m_fCanHornetAttack = false;
return COND_NONE;
}
//=========================================================
// StopTalking - won't speak again for 10-20 seconds.
//=========================================================
void CNPC_AlienGrunt::StopTalking( void )
{
m_flNextWordTime = m_flNextSpeakTime = gpGlobals->curtime + 10 + random->RandomInt(0, 10);
}
void CNPC_AlienGrunt::StartTask ( const Task_t *pTask )
{
switch ( pTask->iTask )
{
case TASK_AGRUNT_GET_PATH_TO_ENEMY_CORPSE:
{
Vector forward;
AngleVectors( GetAbsAngles(), &forward );
Vector flEnemyLKP = GetEnemyLKP();
GetNavigator()->SetGoal( flEnemyLKP - forward * 64, AIN_CLEAR_TARGET);
if ( GetNavigator()->SetGoal( flEnemyLKP - forward * 64, AIN_CLEAR_TARGET) )
{
TaskComplete();
}
else
{
Msg ( "AGruntGetPathToEnemyCorpse failed!!\n" );
TaskFail( FAIL_NO_ROUTE );
}
}
break;
case TASK_AGRUNT_SETUP_HIDE_ATTACK:
// alien grunt shoots hornets back out into the open from a concealed location.
// try to find a spot to throw that gives the smart weapon a good chance of finding the enemy.
// ideally, this spot is along a line that is perpendicular to a line drawn from the agrunt to the enemy.
CHL1BaseNPC *pEnemyMonsterPtr;
pEnemyMonsterPtr = (CHL1BaseNPC *)GetEnemy()->MyNPCPointer();
if ( pEnemyMonsterPtr )
{
Vector vecCenter, vForward, vRight, vecEnemyLKP;
QAngle angTmp;
trace_t tr;
BOOL fSkip;
fSkip = FALSE;
vecCenter = WorldSpaceCenter();
vecEnemyLKP = GetEnemyLKP();
VectorAngles( vecEnemyLKP - GetAbsOrigin(), angTmp );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -