📄 hl1_npc_hgrunt.cpp
字号:
break;
case 2:
enginesound->EmitSound( filter, entindex(), CHAN_VOICE, "hgrunt/gr_die3.wav", 1, ATTN_IDLE );
break;
}
}
//=========================================================
// SetActivity
//=========================================================
Activity CNPC_HGrunt::NPC_TranslateActivity( Activity eNewActivity )
{
switch ( eNewActivity)
{
case ACT_RANGE_ATTACK1:
// grunt is either shooting standing or shooting crouched
if (FBitSet( m_iWeapons, HGRUNT_9MMAR))
{
if ( m_fStanding )
{
// get aimable sequence
return (Activity)ACT_GRUNT_MP5_STANDING;
}
else
{
// get crouching shoot
return (Activity)ACT_GRUNT_MP5_CROUCHING;
}
}
else
{
if ( m_fStanding )
{
// get aimable sequence
return (Activity)ACT_GRUNT_SHOTGUN_STANDING;
}
else
{
// get crouching shoot
return (Activity)ACT_GRUNT_SHOTGUN_CROUCHING;
}
}
break;
case ACT_RANGE_ATTACK2:
// grunt is going to a secondary long range attack. This may be a thrown
// grenade or fired grenade, we must determine which and pick proper sequence
if ( m_iWeapons & HGRUNT_HANDGRENADE )
{
// get toss anim
return (Activity)ACT_GRUNT_TOSS_GRENADE;
}
else
{
// get launch anim
return (Activity)ACT_GRUNT_LAUNCH_GRENADE;
}
break;
case ACT_RUN:
if ( m_iHealth <= HGRUNT_LIMP_HEALTH )
{
// limp!
return ACT_RUN_HURT;
}
else
{
return eNewActivity;
}
break;
case ACT_WALK:
if ( m_iHealth <= HGRUNT_LIMP_HEALTH )
{
// limp!
return ACT_WALK_HURT;
}
else
{
return eNewActivity;
}
break;
case ACT_IDLE:
if ( m_NPCState == NPC_STATE_COMBAT )
{
eNewActivity = ACT_IDLE_ANGRY;
}
break;
}
return BaseClass::NPC_TranslateActivity( eNewActivity );
}
void CNPC_HGrunt::ClearAttackConditions( void )
{
bool fCanRangeAttack2 = HasCondition( COND_CAN_RANGE_ATTACK2 );
// Call the base class.
BaseClass::ClearAttackConditions();
if( fCanRangeAttack2 )
{
// We don't allow the base class to clear this condition because we
// don't sense for it every frame.
SetCondition( COND_CAN_RANGE_ATTACK2 );
}
}
int CNPC_HGrunt::SelectSchedule( void )
{
// clear old sentence
m_iSentence = HGRUNT_SENT_NONE;
// flying? If PRONE, barnacle has me. IF not, it's assumed I am rapelling.
if ( GetMoveType() == MOVETYPE_FLY && m_NPCState != NPC_STATE_PRONE )
{
if (GetFlags() & FL_ONGROUND)
{
// just landed
SetMoveType( MOVETYPE_STEP );
return SCHED_GRUNT_REPEL_LAND;
}
else
{
// repel down a rope,
if ( m_NPCState == NPC_STATE_COMBAT )
return SCHED_GRUNT_REPEL_ATTACK;
else
return SCHED_GRUNT_REPEL;
}
}
// grunts place HIGH priority on running away from danger sounds.
if ( HasCondition ( COND_HEAR_DANGER ) )
{
// dangerous sound nearby!
//!!!KELLY - currently, this is the grunt's signal that a grenade has landed nearby,
// and the grunt should find cover from the blast
// good place for "SHIT!" or some other colorful verbal indicator of dismay.
// It's not safe to play a verbal order here "Scatter", etc cause
// this may only affect a single individual in a squad.
if (FOkToSpeak())
{
SENTENCEG_PlayRndSz( edict(), "HG_GREN", HGRUNT_SENTENCE_VOLUME, GRUNT_SNDLVL, 0, m_voicePitch);
JustSpoke();
}
return SCHED_TAKE_COVER_FROM_BEST_SOUND;
}
switch ( m_NPCState )
{
case NPC_STATE_PRONE:
{
if (m_bInBarnacleMouth)
{
return SCHED_GRUNT_BARNACLE_CHOMP;
}
else
{
return SCHED_GRUNT_BARNACLE_HIT;
}
}
case NPC_STATE_COMBAT:
{
// dead enemy
if ( HasCondition( COND_ENEMY_DEAD ) )
{
// call base class, all code to handle dead enemies is centralized there.
return BaseClass::SelectSchedule();
}
// new enemy
if ( HasCondition( COND_NEW_ENEMY) )
{
if ( m_pSquad )
{
if ( !m_pSquad->IsLeader( this ) )
{
return SCHED_TAKE_COVER_FROM_ENEMY;
}
else
{
//!!!KELLY - the leader of a squad of grunts has just seen the player or a
// monster and has made it the squad's enemy. You
// can check pev->flags for FL_CLIENT to determine whether this is the player
// or a monster. He's going to immediately start
// firing, though. If you'd like, we can make an alternate "first sight"
// schedule where the leader plays a handsign anim
// that gives us enough time to hear a short sentence or spoken command
// before he starts pluggin away.
if (FOkToSpeak())// && RANDOM_LONG(0,1))
{
if ((GetEnemy() != NULL) && GetEnemy()->IsPlayer())
// player
SENTENCEG_PlayRndSz( edict(), "HG_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_SNDLVL, 0, m_voicePitch);
else if ((GetEnemy() != NULL) &&
(GetEnemy()->Classify() != CLASS_PLAYER_ALLY) &&
(GetEnemy()->Classify() != CLASS_HUMAN_PASSIVE) &&
(GetEnemy()->Classify() != CLASS_MACHINE) )
// monster
SENTENCEG_PlayRndSz( edict(), "HG_MONST", HGRUNT_SENTENCE_VOLUME, GRUNT_SNDLVL, 0, m_voicePitch);
JustSpoke();
}
if ( HasCondition ( COND_CAN_RANGE_ATTACK1 ) )
{
return SCHED_GRUNT_SUPPRESS;
}
else
{
return SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE;
}
}
}
}
// no ammo
else if ( HasCondition ( COND_NO_PRIMARY_AMMO ) )
{
//!!!KELLY - this individual just realized he's out of bullet ammo.
// He's going to try to find cover to run to and reload, but rarely, if
// none is available, he'll drop and reload in the open here.
return SCHED_GRUNT_HIDE_RELOAD;
}
// damaged just a little
else if ( HasCondition( COND_LIGHT_DAMAGE ) )
{
// if hurt:
// 90% chance of taking cover
// 10% chance of flinch.
int iPercent = random->RandomInt(0,99);
if ( iPercent <= 90 && GetEnemy() != NULL )
{
// only try to take cover if we actually have an enemy!
//!!!KELLY - this grunt was hit and is going to run to cover.
if (FOkToSpeak()) // && RANDOM_LONG(0,1))
{
//SENTENCEG_PlayRndSz( ENT(pev), "HG_COVER", HGRUNT_SENTENCE_VOLUME, GRUNT_SNDLVL, 0, m_voicePitch);
m_iSentence = HGRUNT_SENT_COVER;
//JustSpoke();
}
return SCHED_TAKE_COVER_FROM_ENEMY;
}
else
{
return SCHED_SMALL_FLINCH;
}
}
// can kick
else if ( HasCondition( COND_CAN_MELEE_ATTACK1 ) )
{
return SCHED_MELEE_ATTACK1;
}
// can grenade launch
else if ( FBitSet( m_iWeapons, HGRUNT_GRENADELAUNCHER) && HasCondition ( COND_CAN_RANGE_ATTACK2 ) && OccupyStrategySlotRange( SQUAD_SLOT_GRENADE1, SQUAD_SLOT_GRENADE2 ) )
{
// shoot a grenade if you can
return SCHED_RANGE_ATTACK2;
}
// can shoot
else if ( HasCondition ( COND_CAN_RANGE_ATTACK1 ) )
{
if ( m_pSquad )
{
if ( m_pSquad->GetLeader() != NULL )
{
CAI_BaseNPC *pSquadLeader = m_pSquad->GetLeader()->MyNPCPointer();
// if the enemy has eluded the squad and a squad member has just located the enemy
// and the enemy does not see the squad member, issue a call to the squad to waste a
// little time and give the player a chance to turn.
if ( pSquadLeader && pSquadLeader->EnemyHasEludedMe() && !HasCondition ( COND_ENEMY_FACING_ME ) )
{
return SCHED_GRUNT_FOUND_ENEMY;
}
}
}
if ( OccupyStrategySlotRange ( SQUAD_SLOT_ENGAGE1, SQUAD_SLOT_ENGAGE2 ) )
{
// try to take an available ENGAGE slot
return SCHED_RANGE_ATTACK1;
}
else if ( HasCondition ( COND_CAN_RANGE_ATTACK2 ) && OccupyStrategySlotRange( SQUAD_SLOT_GRENADE1, SQUAD_SLOT_GRENADE2 ) )
{
// throw a grenade if can and no engage slots are available
return SCHED_RANGE_ATTACK2;
}
else
{
// hide!
return SCHED_TAKE_COVER_FROM_ENEMY;
}
}
// can't see enemy
else if ( HasCondition( COND_ENEMY_OCCLUDED ) )
{
if ( HasCondition( COND_CAN_RANGE_ATTACK2 ) && OccupyStrategySlotRange( SQUAD_SLOT_GRENADE1, SQUAD_SLOT_GRENADE2 ) )
{
//!!!KELLY - this grunt is about to throw or fire a grenade at the player. Great place for "fire in the hole" "frag out" etc
if (FOkToSpeak())
{
SENTENCEG_PlayRndSz( edict(), "HG_THROW", HGRUNT_SENTENCE_VOLUME, GRUNT_SNDLVL, 0, m_voicePitch);
JustSpoke();
}
return SCHED_RANGE_ATTACK2;
}
else if ( OccupyStrategySlotRange ( SQUAD_SLOT_ENGAGE1, SQUAD_SLOT_ENGAGE2 ) )
{
//!!!KELLY - grunt cannot see the enemy and has just decided to
// charge the enemy's position.
if (FOkToSpeak())// && RANDOM_LONG(0,1))
{
//SENTENCEG_PlayRndSz( ENT(pev), "HG_CHARGE", HGRUNT_SENTENCE_VOLUME, GRUNT_SNDLVL, 0, m_voicePitch);
m_iSentence = HGRUNT_SENT_CHARGE;
//JustSpoke();
}
return SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE;
}
else
{
//!!!KELLY - grunt is going to stay put for a couple seconds to see if
// the enemy wanders back out into the open, or approaches the
// grunt's covered position. Good place for a taunt, I guess?
if (FOkToSpeak() && random->RandomInt(0,1))
{
SENTENCEG_PlayRndSz( edict(), "HG_TAUNT", HGRUNT_SENTENCE_VOLUME, GRUNT_SNDLVL, 0, m_voicePitch);
JustSpoke();
}
return SCHED_STANDOFF;
}
}
if ( HasCondition( COND_SEE_ENEMY ) && !HasCondition ( COND_CAN_RANGE_ATTACK1 ) )
{
return SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE;
}
}
case NPC_STATE_ALERT:
if ( HasCondition( COND_ENEMY_DEAD ) && SelectWeightedSequence( ACT_VICTORY_DANCE ) != ACTIVITY_NOT_AVAILABLE )
{
// Scan around for new enemies
return SCHED_VICTORY_DANCE;
}
break;
}
return BaseClass::SelectSchedule();
}
int CNPC_HGrunt::TranslateSchedule( int scheduleType )
{
if ( scheduleType == SCHED_CHASE_ENEMY_FAILED )
{
return SCHED_ESTABLISH_LINE_OF_FIRE;
}
switch ( scheduleType )
{
case SCHED_TAKE_COVER_FROM_ENEMY:
{
if ( m_pSquad )
{
if ( g_iSkillLevel == SKILL_HARD && HasCondition( COND_CAN_RANGE_ATTACK2 ) && OccupyStrategySlotRange( SQUAD_SLOT_GRENADE1, SQUAD_SLOT_GRENADE2 ) )
{
if (FOkToSpeak())
{
SENTENCEG_PlayRndSz( edict(), "HG_THROW", HGRUNT_SENTENCE_VOLUME, GRUNT_SNDLVL, 0, m_voicePitch);
JustSpoke();
}
return SCHED_GRUNT_TOSS_GRENADE_COVER;
}
else
{
return SCHED_GRUNT_TAKE_COVER;
}
}
else
{
if ( random->RandomInt(0,1) )
{
return SCHED_GRUNT_TAKE_COVER;
}
else
{
return SCHED_GRUNT_GRENADE_COVER;
}
}
}
case SCHED_GRUNT_TAKE_COVER_FAILED:
{
if ( HasCondition( COND_CAN_RANGE_ATTACK1 ) && OccupyStrategySlotRange( SQUAD_SLOT_ATTACK1, SQUAD_SLOT_ATTACK2 ) )
{
return SCHED_RANGE_ATTACK1;
}
return SCHED_FAIL;
}
break;
case SCHED_RANGE_ATTACK1:
{
// randomly stand or crouch
if ( random->RandomInt( 0,9 ) == 0)
{
m_fStanding = random->RandomInt( 0, 1 ) != 0;
}
if ( m_fStanding )
return SCHED_GRUNT_RANGE_ATTACK1B;
else
return SCHED_GRUNT_RANGE_ATTACK1A;
}
case SCHED_RANGE_ATTACK2:
{
return SCHED_GRUNT_RANGE_ATTACK2;
}
case SCHED_VICTORY_DANCE:
{
if ( m_pSquad )
{
if ( !m_pSquad->IsLeader( this ) )
{
return SCHED_GRUNT_FAIL;
}
}
return SCHED_GRUNT_VICTORY_DANCE;
}
case SCHED_GRUNT_SUPPRESS:
{
if ( GetEnemy()->IsPlayer() && m_fFirstEncounter )
{
m_fFirstEncounter = FALSE;// after first encounter, leader won't issue handsigns anymore when he has a new enemy
return SCHED_GRUNT_SIGNAL_SUPPRESS;
}
else
{
return SCHED_GRUNT_SUPPRESS;
}
}
case SCHED_FAIL:
{
if ( GetEnemy() != NULL )
{
// grunt has an enemy, so pick a different default fail schedule most likely to help recover.
return SCHED_GRUNT_COMBAT_FAIL;
}
return SCHED_GRUNT_FAIL;
}
case SCHED_GRUNT_REPEL:
{
Vector vecVel = GetAbsVelocity();
if ( vecVel.z > -128 )
{
vecVel.z -= 32;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -