Advertisement
Guest User

hgrunt.cpp (2008)

a guest
Sep 2nd, 2011
300
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 74.52 KB | None | 0 0
  1. /***
  2. *
  3. *   Copyright (c) 1996-2002, Valve LLC. All rights reserved.
  4. *  
  5. *   This product contains software technology licensed from Id
  6. *   Software, Inc. ("Id Technology").  Id Technology (c) 1996 Id Software, Inc.
  7. *   All Rights Reserved.
  8. *
  9. *   This source code contains proprietary and confidential information of
  10. *   Valve LLC and its suppliers.  Access to this code is restricted to
  11. *   persons who have executed a written SDK license with Valve.  Any access,
  12. *   use or distribution of this code by or to any unlicensed person is illegal.
  13. *
  14. ****/
  15. //=========================================================
  16. // hgrunt
  17. //=========================================================
  18.  
  19. //=========================================================
  20. // Hit groups! 
  21. //=========================================================
  22. /*
  23.  
  24.   1 - Head
  25.   2 - Stomach
  26.   3 - Gun
  27.  
  28. */
  29.  
  30.  
  31. #include    "extdll.h"
  32. #include    "plane.h"
  33. #include    "util.h"
  34. #include    "cbase.h"
  35. #include    "monsters.h"
  36. #include    "schedule.h"
  37. #include    "animation.h"
  38. #include    "squadmonster.h"
  39. #include    "weapons.h"
  40. #include    "talkmonster.h"
  41. #include    "soundent.h"
  42. #include    "effects.h"
  43. #include    "customentity.h"
  44.  
  45. int g_fGruntQuestion;               // true if an idle grunt asked a question. Cleared when someone answers.
  46.  
  47. extern DLL_GLOBAL int       g_iSkillLevel;
  48.  
  49. //=========================================================
  50. // monster-specific DEFINE's
  51. //=========================================================
  52. #define GRUNT_CLIP_SIZE                 36 // how many bullets in a clip? - NOTE: 3 round burst sound, so keep as 3 * x!
  53. #define GRUNT_VOL                       0.35        // volume of grunt sounds
  54. #define GRUNT_ATTN                      ATTN_NORM   // attenutation of grunt sentences
  55. #define HGRUNT_LIMP_HEALTH              20
  56. #define HGRUNT_DMG_HEADSHOT             ( DMG_BULLET | DMG_CLUB )   // damage types that can kill a grunt with a single headshot.
  57. #define HGRUNT_NUM_HEADS                2 // how many grunt heads are there?
  58. #define HGRUNT_MINIMUM_HEADSHOT_DAMAGE  15 // must do at least this much damage in one shot to head to score a headshot kill
  59. #define HGRUNT_SENTENCE_VOLUME          (float)0.35 // volume of grunt sentences
  60.  
  61. #define HGRUNT_9MMAR                ( 1 << 0)
  62. #define HGRUNT_HANDGRENADE          ( 1 << 1)
  63. #define HGRUNT_GRENADELAUNCHER      ( 1 << 2)
  64. #define HGRUNT_SHOTGUN              ( 1 << 3)
  65.  
  66. #define HEAD_GROUP                  1
  67. #define HEAD_GRUNT                  0
  68. #define HEAD_COMMANDER              1
  69. #define HEAD_SHOTGUN                2
  70. #define HEAD_M203                   3
  71. #define GUN_GROUP                   2
  72. #define GUN_MP5                     0
  73. #define GUN_SHOTGUN                 1
  74. #define GUN_NONE                    2
  75.  
  76. //=========================================================
  77. // Monster's Anim Events Go Here
  78. //=========================================================
  79. #define     HGRUNT_AE_RELOAD        ( 2 )
  80. #define     HGRUNT_AE_KICK          ( 3 )
  81. #define     HGRUNT_AE_BURST1        ( 4 )
  82. #define     HGRUNT_AE_BURST2        ( 5 )
  83. #define     HGRUNT_AE_BURST3        ( 6 )
  84. #define     HGRUNT_AE_GREN_TOSS     ( 7 )
  85. #define     HGRUNT_AE_GREN_LAUNCH   ( 8 )
  86. #define     HGRUNT_AE_GREN_DROP     ( 9 )
  87. #define     HGRUNT_AE_CAUGHT_ENEMY  ( 10) // grunt established sight with an enemy (player only) that had previously eluded the squad.
  88. #define     HGRUNT_AE_DROP_GUN      ( 11) // grunt (probably dead) is dropping his mp5.
  89.  
  90. //=========================================================
  91. // monster-specific schedule types
  92. //=========================================================
  93. enum
  94. {
  95.     SCHED_GRUNT_SUPPRESS = LAST_COMMON_SCHEDULE + 1,
  96.     SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE,// move to a location to set up an attack against the enemy. (usually when a friendly is in the way).
  97.     SCHED_GRUNT_COVER_AND_RELOAD,
  98.     SCHED_GRUNT_SWEEP,
  99.     SCHED_GRUNT_FOUND_ENEMY,
  100.     SCHED_GRUNT_REPEL,
  101.     SCHED_GRUNT_REPEL_ATTACK,
  102.     SCHED_GRUNT_REPEL_LAND,
  103.     SCHED_GRUNT_WAIT_FACE_ENEMY,
  104.     SCHED_GRUNT_TAKECOVER_FAILED,// special schedule type that forces analysis of conditions and picks the best possible schedule to recover from this type of failure.
  105.     SCHED_GRUNT_ELOF_FAIL,
  106. };
  107.  
  108. //=========================================================
  109. // monster-specific tasks
  110. //=========================================================
  111. enum
  112. {
  113.     TASK_GRUNT_FACE_TOSS_DIR = LAST_COMMON_TASK + 1,
  114.     TASK_GRUNT_SPEAK_SENTENCE,
  115.     TASK_GRUNT_CHECK_FIRE,
  116. };
  117.  
  118. //=========================================================
  119. // monster-specific conditions
  120. //=========================================================
  121. #define bits_COND_GRUNT_NOFIRE  ( bits_COND_SPECIAL1 )
  122.  
  123. class CHGrunt : public CSquadMonster, public CTalkMonster
  124. {
  125. public:
  126.     void Spawn( void );
  127.     void Precache( void );
  128.     void SetYawSpeed ( void );
  129.     int  Classify ( void );
  130.     int ISoundMask ( void );
  131.     void HandleAnimEvent( MonsterEvent_t *pEvent );
  132.     BOOL FCanCheckAttacks ( void );
  133.     BOOL CheckMeleeAttack1 ( float flDot, float flDist );
  134.     BOOL CheckRangeAttack1 ( float flDot, float flDist );
  135.     BOOL CheckRangeAttack2 ( float flDot, float flDist );
  136.     void CheckAmmo ( void );
  137.     void SetActivity ( Activity NewActivity );
  138.     void StartTask ( Task_t *pTask );
  139.     void RunTask ( Task_t *pTask );
  140.     void DeathSound( void );
  141.     void PainSound( void );
  142.     void IdleSound ( void );
  143.     Vector GetGunPosition( void );
  144.     void Shoot ( void );
  145.     void Shotgun ( void );
  146.     void PrescheduleThink ( void );
  147.     void GibMonster( void );
  148.     void SpeakSentence( void );
  149.  
  150.     virtual int ObjectCaps( void ) { return CTalkMonster :: ObjectCaps() | FCAP_IMPULSE_USE; }
  151.     void TalkInit( void ); // Talk n shit
  152.     void DeclineFollowing( void );
  153.  
  154.     int Save( CSave &save );
  155.     int Restore( CRestore &restore );
  156.    
  157.     CBaseEntity *Kick( void );
  158.     Schedule_t  *GetSchedule( void );
  159.     Schedule_t  *GetScheduleOfType ( int Type );
  160.     void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);
  161.     int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
  162.  
  163.     int IRelationship ( CBaseEntity *pTarget );
  164.  
  165.     BOOL FOkToSpeak( void );
  166.     void JustSpoke( void );
  167.  
  168.     float   m_flPlayerDamage;// how much pain has the player inflicted on me?
  169.  
  170.     CUSTOM_SCHEDULES;
  171.     static TYPEDESCRIPTION m_SaveData[];
  172.  
  173.     // checking the feasibility of a grenade toss is kind of costly, so we do it every couple of seconds,
  174.     // not every server frame.
  175.     float m_flNextGrenadeCheck;
  176.     float m_flNextPainTime;
  177.     float m_flLastEnemySightTime;
  178.  
  179.     Vector  m_vecTossVelocity;
  180.  
  181.     BOOL    m_fThrowGrenade;
  182.     BOOL    m_fStanding;
  183.     BOOL    m_fFirstEncounter;// only put on the handsign show in the squad's first encounter.
  184.     int     m_cClipSize;
  185.  
  186.     int m_voicePitch;
  187.  
  188.     int     m_iBrassShell;
  189.     int     m_iShotgunShell;
  190.  
  191.     int     m_iSentence;
  192.  
  193.     static const char *pGruntSentences[];
  194. };
  195.  
  196. LINK_ENTITY_TO_CLASS( monster_human_grunt, CHGrunt );
  197.  
  198. TYPEDESCRIPTION CHGrunt::m_SaveData[] =
  199. {
  200.     DEFINE_FIELD( CHGrunt, m_flNextGrenadeCheck, FIELD_TIME ),
  201.     DEFINE_FIELD( CHGrunt, m_flNextPainTime, FIELD_TIME ),
  202. //  DEFINE_FIELD( CHGrunt, m_flLastEnemySightTime, FIELD_TIME ), // don't save, go to zero
  203.     DEFINE_FIELD( CHGrunt, m_vecTossVelocity, FIELD_VECTOR ),
  204.     DEFINE_FIELD( CHGrunt, m_fThrowGrenade, FIELD_BOOLEAN ),
  205.     DEFINE_FIELD( CHGrunt, m_fStanding, FIELD_BOOLEAN ),
  206.     DEFINE_FIELD( CHGrunt, m_fFirstEncounter, FIELD_BOOLEAN ),
  207.     DEFINE_FIELD( CHGrunt, m_cClipSize, FIELD_INTEGER ),
  208.     DEFINE_FIELD( CHGrunt, m_voicePitch, FIELD_INTEGER ),
  209. //  DEFINE_FIELD( CShotgun, m_iBrassShell, FIELD_INTEGER ),
  210. //  DEFINE_FIELD( CShotgun, m_iShotgunShell, FIELD_INTEGER ),
  211.     DEFINE_FIELD( CHGrunt, m_iSentence, FIELD_INTEGER ),
  212. };
  213.  
  214. IMPLEMENT_SAVERESTORE( CHGrunt, CSquadMonster );
  215.  
  216. const char *CHGrunt::pGruntSentences[] =
  217. {
  218.     "HG_GRENADE", // grenade scared grunt
  219.     "HG_ENEMY", // sees player
  220.     "HG_ENEMY_MON", // sees monster
  221.     "HG_TAKECOVER", // running to cover
  222.     "HG_GRENADE_THROW", // about to throw grenade
  223.     "HG_GO",  // running out to get the enemy
  224.     "HG_TAUNTS", // say rude things
  225. };
  226.  
  227. enum
  228. {
  229.     HGRUNT_SENT_NONE = -1,
  230.     HGRUNT_SENT_GREN = 0,
  231.     HGRUNT_SENT_ALERT,
  232.     HGRUNT_SENT_MONSTER,
  233.     HGRUNT_SENT_COVER,
  234.     HGRUNT_SENT_THROW,
  235.     HGRUNT_SENT_CHARGE,
  236.     HGRUNT_SENT_TAUNT,
  237. } HGRUNT_SENTENCE_TYPES;
  238.  
  239. //=========================================================
  240. // Speak Sentence - say your cued up sentence.
  241. //
  242. // Some grunt sentences (take cover and charge) rely on actually
  243. // being able to execute the intended action. It's really lame
  244. // when a grunt says 'COVER ME' and then doesn't move. The problem
  245. // is that the sentences were played when the decision to TRY
  246. // to move to cover was made. Now the sentence is played after
  247. // we know for sure that there is a valid path. The schedule
  248. // may still fail but in most cases, well after the grunt has
  249. // started moving.
  250. //=========================================================
  251. void CHGrunt::DeclineFollowing( void )
  252. {
  253.     PlaySentence( "HG_POK", 2, VOL_NORM, ATTN_NORM );
  254. }
  255.  
  256. void CHGrunt :: SpeakSentence( void )
  257. {
  258.     if ( m_iSentence == HGRUNT_SENT_NONE )
  259.     {
  260.         // no sentence cued up.
  261.         return;
  262.     }
  263.  
  264.     if (FOkToSpeak())
  265.     {
  266.         SENTENCEG_PlayRndSz( ENT(pev), pGruntSentences[ m_iSentence ], HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
  267.         JustSpoke();
  268.     }
  269. }
  270.  
  271. //=========================================================
  272. // IRelationship - overridden because Alien Grunts are
  273. // Human Grunt's nemesis.
  274. //=========================================================
  275. int CHGrunt::IRelationship ( CBaseEntity *pTarget )
  276. {
  277.     if ( FClassnameIs( pTarget->pev, "monster_blackops" ) || ( FClassnameIs( pTarget->pev,  "monster_gargantua" ) ) )
  278.     {
  279.         return R_NM;
  280.     }
  281.  
  282.     return CSquadMonster::IRelationship( pTarget );
  283. }
  284.  
  285. //=========================================================
  286. // GibMonster - make gun fly through the air.
  287. //=========================================================
  288. void CHGrunt :: GibMonster ( void )
  289. {
  290.     Vector  vecGunPos;
  291.     Vector  vecGunAngles;
  292.  
  293.     if ( GetBodygroup( 2 ) != 2 )
  294.     {// throw a gun if the grunt has one
  295.         GetAttachment( 0, vecGunPos, vecGunAngles );
  296.        
  297.         CBaseEntity *pGun;
  298.         if (FBitSet( pev->weapons, HGRUNT_SHOTGUN ))
  299.         {
  300.             pGun = DropItem( "weapon_shotgun", vecGunPos, vecGunAngles );
  301.         }
  302.         else
  303.         {
  304.             pGun = DropItem( "weapon_9mmAR", vecGunPos, vecGunAngles );
  305.         }
  306.         if ( pGun )
  307.         {
  308.             pGun->pev->velocity = Vector (RANDOM_FLOAT(-100,100), RANDOM_FLOAT(-100,100), RANDOM_FLOAT(200,300));
  309.             pGun->pev->avelocity = Vector ( 0, RANDOM_FLOAT( 200, 400 ), 0 );
  310.         }
  311.    
  312.         if (FBitSet( pev->weapons, HGRUNT_GRENADELAUNCHER ))
  313.         {
  314.             pGun = DropItem( "ammo_ARgrenades", vecGunPos, vecGunAngles );
  315.             if ( pGun )
  316.             {
  317.                 pGun->pev->velocity = Vector (RANDOM_FLOAT(-100,100), RANDOM_FLOAT(-100,100), RANDOM_FLOAT(200,300));
  318.                 pGun->pev->avelocity = Vector ( 0, RANDOM_FLOAT( 200, 400 ), 0 );
  319.             }
  320.         }
  321.     }
  322.  
  323.     CBaseMonster :: GibMonster();
  324. }
  325.  
  326. //=========================================================
  327. // ISoundMask - Overidden for human grunts because they
  328. // hear the DANGER sound that is made by hand grenades and
  329. // other dangerous items.
  330. //=========================================================
  331. int CHGrunt :: ISoundMask ( void )
  332. {
  333.     return  bits_SOUND_WORLD    |
  334.             bits_SOUND_COMBAT   |
  335.             bits_SOUND_PLAYER   |
  336.             bits_SOUND_DANGER;
  337. }
  338.  
  339. //=========================================================
  340. // someone else is talking - don't speak
  341. //=========================================================
  342. BOOL CHGrunt :: FOkToSpeak( void )
  343. {
  344. // if someone else is talking, don't speak
  345.     if (gpGlobals->time <= CTalkMonster::g_talkWaitTime)
  346.         return FALSE;
  347.  
  348.     if ( pev->spawnflags & SF_MONSTER_GAG )
  349.     {
  350.         if ( m_MonsterState != MONSTERSTATE_COMBAT )
  351.         {
  352.             // no talking outside of combat if gagged.
  353.             return FALSE;
  354.         }
  355.     }
  356.  
  357.     // if player is not in pvs, don't speak
  358. //  if (FNullEnt(FIND_CLIENT_IN_PVS(edict())))
  359. //      return FALSE;
  360.    
  361.     return TRUE;
  362. }
  363.  
  364. //=========================================================
  365. //=========================================================
  366. void CHGrunt :: JustSpoke( void )
  367. {
  368.     CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT(1.5, 2.0);
  369.     m_iSentence = HGRUNT_SENT_NONE;
  370. }
  371.  
  372. //=========================================================
  373. // PrescheduleThink - this function runs after conditions
  374. // are collected and before scheduling code is run.
  375. //=========================================================
  376. void CHGrunt :: PrescheduleThink ( void )
  377. {
  378.     if ( InSquad() && m_hEnemy != NULL )
  379.     {
  380.         if ( HasConditions ( bits_COND_SEE_ENEMY ) )
  381.         {
  382.             // update the squad's last enemy sighting time.
  383.             MySquadLeader()->m_flLastEnemySightTime = gpGlobals->time;
  384.         }
  385.         else
  386.         {
  387.             if ( gpGlobals->time - MySquadLeader()->m_flLastEnemySightTime > 5 )
  388.             {
  389.                 // been a while since we've seen the enemy
  390.                 MySquadLeader()->m_fEnemyEluded = TRUE;
  391.             }
  392.         }
  393.     }
  394. }
  395.  
  396. // FACING SHIT
  397.  
  398. static BOOL IsFacing( entvars_t *pevTest, const Vector &reference )
  399. {
  400.     Vector vecDir = (reference - pevTest->origin);
  401.     vecDir.z = 0;
  402.     vecDir = vecDir.Normalize();
  403.     Vector forward, angle;
  404.     angle = pevTest->v_angle;
  405.     angle.x = 0;
  406.     UTIL_MakeVectorsPrivate( angle, forward, NULL, NULL );
  407.     // He's facing me, he meant it
  408.     if ( DotProduct( forward, vecDir ) > 0.96 ) // +/- 15 degrees or so
  409.     {
  410.         return TRUE;
  411.     }
  412.     return FALSE;
  413. }
  414.  
  415. //=========================================================
  416. // FCanCheckAttacks - this is overridden for human grunts
  417. // because they can throw/shoot grenades when they can't see their
  418. // target and the base class doesn't check attacks if the monster
  419. // cannot see its enemy.
  420. //
  421. // !!!BUGBUG - this gets called before a 3-round burst is fired
  422. // which means that a friendly can still be hit with up to 2 rounds.
  423. // ALSO, grenades will not be tossed if there is a friendly in front,
  424. // this is a bad bug. Friendly machine gun fire avoidance
  425. // will unecessarily prevent the throwing of a grenade as well.
  426. //=========================================================
  427. BOOL CHGrunt :: FCanCheckAttacks ( void )
  428. {
  429.     if ( !HasConditions( bits_COND_ENEMY_TOOFAR ) )
  430.     {
  431.         return TRUE;
  432.     }
  433.     else
  434.     {
  435.         return FALSE;
  436.     }
  437. }
  438.  
  439.  
  440. //=========================================================
  441. // CheckMeleeAttack1
  442. //=========================================================
  443. BOOL CHGrunt :: CheckMeleeAttack1 ( float flDot, float flDist )
  444. {
  445.     CBaseMonster *pEnemy;
  446.  
  447.     if ( m_hEnemy != NULL )
  448.     {
  449.         pEnemy = m_hEnemy->MyMonsterPointer();
  450.  
  451.         if ( !pEnemy )
  452.         {
  453.             return FALSE;
  454.         }
  455.     }
  456.  
  457.     if ( flDist <= 64 && flDot >= 0.7   &&
  458.          pEnemy->Classify() != CLASS_ALIEN_BIOWEAPON &&
  459.          pEnemy->Classify() != CLASS_PLAYER_BIOWEAPON )
  460.     {
  461.         return TRUE;
  462.     }
  463.     return FALSE;
  464. }
  465.  
  466. //=========================================================
  467. // CheckRangeAttack1 - overridden for HGrunt, cause
  468. // FCanCheckAttacks() doesn't disqualify all attacks based
  469. // on whether or not the enemy is occluded because unlike
  470. // the base class, the HGrunt can attack when the enemy is
  471. // occluded (throw grenade over wall, etc). We must
  472. // disqualify the machine gun attack if the enemy is occluded.
  473. //=========================================================
  474. BOOL CHGrunt :: CheckRangeAttack1 ( float flDot, float flDist )
  475. {
  476.     if ( !HasConditions( bits_COND_ENEMY_OCCLUDED ) && flDist <= 2048 && flDot >= 0.5 && NoFriendlyFire() )
  477.     {
  478.         TraceResult tr;
  479.  
  480.         if ( !m_hEnemy->IsPlayer() && flDist <= 64 )
  481.         {
  482.             // kick nonclients, but don't shoot at them.
  483.             return FALSE;
  484.         }
  485.  
  486.         Vector vecSrc = GetGunPosition();
  487.  
  488.         // verify that a bullet fired from the gun will hit the enemy before the world.
  489.         UTIL_TraceLine( vecSrc, m_hEnemy->BodyTarget(vecSrc), ignore_monsters, ignore_glass, ENT(pev), &tr);
  490.  
  491.         if ( tr.flFraction == 1.0 )
  492.         {
  493.             return TRUE;
  494.         }
  495.     }
  496.  
  497.     return FALSE;
  498. }
  499.  
  500. //=========================================================
  501. // CheckRangeAttack2 - this checks the Grunt's grenade
  502. // attack.
  503. //=========================================================
  504. BOOL CHGrunt :: CheckRangeAttack2 ( float flDot, float flDist )
  505. {
  506.     if (! FBitSet(pev->weapons, (HGRUNT_HANDGRENADE | HGRUNT_GRENADELAUNCHER)))
  507.     {
  508.         return FALSE;
  509.     }
  510.    
  511.     // if the grunt isn't moving, it's ok to check.
  512.     if ( m_flGroundSpeed != 0 )
  513.     {
  514.         m_fThrowGrenade = FALSE;
  515.         return m_fThrowGrenade;
  516.     }
  517.  
  518.     // assume things haven't changed too much since last time
  519.     if (gpGlobals->time < m_flNextGrenadeCheck )
  520.     {
  521.         return m_fThrowGrenade;
  522.     }
  523.  
  524.     if ( !FBitSet ( m_hEnemy->pev->flags, FL_ONGROUND ) && m_hEnemy->pev->waterlevel == 0 && m_vecEnemyLKP.z > pev->absmax.z  )
  525.     {
  526.         //!!!BUGBUG - we should make this check movetype and make sure it isn't FLY? Players who jump a lot are unlikely to
  527.         // be grenaded.
  528.         // don't throw grenades at anything that isn't on the ground!
  529.         m_fThrowGrenade = FALSE;
  530.         return m_fThrowGrenade;
  531.     }
  532.    
  533.     Vector vecTarget;
  534.  
  535.     if (FBitSet( pev->weapons, HGRUNT_HANDGRENADE))
  536.     {
  537.         // find feet
  538.         if (RANDOM_LONG(0,1))
  539.         {
  540.             // magically know where they are
  541.             vecTarget = Vector( m_hEnemy->pev->origin.x, m_hEnemy->pev->origin.y, m_hEnemy->pev->absmin.z );
  542.         }
  543.         else
  544.         {
  545.             // toss it to where you last saw them
  546.             vecTarget = m_vecEnemyLKP;
  547.         }
  548.         // vecTarget = m_vecEnemyLKP + (m_hEnemy->BodyTarget( pev->origin ) - m_hEnemy->pev->origin);
  549.         // estimate position
  550.         // vecTarget = vecTarget + m_hEnemy->pev->velocity * 2;
  551.     }
  552.     else
  553.     {
  554.         // find target
  555.         // vecTarget = m_hEnemy->BodyTarget( pev->origin );
  556.         vecTarget = m_vecEnemyLKP + (m_hEnemy->BodyTarget( pev->origin ) - m_hEnemy->pev->origin);
  557.         // estimate position
  558.         if (HasConditions( bits_COND_SEE_ENEMY))
  559.             vecTarget = vecTarget + ((vecTarget - pev->origin).Length() / gSkillData.hgruntGrenadeSpeed) * m_hEnemy->pev->velocity;
  560.     }
  561.  
  562.     // are any of my squad members near the intended grenade impact area?
  563.     if ( InSquad() )
  564.     {
  565.         if (SquadMemberInRange( vecTarget, 256 ))
  566.         {
  567.             // crap, I might blow my own guy up. Don't throw a grenade and don't check again for a while.
  568.             m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second.
  569.             m_fThrowGrenade = FALSE;
  570.         }
  571.     }
  572.    
  573.     if ( ( vecTarget - pev->origin ).Length2D() <= 256 )
  574.     {
  575.         // crap, I don't want to blow myself up
  576.         m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second.
  577.         m_fThrowGrenade = FALSE;
  578.         return m_fThrowGrenade;
  579.     }
  580.  
  581.        
  582.     if (FBitSet( pev->weapons, HGRUNT_HANDGRENADE))
  583.     {
  584.         Vector vecToss = VecCheckToss( pev, GetGunPosition(), vecTarget, 0.5 );
  585.  
  586.         if ( vecToss != g_vecZero )
  587.         {
  588.             m_vecTossVelocity = vecToss;
  589.  
  590.             // throw a hand grenade
  591.             m_fThrowGrenade = TRUE;
  592.             // don't check again for a while.
  593.             m_flNextGrenadeCheck = gpGlobals->time; // 1/3 second.
  594.         }
  595.         else
  596.         {
  597.             // don't throw
  598.             m_fThrowGrenade = FALSE;
  599.             // don't check again for a while.
  600.             m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second.
  601.         }
  602.     }
  603.     else
  604.     {
  605.         Vector vecToss = VecCheckThrow( pev, GetGunPosition(), vecTarget, gSkillData.hgruntGrenadeSpeed, 0.5 );
  606.  
  607.         if ( vecToss != g_vecZero )
  608.         {
  609.             m_vecTossVelocity = vecToss;
  610.  
  611.             // throw a hand grenade
  612.             m_fThrowGrenade = TRUE;
  613.             // don't check again for a while.
  614.             m_flNextGrenadeCheck = gpGlobals->time + 0.3; // 1/3 second.
  615.         }
  616.         else
  617.         {
  618.             // don't throw
  619.             m_fThrowGrenade = FALSE;
  620.             // don't check again for a while.
  621.             m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second.
  622.         }
  623.     }
  624.  
  625.    
  626.  
  627.     return m_fThrowGrenade;
  628. }
  629.  
  630.  
  631. //=========================================================
  632. // TraceAttack - make sure we're not taking it in the helmet
  633. //=========================================================
  634. void CHGrunt :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType)
  635. {
  636.     // check for helmet shot
  637.     if (ptr->iHitgroup == 11)
  638.     {
  639.         // make sure we're wearing one
  640.         if (GetBodygroup( 1 ) == HEAD_GRUNT && (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_BLAST | DMG_CLUB)))
  641.         {
  642.             // absorb damage
  643.             flDamage -= 20;
  644.             if (flDamage <= 0)
  645.             {
  646.                 UTIL_Ricochet( ptr->vecEndPos, 1.0 );
  647.                 flDamage = 0.01;
  648.             }
  649.         }
  650.         // it's head shot anyways
  651.         ptr->iHitgroup = HITGROUP_HEAD;
  652.     }
  653.     CSquadMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType );
  654. }
  655.  
  656.  
  657. //=========================================================
  658. // TakeDamage - overridden for the grunt because the grunt
  659. // needs to forget that he is in cover if he's hurt. (Obviously
  660. // not in a safe place anymore).
  661. //=========================================================
  662. int CHGrunt :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
  663. {
  664.     // make sure friends talk about it if player hurts talkmonsters...
  665.     int ret = CSquadMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType);
  666.     if ( !IsAlive() || pev->deadflag == DEAD_DYING )
  667.         return ret;
  668.  
  669.     if ( m_MonsterState != MONSTERSTATE_PRONE && (pevAttacker->flags & FL_CLIENT) )
  670.     {
  671.         m_flPlayerDamage += flDamage;
  672.  
  673.         // This is a heurstic to determine if the player intended to harm me
  674.         // If I have an enemy, we can't establish intent (may just be crossfire)
  675.         if ( m_hEnemy == NULL )
  676.         {
  677.             // If the player was facing directly at me, or I'm already suspicious, get mad
  678.             if ( (m_afMemory & bits_MEMORY_SUSPICIOUS) || IsFacing( pevAttacker, pev->origin ) )
  679.             {
  680.                 // Alright, now I'm pissed!
  681.                 PlaySentence( "HG_MAD", 4, VOL_NORM, ATTN_NORM );
  682.  
  683.                 Remember( bits_MEMORY_PROVOKED );
  684.                 StopFollowing( TRUE );
  685.             }
  686.             else
  687.             {
  688.                 // Hey, be careful with that
  689.                 PlaySentence( "HG_SHOT", 4, VOL_NORM, ATTN_NORM );
  690.                 Remember( bits_MEMORY_SUSPICIOUS );
  691.             }
  692.         }
  693.         else if ( !(m_hEnemy->IsPlayer()) && pev->deadflag == DEAD_NO )
  694.         {
  695.             PlaySentence( "HG_SHOT", 4, VOL_NORM, ATTN_NORM );
  696.         }
  697.     }
  698.  
  699.     return ret;
  700.     /*Forget( bits_MEMORY_INCOVER );
  701.  
  702.     return CSquadMonster :: TakeDamage ( pevInflictor, pevAttacker, flDamage, bitsDamageType );*/
  703. }
  704.  
  705. //=========================================================
  706. // SetYawSpeed - allows each sequence to have a different
  707. // turn rate associated with it.
  708. //=========================================================
  709. void CHGrunt :: SetYawSpeed ( void )
  710. {
  711.     int ys;
  712.  
  713.     switch ( m_Activity )
  714.     {
  715.     case ACT_IDLE: 
  716.         ys = 150;      
  717.         break;
  718.     case ACT_RUN:  
  719.         ys = 150;  
  720.         break;
  721.     case ACT_WALK: 
  722.         ys = 180;      
  723.         break;
  724.     case ACT_RANGE_ATTACK1:
  725.         ys = 120;  
  726.         break;
  727.     case ACT_RANGE_ATTACK2:
  728.         ys = 120;  
  729.         break;
  730.     case ACT_MELEE_ATTACK1:
  731.         ys = 120;  
  732.         break;
  733.     case ACT_MELEE_ATTACK2:
  734.         ys = 120;  
  735.         break;
  736.     case ACT_TURN_LEFT:
  737.     case ACT_TURN_RIGHT:   
  738.         ys = 180;
  739.         break;
  740.     case ACT_GLIDE:
  741.     case ACT_FLY:
  742.         ys = 30;
  743.         break;
  744.     default:
  745.         ys = 90;
  746.         break;
  747.     }
  748.  
  749.     pev->yaw_speed = ys;
  750. }
  751.  
  752. void CHGrunt :: IdleSound( void )
  753. {
  754.     if (FOkToSpeak() && (g_fGruntQuestion || RANDOM_LONG(0,1)))
  755.     {
  756.         if (!g_fGruntQuestion)
  757.         {
  758.             // ask question or make statement
  759.             switch (RANDOM_LONG(0,2))
  760.             {
  761.             case 0: // check in
  762.                 SENTENCEG_PlayRndSz(ENT(pev), "HG_CHECKS", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
  763.                 g_fGruntQuestion = 1;
  764.                 break;
  765.             case 1: // question
  766.                 SENTENCEG_PlayRndSz(ENT(pev), "HG_QUESTS", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
  767.                 g_fGruntQuestion = 2;
  768.                 break;
  769.             case 2: // statement
  770.                 SENTENCEG_PlayRndSz(ENT(pev), "HG_IDLES", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
  771.                 break;
  772.             }
  773.         }
  774.         else
  775.         {
  776.             switch (g_fGruntQuestion)
  777.             {
  778.             case 1: // check in
  779.                 SENTENCEG_PlayRndSz(ENT(pev), "HG_CLEARS", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
  780.                 break;
  781.             case 2: // question
  782.                 SENTENCEG_PlayRndSz(ENT(pev), "HG_ANSWERS", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch);
  783.                 break;
  784.             }
  785.             g_fGruntQuestion = 0;
  786.         }
  787.         JustSpoke();
  788.     }
  789. }
  790.  
  791. //=========================================================
  792. // CheckAmmo - overridden for the grunt because he actually
  793. // uses ammo! (base class doesn't)
  794. //=========================================================
  795. void CHGrunt :: CheckAmmo ( void )
  796. {
  797.     if ( m_cAmmoLoaded <= 0 )
  798.     {
  799.         SetConditions(bits_COND_NO_AMMO_LOADED);
  800.     }
  801. }
  802.  
  803. //=========================================================
  804. // Classify - indicates this monster's place in the
  805. // relationship table.
  806. //=========================================================
  807. int CHGrunt :: Classify ( void )
  808. {
  809.     return  CLASS_PLAYER_ALLY;
  810. }
  811.  
  812. //=========================================================
  813. //=========================================================
  814. CBaseEntity *CHGrunt :: Kick( void )
  815. {
  816.     TraceResult tr;
  817.  
  818.     UTIL_MakeVectors( pev->angles );
  819.     Vector vecStart = pev->origin;
  820.     vecStart.z += pev->size.z * 0.5;
  821.     Vector vecEnd = vecStart + (gpGlobals->v_forward * 70);
  822.  
  823.     UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr );
  824.    
  825.     if ( tr.pHit )
  826.     {
  827.         CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit );
  828.         return pEntity;
  829.     }
  830.  
  831.     return NULL;
  832. }
  833.  
  834. //=========================================================
  835. // GetGunPosition   return the end of the barrel
  836. //=========================================================
  837.  
  838. Vector CHGrunt :: GetGunPosition( )
  839. {
  840.     if (m_fStanding )
  841.     {
  842.         return pev->origin + Vector( 0, 0, 60 );
  843.     }
  844.     else
  845.     {
  846.         return pev->origin + Vector( 0, 0, 48 );
  847.     }
  848. }
  849.  
  850. //=========================================================
  851. // Shoot
  852. //=========================================================
  853. void CHGrunt :: Shoot ( void )
  854. {
  855.     if (m_hEnemy == NULL)
  856.     {
  857.         return;
  858.     }
  859.  
  860.     Vector vecShootOrigin = GetGunPosition();
  861.     Vector vecShootDir = ShootAtEnemy( vecShootOrigin );
  862.  
  863.     UTIL_MakeVectors ( pev->angles );
  864.  
  865.     Vector  vecShellVelocity = gpGlobals->v_right * RANDOM_FLOAT(40,90) + gpGlobals->v_up * RANDOM_FLOAT(75,200) + gpGlobals->v_forward * RANDOM_FLOAT(-40, 40);
  866.     EjectBrass ( vecShootOrigin - vecShootDir * 24, vecShellVelocity, pev->angles.y, m_iBrassShell, TE_BOUNCE_SHELL);
  867.     FireBullets(1, vecShootOrigin, vecShootDir, VECTOR_CONE_10DEGREES, 2048, BULLET_MONSTER_MP5 ); // shoot +-5 degrees
  868.  
  869.     pev->effects |= EF_MUZZLEFLASH;
  870.    
  871.     m_cAmmoLoaded--;// take away a bullet!
  872.  
  873.     Vector angDir = UTIL_VecToAngles( vecShootDir );
  874.     SetBlending( 0, angDir.x );
  875. }
  876.  
  877. //=========================================================
  878. // Shoot
  879. //=========================================================
  880. void CHGrunt :: Shotgun ( void )
  881. {
  882.     if (m_hEnemy == NULL)
  883.     {
  884.         return;
  885.     }
  886.  
  887.     Vector vecShootOrigin = GetGunPosition();
  888.     Vector vecShootDir = ShootAtEnemy( vecShootOrigin );
  889.  
  890.     UTIL_MakeVectors ( pev->angles );
  891.  
  892.     Vector  vecShellVelocity = gpGlobals->v_right * RANDOM_FLOAT(40,90) + gpGlobals->v_up * RANDOM_FLOAT(75,200) + gpGlobals->v_forward * RANDOM_FLOAT(-40, 40);
  893.     EjectBrass ( vecShootOrigin - vecShootDir * 24, vecShellVelocity, pev->angles.y, m_iShotgunShell, TE_BOUNCE_SHOTSHELL);
  894.     FireBullets(gSkillData.hgruntShotgunPellets, vecShootOrigin, vecShootDir, VECTOR_CONE_15DEGREES, 2048, BULLET_PLAYER_BUCKSHOT, 0 ); // shoot +-7.5 degrees
  895.  
  896.     pev->effects |= EF_MUZZLEFLASH;
  897.    
  898.     m_cAmmoLoaded--;// take away a bullet!
  899.  
  900.     Vector angDir = UTIL_VecToAngles( vecShootDir );
  901.     SetBlending( 0, angDir.x );
  902. }
  903.  
  904. //=========================================================
  905. // HandleAnimEvent - catches the monster-specific messages
  906. // that occur when tagged animation frames are played.
  907. //=========================================================
  908. void CHGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent )
  909. {
  910.     Vector  vecShootDir;
  911.     Vector  vecShootOrigin;
  912.  
  913.     switch( pEvent->event )
  914.     {
  915.         case HGRUNT_AE_DROP_GUN:
  916.             {
  917.             Vector  vecGunPos;
  918.             Vector  vecGunAngles;
  919.  
  920.             GetAttachment( 0, vecGunPos, vecGunAngles );
  921.  
  922.             // switch to body group with no gun.
  923.             SetBodygroup( GUN_GROUP, GUN_NONE );
  924.  
  925.             // now spawn a gun.
  926.             if (FBitSet( pev->weapons, HGRUNT_SHOTGUN ))
  927.             {
  928.                  DropItem( "weapon_shotgun", vecGunPos, vecGunAngles );
  929.             }
  930.             else
  931.             {
  932.                  DropItem( "weapon_9mmAR", vecGunPos, vecGunAngles );
  933.             }
  934.             if (FBitSet( pev->weapons, HGRUNT_GRENADELAUNCHER ))
  935.             {
  936.                 DropItem( "ammo_ARgrenades", BodyTarget( pev->origin ), vecGunAngles );
  937.             }
  938.  
  939.             }
  940.             break;
  941.  
  942.         case HGRUNT_AE_RELOAD:
  943.             EMIT_SOUND( ENT(pev), CHAN_WEAPON, "hgrunt/gr_reload1.wav", 1, ATTN_NORM );
  944.             m_cAmmoLoaded = m_cClipSize;
  945.             ClearConditions(bits_COND_NO_AMMO_LOADED);
  946.             break;
  947.  
  948.         case HGRUNT_AE_GREN_TOSS:
  949.         {
  950.             UTIL_MakeVectors( pev->angles );
  951.             // CGrenade::ShootTimed( pev, pev->origin + gpGlobals->v_forward * 34 + Vector (0, 0, 32), m_vecTossVelocity, 3.5 );
  952.             CGrenade::ShootTimed( pev, GetGunPosition(), m_vecTossVelocity, 3.5 );
  953.  
  954.             m_fThrowGrenade = FALSE;
  955.             m_flNextGrenadeCheck = gpGlobals->time + 6;// wait six seconds before even looking again to see if a grenade can be thrown.
  956.             // !!!LATER - when in a group, only try to throw grenade if ordered.
  957.         }
  958.         break;
  959.  
  960.         case HGRUNT_AE_GREN_LAUNCH:
  961.         {
  962.             EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/glauncher.wav", 0.8, ATTN_NORM);
  963.             CGrenade::ShootContact( pev, GetGunPosition(), m_vecTossVelocity );
  964.             m_fThrowGrenade = FALSE;
  965.             if (g_iSkillLevel == SKILL_HARD)
  966.                 m_flNextGrenadeCheck = gpGlobals->time + RANDOM_FLOAT( 2, 5 );// wait a random amount of time before shooting again
  967.             else
  968.                 m_flNextGrenadeCheck = gpGlobals->time + 6;// wait six seconds before even looking again to see if a grenade can be thrown.
  969.         }
  970.         break;
  971.  
  972.         case HGRUNT_AE_GREN_DROP:
  973.         {
  974.             UTIL_MakeVectors( pev->angles );
  975.             CGrenade::ShootTimed( pev, pev->origin + gpGlobals->v_forward * 17 - gpGlobals->v_right * 27 + gpGlobals->v_up * 6, g_vecZero, 3 );
  976.         }
  977.         break;
  978.  
  979.         case HGRUNT_AE_BURST1:
  980.         {
  981.             if ( FBitSet( pev->weapons, HGRUNT_9MMAR ))
  982.             {
  983.                 Shoot();
  984.  
  985.                 // the first round of the three round burst plays the sound and puts a sound in the world sound list.
  986.                 if ( RANDOM_LONG(0,1) )
  987.                 {
  988.                     EMIT_SOUND( ENT(pev), CHAN_WEAPON, "hgrunt/gr_mgun1.wav", 1, ATTN_NORM );
  989.                 }
  990.                 else
  991.                 {
  992.                     EMIT_SOUND( ENT(pev), CHAN_WEAPON, "hgrunt/gr_mgun2.wav", 1, ATTN_NORM );
  993.                 }
  994.             }
  995.             else
  996.             {
  997.                 Shotgun( );
  998.  
  999.                 EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/sbarrel1.wav", 1, ATTN_NORM );
  1000.             }
  1001.        
  1002.             CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 384, 0.3 );
  1003.         }
  1004.         break;
  1005.  
  1006.         case HGRUNT_AE_BURST2:
  1007.         case HGRUNT_AE_BURST3:
  1008.             Shoot();
  1009.             break;
  1010.  
  1011.         case HGRUNT_AE_KICK:
  1012.         {
  1013.             CBaseEntity *pHurt = Kick();
  1014.  
  1015.             if ( pHurt )
  1016.             {
  1017.                 // SOUND HERE!
  1018.                 UTIL_MakeVectors( pev->angles );
  1019.                 pHurt->pev->punchangle.x = 15;
  1020.                 pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_forward * 100 + gpGlobals->v_up * 50;
  1021.                 pHurt->TakeDamage( pev, pev, gSkillData.hgruntDmgKick, DMG_CLUB );
  1022.             }
  1023.         }
  1024.         break;
  1025.  
  1026.         case HGRUNT_AE_CAUGHT_ENEMY:
  1027.         {
  1028.             if ( FOkToSpeak() )
  1029.             {
  1030.                 SENTENCEG_PlayRndSz(ENT(pev), "HG_ENEMY", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
  1031.                  JustSpoke();
  1032.             }
  1033.  
  1034.         }
  1035.  
  1036.         default:
  1037.             CSquadMonster::HandleAnimEvent( pEvent );
  1038.             break;
  1039.     }
  1040. }
  1041.  
  1042. //=========================================================
  1043. // Spawn
  1044. //=========================================================
  1045. void CHGrunt :: Spawn()
  1046. {
  1047.     Precache( );
  1048.  
  1049.     SET_MODEL(ENT(pev), "models/hgrunt.mdl");
  1050.     UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
  1051.  
  1052.     pev->solid          = SOLID_SLIDEBOX;
  1053.     pev->movetype       = MOVETYPE_STEP;
  1054.     m_bloodColor        = BLOOD_COLOR_RED;
  1055.     pev->effects        = 0;
  1056.     pev->health         = gSkillData.hgruntHealth;
  1057.     m_flFieldOfView     = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result )
  1058.     m_MonsterState      = MONSTERSTATE_NONE;
  1059.     m_flNextGrenadeCheck = gpGlobals->time + 1;
  1060.     m_flNextPainTime    = gpGlobals->time;
  1061.     m_iSentence         = HGRUNT_SENT_NONE;
  1062.  
  1063.     m_afCapability      = bits_CAP_SQUAD | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;
  1064.  
  1065.     m_fEnemyEluded      = FALSE;
  1066.     m_fFirstEncounter   = TRUE;// this is true when the grunt spawns, because he hasn't encountered an enemy yet.
  1067.  
  1068.     m_HackedGunPos = Vector ( 0, 0, 55 );
  1069.  
  1070.     if (pev->weapons == 0)
  1071.     {
  1072.         // initialize to original values
  1073.         pev->weapons = HGRUNT_9MMAR | HGRUNT_HANDGRENADE;
  1074.         // pev->weapons = HGRUNT_SHOTGUN;
  1075.         // pev->weapons = HGRUNT_9MMAR | HGRUNT_GRENADELAUNCHER;
  1076.     }
  1077.  
  1078.     if (FBitSet( pev->weapons, HGRUNT_SHOTGUN ))
  1079.     {
  1080.         SetBodygroup( GUN_GROUP, GUN_SHOTGUN );
  1081.         m_cClipSize     = 8;
  1082.     }
  1083.     else
  1084.     {
  1085.         m_cClipSize     = GRUNT_CLIP_SIZE;
  1086.     }
  1087.     m_cAmmoLoaded       = m_cClipSize;
  1088.  
  1089.     if (RANDOM_LONG( 0, 99 ) < 80)
  1090.         pev->skin = 0;  // light skin
  1091.     else
  1092.         pev->skin = 1;  // dark skin
  1093.  
  1094.     if (FBitSet( pev->weapons, HGRUNT_SHOTGUN ))
  1095.     {
  1096.         SetBodygroup( HEAD_GROUP, HEAD_SHOTGUN);
  1097.     }
  1098.     else if (FBitSet( pev->weapons, HGRUNT_GRENADELAUNCHER ))
  1099.     {
  1100.         SetBodygroup( HEAD_GROUP, HEAD_M203 );
  1101.         pev->skin = 1; // alway dark skin
  1102.     }
  1103.  
  1104.     CTalkMonster::g_talkWaitTime = 0;
  1105.     SetUse( &CTalkMonster::FollowerUse );
  1106.  
  1107.     MonsterInit();
  1108. }
  1109.  
  1110. //=========================================================
  1111. // Precache - precaches all resources this monster needs
  1112. //=========================================================
  1113. void CHGrunt :: Precache()
  1114. {
  1115.     PRECACHE_MODEL("models/hgrunt.mdl");
  1116.  
  1117.     PRECACHE_SOUND( "hgrunt/gr_mgun1.wav" );
  1118.     PRECACHE_SOUND( "hgrunt/gr_mgun2.wav" );
  1119.    
  1120.     PRECACHE_SOUND( "hgrunt/death1.wav" );
  1121.     PRECACHE_SOUND( "hgrunt/death2.wav" );
  1122.     PRECACHE_SOUND( "hgrunt/death3.wav" );
  1123.     PRECACHE_SOUND( "hgrunt/death4.wav" );
  1124.     PRECACHE_SOUND( "hgrunt/death5.wav" );
  1125.     PRECACHE_SOUND( "hgrunt/death6.wav" );
  1126.  
  1127.     PRECACHE_SOUND( "hgrunt/pain1.wav" );
  1128.     PRECACHE_SOUND( "hgrunt/pain2.wav" );
  1129.     PRECACHE_SOUND( "hgrunt/pain3.wav" );
  1130.     PRECACHE_SOUND( "hgrunt/pain4.wav" );
  1131.     PRECACHE_SOUND( "hgrunt/pain5.wav" );
  1132.     PRECACHE_SOUND( "hgrunt/pain6.wav" );
  1133.  
  1134.     PRECACHE_SOUND( "hgrunt/gr_reload1.wav" );
  1135.  
  1136.     PRECACHE_SOUND( "weapons/glauncher.wav" );
  1137.  
  1138.     PRECACHE_SOUND( "weapons/sbarrel1.wav" );
  1139.  
  1140.     PRECACHE_SOUND("zombie/claw_miss2.wav");// because we use the basemonster SWIPE animation event
  1141.  
  1142.     TalkInit();
  1143.     CTalkMonster::Precache();
  1144.  
  1145.     // get voice pitch
  1146.     if (RANDOM_LONG(0,1))
  1147.         m_voicePitch = 109 + RANDOM_LONG(0,7);
  1148.     else
  1149.         m_voicePitch = 100;
  1150.  
  1151.     m_iBrassShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell
  1152.     m_iShotgunShell = PRECACHE_MODEL ("models/shotgunshell.mdl");
  1153. }  
  1154.  
  1155. // Init talk data
  1156. void CHGrunt :: TalkInit()
  1157. {
  1158.     CTalkMonster::TalkInit();
  1159.  
  1160.     // Human Grunt (ALLY)
  1161.  
  1162.     // -------
  1163.     // Note: (The following HG_ is in the sentence.txt (CUSTOM MADE)
  1164.     // So u need to make them by your self!
  1165.     // -------
  1166.  
  1167.     m_szGrp[TL_ANSWER]  =   NULL;
  1168.     m_szGrp[TL_QUESTION] =  NULL;
  1169.     m_szGrp[TL_IDLE] =      "HG_IDLES";
  1170.     m_szGrp[TL_STARE] = "HG_STARE";
  1171.     m_szGrp[TL_USE] =       "HG_USE";
  1172.     m_szGrp[TL_UNUSE] = "HG_UNUSE";
  1173.     m_szGrp[TL_STOP] =      "HG_STOP";
  1174.  
  1175.     m_szGrp[TL_NOSHOOT] =   NULL;
  1176.     m_szGrp[TL_HELLO] = "HG_HELLO";
  1177.  
  1178.     m_szGrp[TL_PLHURT1] =   NULL;
  1179.     m_szGrp[TL_PLHURT2] =   NULL;
  1180.     m_szGrp[TL_PLHURT3] =   NULL;
  1181.  
  1182.     m_szGrp[TL_PHELLO] =    NULL;
  1183.     m_szGrp[TL_PIDLE] = NULL;
  1184.     m_szGrp[TL_PQUESTION] = NULL;
  1185.  
  1186.     m_szGrp[TL_SMELL] = NULL;
  1187.    
  1188.     m_szGrp[TL_WOUND] = NULL;
  1189.     m_szGrp[TL_MORTAL] =    NULL;
  1190.  
  1191.     // get voice for head
  1192.     m_voicePitch = 100;
  1193. }
  1194.  
  1195. //=========================================================
  1196. // start task
  1197. //=========================================================
  1198. void CHGrunt :: StartTask ( Task_t *pTask )
  1199. {
  1200.     m_iTaskStatus = TASKSTATUS_RUNNING;
  1201.  
  1202.     switch ( pTask->iTask )
  1203.     {
  1204.     case TASK_GRUNT_CHECK_FIRE:
  1205.         if ( !NoFriendlyFire() )
  1206.         {
  1207.             SetConditions( bits_COND_GRUNT_NOFIRE );
  1208.         }
  1209.         TaskComplete();
  1210.         break;
  1211.  
  1212.     case TASK_GRUNT_SPEAK_SENTENCE:
  1213.         SpeakSentence();
  1214.         TaskComplete();
  1215.         break;
  1216.    
  1217.     case TASK_WALK_PATH:
  1218.     case TASK_RUN_PATH:
  1219.         // grunt no longer assumes he is covered if he moves
  1220.         Forget( bits_MEMORY_INCOVER );
  1221.         CSquadMonster ::StartTask( pTask );
  1222.         break;
  1223.  
  1224.     case TASK_RELOAD:
  1225.         m_IdealActivity = ACT_RELOAD;
  1226.         break;
  1227.  
  1228.     case TASK_GRUNT_FACE_TOSS_DIR:
  1229.         break;
  1230.  
  1231.     case TASK_FACE_IDEAL:
  1232.     case TASK_FACE_ENEMY:
  1233.         CSquadMonster :: StartTask( pTask );
  1234.         if (pev->movetype == MOVETYPE_FLY)
  1235.         {
  1236.             m_IdealActivity = ACT_GLIDE;
  1237.         }
  1238.         break;
  1239.  
  1240.     default:
  1241.         CSquadMonster :: StartTask( pTask );
  1242.         break;
  1243.     }
  1244. }
  1245.  
  1246. //=========================================================
  1247. // RunTask
  1248. //=========================================================
  1249. void CHGrunt :: RunTask ( Task_t *pTask )
  1250. {
  1251.     switch ( pTask->iTask )
  1252.     {
  1253.     case TASK_GRUNT_FACE_TOSS_DIR:
  1254.         {
  1255.             // project a point along the toss vector and turn to face that point.
  1256.             MakeIdealYaw( pev->origin + m_vecTossVelocity * 64 );
  1257.             ChangeYaw( pev->yaw_speed );
  1258.  
  1259.             if ( FacingIdeal() )
  1260.             {
  1261.                 m_iTaskStatus = TASKSTATUS_COMPLETE;
  1262.             }
  1263.             break;
  1264.         }
  1265.     default:
  1266.         {
  1267.             CSquadMonster :: RunTask( pTask );
  1268.             break;
  1269.         }
  1270.     }
  1271. }
  1272.  
  1273. //=========================================================
  1274. // PainSound
  1275. //=========================================================
  1276. void CHGrunt :: PainSound ( void )
  1277. {
  1278.     if ( gpGlobals->time > m_flNextPainTime )
  1279.     {
  1280. #if 0
  1281.         if ( RANDOM_LONG(0,99) < 5 )
  1282.         {
  1283.             // pain sentences are rare
  1284.             if (FOkToSpeak())
  1285.             {
  1286.                 SENTENCEG_PlayRndSz(ENT(pev), "HG_PAIN", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, PITCH_NORM);
  1287.                 JustSpoke();
  1288.                 return;
  1289.             }
  1290.         }
  1291. #endif
  1292.         switch ( RANDOM_LONG(0,6) )
  1293.         {
  1294.         case 0:
  1295.             EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/pain1.wav", 1, ATTN_NORM );  
  1296.             break;
  1297.         case 1:
  1298.             EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/pain4.wav", 1, ATTN_NORM );  
  1299.             break;
  1300.         case 2:
  1301.             EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/pain5.wav", 1, ATTN_NORM );  
  1302.             break;
  1303.         case 3:
  1304.             EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/pain2.wav", 1, ATTN_NORM );  
  1305.             break;
  1306.         case 4:
  1307.             EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/pain3.wav", 1, ATTN_NORM );  
  1308.             break;
  1309.         case 5:
  1310.             EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/pain6.wav", 1, ATTN_NORM );  
  1311.             break;
  1312.         }
  1313.  
  1314.         m_flNextPainTime = gpGlobals->time + 1;
  1315.     }
  1316. }
  1317.  
  1318. //=========================================================
  1319. // DeathSound
  1320. //=========================================================
  1321. void CHGrunt :: DeathSound ( void )
  1322. {
  1323.     switch ( RANDOM_LONG(0,2) )
  1324.     {
  1325.     case 0:
  1326.         EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/death1.wav", 1, ATTN_IDLE ); 
  1327.         break;
  1328.     case 1:
  1329.         EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/death2.wav", 1, ATTN_IDLE ); 
  1330.         break;
  1331.     case 2:
  1332.         EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/death3.wav", 1, ATTN_IDLE ); 
  1333.         break;
  1334.     case 3:
  1335.         EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/death4.wav", 1, ATTN_IDLE ); 
  1336.         break;
  1337.     case 4:
  1338.         EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/death5.wav", 1, ATTN_IDLE ); 
  1339.         break;
  1340.     case 5:
  1341.         EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/death6.wav", 1, ATTN_IDLE ); 
  1342.         break;
  1343.     }
  1344. }
  1345.  
  1346. //=========================================================
  1347. // AI Schedules Specific to this monster
  1348. //=========================================================
  1349.  
  1350. //=========================================================
  1351. // GruntFail
  1352. //=========================================================
  1353. Task_t  tlGruntFail[] =
  1354. {
  1355.     { TASK_STOP_MOVING,         0               },
  1356.     { TASK_SET_ACTIVITY,        (float)ACT_IDLE },
  1357.     { TASK_WAIT,                (float)2        },
  1358.     { TASK_WAIT_PVS,            (float)0        },
  1359. };
  1360.  
  1361. Schedule_t  slGruntFail[] =
  1362. {
  1363.     {
  1364.         tlGruntFail,
  1365.         ARRAYSIZE ( tlGruntFail ),
  1366.         bits_COND_CAN_RANGE_ATTACK1 |
  1367.         bits_COND_CAN_RANGE_ATTACK2 |
  1368.         bits_COND_CAN_MELEE_ATTACK1 |
  1369.         bits_COND_CAN_MELEE_ATTACK2,
  1370.         0,
  1371.         "Grunt Fail"
  1372.     },
  1373. };
  1374.  
  1375. //=========================================================
  1376. // Grunt Combat Fail
  1377. //=========================================================
  1378. Task_t  tlGruntCombatFail[] =
  1379. {
  1380.     { TASK_STOP_MOVING,         0               },
  1381.     { TASK_SET_ACTIVITY,        (float)ACT_IDLE },
  1382.     { TASK_WAIT_FACE_ENEMY,     (float)2        },
  1383.     { TASK_WAIT_PVS,            (float)0        },
  1384. };
  1385.  
  1386. Schedule_t  slGruntCombatFail[] =
  1387. {
  1388.     {
  1389.         tlGruntCombatFail,
  1390.         ARRAYSIZE ( tlGruntCombatFail ),
  1391.         bits_COND_CAN_RANGE_ATTACK1 |
  1392.         bits_COND_CAN_RANGE_ATTACK2,
  1393.         0,
  1394.         "Grunt Combat Fail"
  1395.     },
  1396. };
  1397.  
  1398. //=========================================================
  1399. // Victory dance!
  1400. //=========================================================
  1401. Task_t  tlGruntVictoryDance[] =
  1402. {
  1403.     { TASK_STOP_MOVING,                     (float)0                    },
  1404.     { TASK_FACE_ENEMY,                      (float)0                    },
  1405.     { TASK_WAIT,                            (float)1.5                  },
  1406.     { TASK_GET_PATH_TO_ENEMY_CORPSE,        (float)0                    },
  1407.     { TASK_WALK_PATH,                       (float)0                    },
  1408.     { TASK_WAIT_FOR_MOVEMENT,               (float)0                    },
  1409.     { TASK_FACE_ENEMY,                      (float)0                    },
  1410.     { TASK_PLAY_SEQUENCE,                   (float)ACT_VICTORY_DANCE    },
  1411. };
  1412.  
  1413. Schedule_t  slGruntVictoryDance[] =
  1414. {
  1415.     {
  1416.         tlGruntVictoryDance,
  1417.         ARRAYSIZE ( tlGruntVictoryDance ),
  1418.         bits_COND_NEW_ENEMY     |
  1419.         bits_COND_LIGHT_DAMAGE  |
  1420.         bits_COND_HEAVY_DAMAGE,
  1421.         0,
  1422.         "GruntVictoryDance"
  1423.     },
  1424. };
  1425.  
  1426. //=========================================================
  1427. // Establish line of fire - move to a position that allows
  1428. // the grunt to attack.
  1429. //=========================================================
  1430. Task_t tlGruntEstablishLineOfFire[] =
  1431. {
  1432.     { TASK_SET_FAIL_SCHEDULE,   (float)SCHED_GRUNT_ELOF_FAIL    },
  1433.     { TASK_GET_PATH_TO_ENEMY,   (float)0                        },
  1434.     { TASK_GRUNT_SPEAK_SENTENCE,(float)0                        },
  1435.     { TASK_RUN_PATH,            (float)0                        },
  1436.     { TASK_WAIT_FOR_MOVEMENT,   (float)0                        },
  1437. };
  1438.  
  1439. Schedule_t slGruntEstablishLineOfFire[] =
  1440. {
  1441.     {
  1442.         tlGruntEstablishLineOfFire,
  1443.         ARRAYSIZE ( tlGruntEstablishLineOfFire ),
  1444.         bits_COND_NEW_ENEMY         |
  1445.         bits_COND_ENEMY_DEAD        |
  1446.         bits_COND_CAN_RANGE_ATTACK1 |
  1447.         bits_COND_CAN_MELEE_ATTACK1 |
  1448.         bits_COND_CAN_RANGE_ATTACK2 |
  1449.         bits_COND_CAN_MELEE_ATTACK2 |
  1450.         bits_COND_HEAR_SOUND,
  1451.        
  1452.         bits_SOUND_DANGER,
  1453.         "GruntEstablishLineOfFire"
  1454.     },
  1455. };
  1456.  
  1457. //=========================================================
  1458. // GruntFoundEnemy - grunt established sight with an enemy
  1459. // that was hiding from the squad.
  1460. //=========================================================
  1461. Task_t  tlGruntFoundEnemy[] =
  1462. {
  1463.     { TASK_STOP_MOVING,             0                           },
  1464.     { TASK_FACE_ENEMY,              (float)0                    },
  1465.     { TASK_PLAY_SEQUENCE_FACE_ENEMY,(float)ACT_SIGNAL1          },
  1466. };
  1467.  
  1468. Schedule_t  slGruntFoundEnemy[] =
  1469. {
  1470.     {
  1471.         tlGruntFoundEnemy,
  1472.         ARRAYSIZE ( tlGruntFoundEnemy ),
  1473.         bits_COND_HEAR_SOUND,
  1474.        
  1475.         bits_SOUND_DANGER,
  1476.         "GruntFoundEnemy"
  1477.     },
  1478. };
  1479.  
  1480. //=========================================================
  1481. // GruntCombatFace Schedule
  1482. //=========================================================
  1483. Task_t  tlGruntCombatFace1[] =
  1484. {
  1485.     { TASK_STOP_MOVING,             0                           },
  1486.     { TASK_SET_ACTIVITY,            (float)ACT_IDLE             },
  1487.     { TASK_FACE_ENEMY,              (float)0                    },
  1488.     { TASK_WAIT,                    (float)1.5                  },
  1489.     { TASK_SET_SCHEDULE,            (float)SCHED_GRUNT_SWEEP    },
  1490. };
  1491.  
  1492. Schedule_t  slGruntCombatFace[] =
  1493. {
  1494.     {
  1495.         tlGruntCombatFace1,
  1496.         ARRAYSIZE ( tlGruntCombatFace1 ),
  1497.         bits_COND_NEW_ENEMY             |
  1498.         bits_COND_ENEMY_DEAD            |
  1499.         bits_COND_CAN_RANGE_ATTACK1     |
  1500.         bits_COND_CAN_RANGE_ATTACK2,
  1501.         0,
  1502.         "Combat Face"
  1503.     },
  1504. };
  1505.  
  1506. //=========================================================
  1507. // Suppressing fire - don't stop shooting until the clip is
  1508. // empty or grunt gets hurt.
  1509. //=========================================================
  1510. Task_t  tlGruntSignalSuppress[] =
  1511. {
  1512.     { TASK_STOP_MOVING,                 0                       },
  1513.     { TASK_FACE_IDEAL,                  (float)0                },
  1514.     { TASK_PLAY_SEQUENCE_FACE_ENEMY,    (float)ACT_SIGNAL2      },
  1515.     { TASK_FACE_ENEMY,                  (float)0                },
  1516.     { TASK_GRUNT_CHECK_FIRE,            (float)0                },
  1517.     { TASK_RANGE_ATTACK1,               (float)0                },
  1518.     { TASK_FACE_ENEMY,                  (float)0                },
  1519.     { TASK_GRUNT_CHECK_FIRE,            (float)0                },
  1520.     { TASK_RANGE_ATTACK1,               (float)0                },
  1521.     { TASK_FACE_ENEMY,                  (float)0                },
  1522.     { TASK_GRUNT_CHECK_FIRE,            (float)0                },
  1523.     { TASK_RANGE_ATTACK1,               (float)0                },
  1524.     { TASK_FACE_ENEMY,                  (float)0                },
  1525.     { TASK_GRUNT_CHECK_FIRE,            (float)0                },
  1526.     { TASK_RANGE_ATTACK1,               (float)0                },
  1527.     { TASK_FACE_ENEMY,                  (float)0                },
  1528.     { TASK_GRUNT_CHECK_FIRE,            (float)0                },
  1529.     { TASK_RANGE_ATTACK1,               (float)0                },
  1530. };
  1531.  
  1532. Schedule_t  slGruntSignalSuppress[] =
  1533. {
  1534.     {
  1535.         tlGruntSignalSuppress,
  1536.         ARRAYSIZE ( tlGruntSignalSuppress ),
  1537.         bits_COND_ENEMY_DEAD        |
  1538.         bits_COND_LIGHT_DAMAGE      |
  1539.         bits_COND_HEAVY_DAMAGE      |
  1540.         bits_COND_HEAR_SOUND        |
  1541.         bits_COND_GRUNT_NOFIRE      |
  1542.         bits_COND_NO_AMMO_LOADED,
  1543.  
  1544.         bits_SOUND_DANGER,
  1545.         "SignalSuppress"
  1546.     },
  1547. };
  1548.  
  1549. Task_t  tlGruntSuppress[] =
  1550. {
  1551.     { TASK_STOP_MOVING,         0                           },
  1552.     { TASK_FACE_ENEMY,          (float)0                    },
  1553.     { TASK_GRUNT_CHECK_FIRE,    (float)0                    },
  1554.     { TASK_RANGE_ATTACK1,       (float)0                    },
  1555.     { TASK_FACE_ENEMY,          (float)0                    },
  1556.     { TASK_GRUNT_CHECK_FIRE,    (float)0                    },
  1557.     { TASK_RANGE_ATTACK1,       (float)0                    },
  1558.     { TASK_FACE_ENEMY,          (float)0                    },
  1559.     { TASK_GRUNT_CHECK_FIRE,    (float)0                    },
  1560.     { TASK_RANGE_ATTACK1,       (float)0                    },
  1561.     { TASK_FACE_ENEMY,          (float)0                    },
  1562.     { TASK_GRUNT_CHECK_FIRE,    (float)0                    },
  1563.     { TASK_RANGE_ATTACK1,       (float)0                    },
  1564.     { TASK_FACE_ENEMY,          (float)0                    },
  1565.     { TASK_GRUNT_CHECK_FIRE,    (float)0                    },
  1566.     { TASK_RANGE_ATTACK1,       (float)0                    },
  1567. };
  1568.  
  1569. Schedule_t  slGruntSuppress[] =
  1570. {
  1571.     {
  1572.         tlGruntSuppress,
  1573.         ARRAYSIZE ( tlGruntSuppress ),
  1574.         bits_COND_ENEMY_DEAD        |
  1575.         bits_COND_LIGHT_DAMAGE      |
  1576.         bits_COND_HEAVY_DAMAGE      |
  1577.         bits_COND_HEAR_SOUND        |
  1578.         bits_COND_GRUNT_NOFIRE      |
  1579.         bits_COND_NO_AMMO_LOADED,
  1580.  
  1581.         bits_SOUND_DANGER,
  1582.         "Suppress"
  1583.     },
  1584. };
  1585.  
  1586. // FOLLOW PLAYER
  1587.  
  1588. Task_t  tlGruntFollow[] =
  1589. {
  1590.     { TASK_MOVE_TO_TARGET_RANGE,(float)128      }// Move within 128 of target ent (client)
  1591.     { TASK_SET_SCHEDULE,        (float)SCHED_TARGET_FACE },
  1592. };
  1593.  
  1594. Schedule_t  slGruntFollow[] =
  1595. {
  1596.     {
  1597.         tlGruntFollow,
  1598.         ARRAYSIZE ( tlGruntFollow ),
  1599.         bits_COND_NEW_ENEMY     |
  1600.         bits_COND_LIGHT_DAMAGE  |
  1601.         bits_COND_HEAVY_DAMAGE  |
  1602.         bits_COND_HEAR_SOUND |
  1603.         bits_COND_PROVOKED,
  1604.         bits_SOUND_DANGER,
  1605.         "Follow"
  1606.     },
  1607. };
  1608.  
  1609. //=========================================================
  1610. // grunt wait in cover - we don't allow danger or the ability
  1611. // to attack to break a grunt's run to cover schedule, but
  1612. // when a grunt is in cover, we do want them to attack if they can.
  1613. //=========================================================
  1614. Task_t  tlGruntWaitInCover[] =
  1615. {
  1616.     { TASK_STOP_MOVING,             (float)0                    },
  1617.     { TASK_SET_ACTIVITY,            (float)ACT_IDLE             },
  1618.     { TASK_WAIT_FACE_ENEMY,         (float)1                    },
  1619. };
  1620.  
  1621. Schedule_t  slGruntWaitInCover[] =
  1622. {
  1623.     {
  1624.         tlGruntWaitInCover,
  1625.         ARRAYSIZE ( tlGruntWaitInCover ),
  1626.         bits_COND_NEW_ENEMY         |
  1627.         bits_COND_HEAR_SOUND        |
  1628.         bits_COND_CAN_RANGE_ATTACK1 |
  1629.         bits_COND_CAN_RANGE_ATTACK2 |
  1630.         bits_COND_CAN_MELEE_ATTACK1 |
  1631.         bits_COND_CAN_MELEE_ATTACK2,
  1632.  
  1633.         bits_SOUND_DANGER,
  1634.         "GruntWaitInCover"
  1635.     },
  1636. };
  1637.  
  1638. //=========================================================
  1639. // run to cover.
  1640. // !!!BUGBUG - set a decent fail schedule here.
  1641. //=========================================================
  1642. Task_t  tlGruntTakeCover1[] =
  1643. {
  1644.     { TASK_STOP_MOVING,             (float)0                            },
  1645.     { TASK_SET_FAIL_SCHEDULE,       (float)SCHED_GRUNT_TAKECOVER_FAILED },
  1646.     { TASK_WAIT,                    (float)0.2                          },
  1647.     { TASK_FIND_COVER_FROM_ENEMY,   (float)0                            },
  1648.     { TASK_GRUNT_SPEAK_SENTENCE,    (float)0                            },
  1649.     { TASK_RUN_PATH,                (float)0                            },
  1650.     { TASK_WAIT_FOR_MOVEMENT,       (float)0                            },
  1651.     { TASK_REMEMBER,                (float)bits_MEMORY_INCOVER          },
  1652.     { TASK_SET_SCHEDULE,            (float)SCHED_GRUNT_WAIT_FACE_ENEMY  },
  1653. };
  1654.  
  1655. Schedule_t  slGruntTakeCover[] =
  1656. {
  1657.     {
  1658.         tlGruntTakeCover1,
  1659.         ARRAYSIZE ( tlGruntTakeCover1 ),
  1660.         0,
  1661.         0,
  1662.         "TakeCover"
  1663.     },
  1664. };
  1665.  
  1666. //=========================================================
  1667. // drop grenade then run to cover.
  1668. //=========================================================
  1669. Task_t  tlGruntGrenadeCover1[] =
  1670. {
  1671.     { TASK_STOP_MOVING,                     (float)0                            },
  1672.     { TASK_FIND_COVER_FROM_ENEMY,           (float)99                           },
  1673.     { TASK_FIND_FAR_NODE_COVER_FROM_ENEMY,  (float)384                          },
  1674.     { TASK_PLAY_SEQUENCE,                   (float)ACT_SPECIAL_ATTACK1          },
  1675.     { TASK_CLEAR_MOVE_WAIT,                 (float)0                            },
  1676.     { TASK_RUN_PATH,                        (float)0                            },
  1677.     { TASK_WAIT_FOR_MOVEMENT,               (float)0                            },
  1678.     { TASK_SET_SCHEDULE,                    (float)SCHED_GRUNT_WAIT_FACE_ENEMY  },
  1679. };
  1680.  
  1681. Schedule_t  slGruntGrenadeCover[] =
  1682. {
  1683.     {
  1684.         tlGruntGrenadeCover1,
  1685.         ARRAYSIZE ( tlGruntGrenadeCover1 ),
  1686.         0,
  1687.         0,
  1688.         "GrenadeCover"
  1689.     },
  1690. };
  1691.  
  1692.  
  1693. //=========================================================
  1694. // drop grenade then run to cover.
  1695. //=========================================================
  1696. Task_t  tlGruntTossGrenadeCover1[] =
  1697. {
  1698.     { TASK_FACE_ENEMY,                      (float)0                            },
  1699.     { TASK_RANGE_ATTACK2,                   (float)0                            },
  1700.     { TASK_SET_SCHEDULE,                    (float)SCHED_TAKE_COVER_FROM_ENEMY  },
  1701. };
  1702.  
  1703. Schedule_t  slGruntTossGrenadeCover[] =
  1704. {
  1705.     {
  1706.         tlGruntTossGrenadeCover1,
  1707.         ARRAYSIZE ( tlGruntTossGrenadeCover1 ),
  1708.         0,
  1709.         0,
  1710.         "TossGrenadeCover"
  1711.     },
  1712. };
  1713.  
  1714. //=========================================================
  1715. // hide from the loudest sound source (to run from grenade)
  1716. //=========================================================
  1717. Task_t  tlGruntTakeCoverFromBestSound[] =
  1718. {
  1719.     { TASK_SET_FAIL_SCHEDULE,           (float)SCHED_COWER          },// duck and cover if cannot move from explosion
  1720.     { TASK_STOP_MOVING,                 (float)0                    },
  1721.     { TASK_FIND_COVER_FROM_BEST_SOUND,  (float)0                    },
  1722.     { TASK_RUN_PATH,                    (float)0                    },
  1723.     { TASK_WAIT_FOR_MOVEMENT,           (float)0                    },
  1724.     { TASK_REMEMBER,                    (float)bits_MEMORY_INCOVER  },
  1725.     { TASK_TURN_LEFT,                   (float)179                  },
  1726. };
  1727.  
  1728. Schedule_t  slGruntTakeCoverFromBestSound[] =
  1729. {
  1730.     {
  1731.         tlGruntTakeCoverFromBestSound,
  1732.         ARRAYSIZE ( tlGruntTakeCoverFromBestSound ),
  1733.         0,
  1734.         0,
  1735.         "GruntTakeCoverFromBestSound"
  1736.     },
  1737. };
  1738.  
  1739. //=========================================================
  1740. // Grunt reload schedule
  1741. //=========================================================
  1742. Task_t  tlGruntHideReload[] =
  1743. {
  1744.     { TASK_STOP_MOVING,             (float)0                    },
  1745.     { TASK_SET_FAIL_SCHEDULE,       (float)SCHED_RELOAD         },
  1746.     { TASK_FIND_COVER_FROM_ENEMY,   (float)0                    },
  1747.     { TASK_RUN_PATH,                (float)0                    },
  1748.     { TASK_WAIT_FOR_MOVEMENT,       (float)0                    },
  1749.     { TASK_REMEMBER,                (float)bits_MEMORY_INCOVER  },
  1750.     { TASK_FACE_ENEMY,              (float)0                    },
  1751.     { TASK_PLAY_SEQUENCE,           (float)ACT_RELOAD           },
  1752. };
  1753.  
  1754. Schedule_t slGruntHideReload[] =
  1755. {
  1756.     {
  1757.         tlGruntHideReload,
  1758.         ARRAYSIZE ( tlGruntHideReload ),
  1759.         bits_COND_HEAVY_DAMAGE  |
  1760.         bits_COND_HEAR_SOUND,
  1761.  
  1762.         bits_SOUND_DANGER,
  1763.         "GruntHideReload"
  1764.     }
  1765. };
  1766.  
  1767. //=========================================================
  1768. // Do a turning sweep of the area
  1769. //=========================================================
  1770. Task_t  tlGruntSweep[] =
  1771. {
  1772.     { TASK_TURN_LEFT,           (float)179  },
  1773.     { TASK_WAIT,                (float)1    },
  1774.     { TASK_TURN_LEFT,           (float)179  },
  1775.     { TASK_WAIT,                (float)1    },
  1776. };
  1777.  
  1778. Schedule_t  slGruntSweep[] =
  1779. {
  1780.     {
  1781.         tlGruntSweep,
  1782.         ARRAYSIZE ( tlGruntSweep ),
  1783.        
  1784.         bits_COND_NEW_ENEMY     |
  1785.         bits_COND_LIGHT_DAMAGE  |
  1786.         bits_COND_HEAVY_DAMAGE  |
  1787.         bits_COND_CAN_RANGE_ATTACK1 |
  1788.         bits_COND_CAN_RANGE_ATTACK2 |
  1789.         bits_COND_HEAR_SOUND,
  1790.  
  1791.         bits_SOUND_WORLD        |// sound flags
  1792.         bits_SOUND_DANGER       |
  1793.         bits_SOUND_PLAYER,
  1794.  
  1795.         "Grunt Sweep"
  1796.     },
  1797. };
  1798.  
  1799. //=========================================================
  1800. // primary range attack. Overriden because base class stops attacking when the enemy is occluded.
  1801. // grunt's grenade toss requires the enemy be occluded.
  1802. //=========================================================
  1803. Task_t  tlGruntRangeAttack1A[] =
  1804. {
  1805.     { TASK_STOP_MOVING,         (float)0        },
  1806.     { TASK_PLAY_SEQUENCE_FACE_ENEMY,        (float)ACT_CROUCH },
  1807.     { TASK_GRUNT_CHECK_FIRE,    (float)0        },
  1808.     { TASK_RANGE_ATTACK1,       (float)0        },
  1809.     { TASK_FACE_ENEMY,          (float)0        },
  1810.     { TASK_GRUNT_CHECK_FIRE,    (float)0        },
  1811.     { TASK_RANGE_ATTACK1,       (float)0        },
  1812.     { TASK_FACE_ENEMY,          (float)0        },
  1813.     { TASK_GRUNT_CHECK_FIRE,    (float)0        },
  1814.     { TASK_RANGE_ATTACK1,       (float)0        },
  1815.     { TASK_FACE_ENEMY,          (float)0        },
  1816.     { TASK_GRUNT_CHECK_FIRE,    (float)0        },
  1817.     { TASK_RANGE_ATTACK1,       (float)0        },
  1818. };
  1819.  
  1820. Schedule_t  slGruntRangeAttack1A[] =
  1821. {
  1822.     {
  1823.         tlGruntRangeAttack1A,
  1824.         ARRAYSIZE ( tlGruntRangeAttack1A ),
  1825.         bits_COND_NEW_ENEMY         |
  1826.         bits_COND_ENEMY_DEAD        |
  1827.         bits_COND_HEAVY_DAMAGE      |
  1828.         bits_COND_ENEMY_OCCLUDED    |
  1829.         bits_COND_HEAR_SOUND        |
  1830.         bits_COND_GRUNT_NOFIRE      |
  1831.         bits_COND_NO_AMMO_LOADED,
  1832.        
  1833.         bits_SOUND_DANGER,
  1834.         "Range Attack1A"
  1835.     },
  1836. };
  1837.  
  1838.  
  1839. //=========================================================
  1840. // primary range attack. Overriden because base class stops attacking when the enemy is occluded.
  1841. // grunt's grenade toss requires the enemy be occluded.
  1842. //=========================================================
  1843. Task_t  tlGruntRangeAttack1B[] =
  1844. {
  1845.     { TASK_STOP_MOVING,             (float)0        },
  1846.     { TASK_PLAY_SEQUENCE_FACE_ENEMY,(float)ACT_IDLE_ANGRY  },
  1847.     { TASK_GRUNT_CHECK_FIRE,    (float)0        },
  1848.     { TASK_RANGE_ATTACK1,       (float)0        },
  1849.     { TASK_FACE_ENEMY,          (float)0        },
  1850.     { TASK_GRUNT_CHECK_FIRE,    (float)0        },
  1851.     { TASK_RANGE_ATTACK1,       (float)0        },
  1852.     { TASK_FACE_ENEMY,          (float)0        },
  1853.     { TASK_GRUNT_CHECK_FIRE,    (float)0        },
  1854.     { TASK_RANGE_ATTACK1,       (float)0        },
  1855.     { TASK_FACE_ENEMY,          (float)0        },
  1856.     { TASK_GRUNT_CHECK_FIRE,    (float)0        },
  1857.     { TASK_RANGE_ATTACK1,       (float)0        },
  1858. };
  1859.  
  1860. Schedule_t  slGruntRangeAttack1B[] =
  1861. {
  1862.     {
  1863.         tlGruntRangeAttack1B,
  1864.         ARRAYSIZE ( tlGruntRangeAttack1B ),
  1865.         bits_COND_NEW_ENEMY         |
  1866.         bits_COND_ENEMY_DEAD        |
  1867.         bits_COND_HEAVY_DAMAGE      |
  1868.         bits_COND_ENEMY_OCCLUDED    |
  1869.         bits_COND_NO_AMMO_LOADED    |
  1870.         bits_COND_GRUNT_NOFIRE      |
  1871.         bits_COND_HEAR_SOUND,
  1872.        
  1873.         bits_SOUND_DANGER,
  1874.         "Range Attack1B"
  1875.     },
  1876. };
  1877.  
  1878. //=========================================================
  1879. // secondary range attack. Overriden because base class stops attacking when the enemy is occluded.
  1880. // grunt's grenade toss requires the enemy be occluded.
  1881. //=========================================================
  1882. Task_t  tlGruntRangeAttack2[] =
  1883. {
  1884.     { TASK_STOP_MOVING,             (float)0                    },
  1885.     { TASK_GRUNT_FACE_TOSS_DIR,     (float)0                    },
  1886.     { TASK_PLAY_SEQUENCE,           (float)ACT_RANGE_ATTACK2    },
  1887.     { TASK_SET_SCHEDULE,            (float)SCHED_GRUNT_WAIT_FACE_ENEMY  },// don't run immediately after throwing grenade.
  1888. };
  1889.  
  1890. Schedule_t  slGruntRangeAttack2[] =
  1891. {
  1892.     {
  1893.         tlGruntRangeAttack2,
  1894.         ARRAYSIZE ( tlGruntRangeAttack2 ),
  1895.         0,
  1896.         0,
  1897.         "RangeAttack2"
  1898.     },
  1899. };
  1900.  
  1901.  
  1902. //=========================================================
  1903. // repel
  1904. //=========================================================
  1905. Task_t  tlGruntRepel[] =
  1906. {
  1907.     { TASK_STOP_MOVING,         (float)0        },
  1908.     { TASK_FACE_IDEAL,          (float)0        },
  1909.     { TASK_PLAY_SEQUENCE,       (float)ACT_GLIDE    },
  1910. };
  1911.  
  1912. Schedule_t  slGruntRepel[] =
  1913. {
  1914.     {
  1915.         tlGruntRepel,
  1916.         ARRAYSIZE ( tlGruntRepel ),
  1917.         bits_COND_SEE_ENEMY         |
  1918.         bits_COND_NEW_ENEMY         |
  1919.         bits_COND_LIGHT_DAMAGE      |
  1920.         bits_COND_HEAVY_DAMAGE      |
  1921.         bits_COND_HEAR_SOUND,
  1922.        
  1923.         bits_SOUND_DANGER           |
  1924.         bits_SOUND_COMBAT           |
  1925.         bits_SOUND_PLAYER,
  1926.         "Repel"
  1927.     },
  1928. };
  1929.  
  1930.  
  1931. //=========================================================
  1932. // repel
  1933. //=========================================================
  1934. Task_t  tlGruntRepelAttack[] =
  1935. {
  1936.     { TASK_STOP_MOVING,         (float)0        },
  1937.     { TASK_FACE_ENEMY,          (float)0        },
  1938.     { TASK_PLAY_SEQUENCE,       (float)ACT_FLY  },
  1939. };
  1940.  
  1941. Schedule_t  slGruntRepelAttack[] =
  1942. {
  1943.     {
  1944.         tlGruntRepelAttack,
  1945.         ARRAYSIZE ( tlGruntRepelAttack ),
  1946.         bits_COND_ENEMY_OCCLUDED,
  1947.         0,
  1948.         "Repel Attack"
  1949.     },
  1950. };
  1951.  
  1952. //=========================================================
  1953. // repel land
  1954. //=========================================================
  1955. Task_t  tlGruntRepelLand[] =
  1956. {
  1957.     { TASK_STOP_MOVING,         (float)0        },
  1958.     { TASK_PLAY_SEQUENCE,       (float)ACT_LAND },
  1959.     { TASK_GET_PATH_TO_LASTPOSITION,(float)0                },
  1960.     { TASK_RUN_PATH,                (float)0                },
  1961.     { TASK_WAIT_FOR_MOVEMENT,       (float)0                },
  1962.     { TASK_CLEAR_LASTPOSITION,      (float)0                },
  1963. };
  1964.  
  1965. Schedule_t  slGruntRepelLand[] =
  1966. {
  1967.     {
  1968.         tlGruntRepelLand,
  1969.         ARRAYSIZE ( tlGruntRepelLand ),
  1970.         bits_COND_SEE_ENEMY         |
  1971.         bits_COND_NEW_ENEMY         |
  1972.         bits_COND_LIGHT_DAMAGE      |
  1973.         bits_COND_HEAVY_DAMAGE      |
  1974.         bits_COND_HEAR_SOUND,
  1975.        
  1976.         bits_SOUND_DANGER           |
  1977.         bits_SOUND_COMBAT           |
  1978.         bits_SOUND_PLAYER,
  1979.         "Repel Land"
  1980.     },
  1981. };
  1982.  
  1983.  
  1984. DEFINE_CUSTOM_SCHEDULES( CHGrunt )
  1985. {
  1986.     slGruntFollow,
  1987.     slGruntFail,
  1988.     slGruntCombatFail,
  1989.     slGruntVictoryDance,
  1990.     slGruntEstablishLineOfFire,
  1991.     slGruntFoundEnemy,
  1992.     slGruntCombatFace,
  1993.     slGruntSignalSuppress,
  1994.     slGruntSuppress,
  1995.     slGruntWaitInCover,
  1996.     slGruntTakeCover,
  1997.     slGruntGrenadeCover,
  1998.     slGruntTossGrenadeCover,
  1999.     slGruntTakeCoverFromBestSound,
  2000.     slGruntHideReload,
  2001.     slGruntSweep,
  2002.     slGruntRangeAttack1A,
  2003.     slGruntRangeAttack1B,
  2004.     slGruntRangeAttack2,
  2005.     slGruntRepel,
  2006.     slGruntRepelAttack,
  2007.     slGruntRepelLand,
  2008. };
  2009.  
  2010. IMPLEMENT_CUSTOM_SCHEDULES( CHGrunt, CSquadMonster );
  2011.  
  2012. //=========================================================
  2013. // SetActivity
  2014. //=========================================================
  2015. void CHGrunt :: SetActivity ( Activity NewActivity )
  2016. {
  2017.     int iSequence = ACTIVITY_NOT_AVAILABLE;
  2018.     void *pmodel = GET_MODEL_PTR( ENT(pev) );
  2019.  
  2020.     switch ( NewActivity)
  2021.     {
  2022.     case ACT_RANGE_ATTACK1:
  2023.         // grunt is either shooting standing or shooting crouched
  2024.         if (FBitSet( pev->weapons, HGRUNT_9MMAR))
  2025.         {
  2026.             if ( m_fStanding )
  2027.             {
  2028.                 // get aimable sequence
  2029.                 iSequence = LookupSequence( "standing_mp5" );
  2030.             }
  2031.             else
  2032.             {
  2033.                 // get crouching shoot
  2034.                 iSequence = LookupSequence( "crouching_mp5" );
  2035.             }
  2036.         }
  2037.         else
  2038.         {
  2039.             if ( m_fStanding )
  2040.             {
  2041.                 // get aimable sequence
  2042.                 iSequence = LookupSequence( "standing_shotgun" );
  2043.             }
  2044.             else
  2045.             {
  2046.                 // get crouching shoot
  2047.                 iSequence = LookupSequence( "crouching_shotgun" );
  2048.             }
  2049.         }
  2050.         break;
  2051.     case ACT_RANGE_ATTACK2:
  2052.         // grunt is going to a secondary long range attack. This may be a thrown
  2053.         // grenade or fired grenade, we must determine which and pick proper sequence
  2054.         if ( pev->weapons & HGRUNT_HANDGRENADE )
  2055.         {
  2056.             // get toss anim
  2057.             iSequence = LookupSequence( "throwgrenade" );
  2058.         }
  2059.         else
  2060.         {
  2061.             // get launch anim
  2062.             iSequence = LookupSequence( "launchgrenade" );
  2063.         }
  2064.         break;
  2065.     case ACT_RUN:
  2066.         if ( pev->health <= HGRUNT_LIMP_HEALTH )
  2067.         {
  2068.             // limp!
  2069.             iSequence = LookupActivity ( ACT_RUN_HURT );
  2070.         }
  2071.         else
  2072.         {
  2073.             iSequence = LookupActivity ( NewActivity );
  2074.         }
  2075.         break;
  2076.     case ACT_WALK:
  2077.         if ( pev->health <= HGRUNT_LIMP_HEALTH )
  2078.         {
  2079.             // limp!
  2080.             iSequence = LookupActivity ( ACT_WALK_HURT );
  2081.         }
  2082.         else
  2083.         {
  2084.             iSequence = LookupActivity ( NewActivity );
  2085.         }
  2086.         break;
  2087.     case ACT_IDLE:
  2088.         if ( m_MonsterState == MONSTERSTATE_COMBAT )
  2089.         {
  2090.             NewActivity = ACT_IDLE_ANGRY;
  2091.         }
  2092.         iSequence = LookupActivity ( NewActivity );
  2093.         break;
  2094.     default:
  2095.         iSequence = LookupActivity ( NewActivity );
  2096.         break;
  2097.     }
  2098.    
  2099.     m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present
  2100.  
  2101.     // Set to the desired anim, or default anim if the desired is not present
  2102.     if ( iSequence > ACTIVITY_NOT_AVAILABLE )
  2103.     {
  2104.         if ( pev->sequence != iSequence || !m_fSequenceLoops )
  2105.         {
  2106.             pev->frame = 0;
  2107.         }
  2108.  
  2109.         pev->sequence       = iSequence;    // Set to the reset anim (if it's there)
  2110.         ResetSequenceInfo( );
  2111.         SetYawSpeed();
  2112.     }
  2113.     else
  2114.     {
  2115.         // Not available try to get default anim
  2116.         ALERT ( at_console, "%s has no sequence for act:%d\n", STRING(pev->classname), NewActivity );
  2117.         pev->sequence       = 0;    // Set to the reset anim (if it's there)
  2118.     }
  2119. }
  2120.  
  2121. //=========================================================
  2122. // Get Schedule!
  2123. //=========================================================
  2124. Schedule_t *CHGrunt :: GetSchedule( void )
  2125. {
  2126.  
  2127.     // clear old sentence
  2128.     m_iSentence = HGRUNT_SENT_NONE;
  2129.  
  2130.     // flying? If PRONE, barnacle has me. IF not, it's assumed I am rapelling.
  2131.     if ( pev->movetype == MOVETYPE_FLY && m_MonsterState != MONSTERSTATE_PRONE )
  2132.     {
  2133.         if (pev->flags & FL_ONGROUND)
  2134.         {
  2135.             // just landed
  2136.             pev->movetype = MOVETYPE_STEP;
  2137.             return GetScheduleOfType ( SCHED_GRUNT_REPEL_LAND );
  2138.         }
  2139.         else
  2140.         {
  2141.             // repel down a rope,
  2142.             if ( m_MonsterState == MONSTERSTATE_COMBAT )
  2143.                 return GetScheduleOfType ( SCHED_GRUNT_REPEL_ATTACK );
  2144.             else
  2145.                 return GetScheduleOfType ( SCHED_GRUNT_REPEL );
  2146.         }
  2147.     }
  2148.  
  2149.     // grunts place HIGH priority on running away from danger sounds.
  2150.     if ( HasConditions(bits_COND_HEAR_SOUND) )
  2151.     {
  2152.         CSound *pSound;
  2153.         pSound = PBestSound();
  2154.  
  2155.         ASSERT( pSound != NULL );
  2156.         if ( pSound)
  2157.         {
  2158.             if (pSound->m_iType & bits_SOUND_DANGER)
  2159.             {
  2160.                 // dangerous sound nearby!
  2161.                
  2162.                 //!!!KELLY - currently, this is the grunt's signal that a grenade has landed nearby,
  2163.                 // and the grunt should find cover from the blast
  2164.                 // good place for "SHIT!" or some other colorful verbal indicator of dismay.
  2165.                 // It's not safe to play a verbal order here "Scatter", etc cause
  2166.                 // this may only affect a single individual in a squad.
  2167.                
  2168.                 if (FOkToSpeak())
  2169.                 {
  2170.                     SENTENCEG_PlayRndSz( ENT(pev), "HG_GRENADE", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
  2171.                     JustSpoke();
  2172.                 }
  2173.                 return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND );
  2174.             }
  2175.             /*
  2176.             if (!HasConditions( bits_COND_SEE_ENEMY ) && ( pSound->m_iType & (bits_SOUND_PLAYER | bits_SOUND_COMBAT) ))
  2177.             {
  2178.                 MakeIdealYaw( pSound->m_vecOrigin );
  2179.             }
  2180.             */
  2181.         }
  2182.     }
  2183.     switch  ( m_MonsterState )
  2184.     {
  2185.     case MONSTERSTATE_COMBAT:
  2186.         {
  2187. // dead enemy
  2188.             if ( HasConditions( bits_COND_ENEMY_DEAD ) )
  2189.             {
  2190.                 // call base class, all code to handle dead enemies is centralized there.
  2191.                 return CBaseMonster :: GetSchedule();
  2192.             }
  2193.  
  2194. // new enemy
  2195.             if ( HasConditions(bits_COND_NEW_ENEMY) )
  2196.             {
  2197.                 if ( InSquad() )
  2198.                 {
  2199.                     MySquadLeader()->m_fEnemyEluded = FALSE;
  2200.  
  2201.                     if ( !IsLeader() )
  2202.                     {
  2203.                         return GetScheduleOfType ( SCHED_TAKE_COVER_FROM_ENEMY );
  2204.                     }
  2205.                     else
  2206.                     {
  2207.                         //!!!KELLY - the leader of a squad of grunts has just seen the player or a
  2208.                         // monster and has made it the squad's enemy. You
  2209.                         // can check pev->flags for FL_CLIENT to determine whether this is the player
  2210.                         // or a monster. He's going to immediately start
  2211.                         // firing, though. If you'd like, we can make an alternate "first sight"
  2212.                         // schedule where the leader plays a handsign anim
  2213.                         // that gives us enough time to hear a short sentence or spoken command
  2214.                         // before he starts pluggin away.
  2215.                         if (FOkToSpeak())// && RANDOM_LONG(0,1))
  2216.                         {
  2217.                             if ((m_hEnemy != NULL) && m_hEnemy->IsPlayer())
  2218.                                 // player
  2219.                                 SENTENCEG_PlayRndSz( ENT(pev), "HG_ENEMY", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
  2220.                             else if ((m_hEnemy != NULL) &&
  2221.                                     (m_hEnemy->Classify() != CLASS_PLAYER_ALLY) &&
  2222.                                     (m_hEnemy->Classify() != CLASS_HUMAN_PASSIVE) &&
  2223.                                     (m_hEnemy->Classify() != CLASS_MACHINE))
  2224.                                 // monster
  2225.                                 SENTENCEG_PlayRndSz( ENT(pev), "HG_ENEMY_MON", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
  2226.  
  2227.                             JustSpoke();
  2228.                         }
  2229.                        
  2230.                         if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) )
  2231.                         {
  2232.                             return GetScheduleOfType ( SCHED_GRUNT_SUPPRESS );
  2233.                         }
  2234.                         else
  2235.                         {
  2236.                             return GetScheduleOfType ( SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE );
  2237.                         }
  2238.                     }
  2239.                 }
  2240.             }
  2241. // no ammo
  2242.             else if ( HasConditions ( bits_COND_NO_AMMO_LOADED ) )
  2243.             {
  2244.                 //!!!KELLY - this individual just realized he's out of bullet ammo.
  2245.                 // He's going to try to find cover to run to and reload, but rarely, if
  2246.                 // none is available, he'll drop and reload in the open here.
  2247.                 return GetScheduleOfType ( SCHED_GRUNT_COVER_AND_RELOAD );
  2248.             }
  2249.            
  2250. // damaged just a little
  2251.             else if ( HasConditions( bits_COND_LIGHT_DAMAGE ) )
  2252.             {
  2253.                 // if hurt:
  2254.                 // 90% chance of taking cover
  2255.                 // 10% chance of flinch.
  2256.                 int iPercent = RANDOM_LONG(0,99);
  2257.  
  2258.                 if ( iPercent <= 90 && m_hEnemy != NULL )
  2259.                 {
  2260.                     // only try to take cover if we actually have an enemy!
  2261.  
  2262.                     //!!!KELLY - this grunt was hit and is going to run to cover.
  2263.                     if (FOkToSpeak()) // && RANDOM_LONG(0,1))
  2264.                     {
  2265.                         //SENTENCEG_PlayRndSz( ENT(pev), "HG_COVER", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
  2266.                         m_iSentence = HGRUNT_SENT_COVER;
  2267.                         //JustSpoke();
  2268.                     }
  2269.                     return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY );
  2270.                 }
  2271.                 else
  2272.                 {
  2273.                     return GetScheduleOfType( SCHED_SMALL_FLINCH );
  2274.                 }
  2275.             }
  2276. // can kick
  2277.             else if ( HasConditions ( bits_COND_CAN_MELEE_ATTACK1 ) )
  2278.             {
  2279.                 return GetScheduleOfType ( SCHED_MELEE_ATTACK1 );
  2280.             }
  2281. // can grenade launch
  2282.  
  2283.             else if ( FBitSet( pev->weapons, HGRUNT_GRENADELAUNCHER) && HasConditions ( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) )
  2284.             {
  2285.                 // shoot a grenade if you can
  2286.                 return GetScheduleOfType( SCHED_RANGE_ATTACK2 );
  2287.             }
  2288. // can shoot
  2289.             else if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) )
  2290.             {
  2291.                 if ( InSquad() )
  2292.                 {
  2293.                     // if the enemy has eluded the squad and a squad member has just located the enemy
  2294.                     // and the enemy does not see the squad member, issue a call to the squad to waste a
  2295.                     // little time and give the player a chance to turn.
  2296.                     if ( MySquadLeader()->m_fEnemyEluded && !HasConditions ( bits_COND_ENEMY_FACING_ME ) )
  2297.                     {
  2298.                         MySquadLeader()->m_fEnemyEluded = FALSE;
  2299.                         return GetScheduleOfType ( SCHED_GRUNT_FOUND_ENEMY );
  2300.                     }
  2301.                 }
  2302.  
  2303.                 if ( OccupySlot ( bits_SLOTS_HGRUNT_ENGAGE ) )
  2304.                 {
  2305.                     // try to take an available ENGAGE slot
  2306.                     return GetScheduleOfType( SCHED_RANGE_ATTACK1 );
  2307.                 }
  2308.                 else if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) )
  2309.                 {
  2310.                     // throw a grenade if can and no engage slots are available
  2311.                     return GetScheduleOfType( SCHED_RANGE_ATTACK2 );
  2312.                 }
  2313.                 else
  2314.                 {
  2315.                     // hide!
  2316.                     return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY );
  2317.                 }
  2318.             }
  2319. // can't see enemy
  2320.             else if ( HasConditions( bits_COND_ENEMY_OCCLUDED ) )
  2321.             {
  2322.                 if ( HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) )
  2323.                 {
  2324.                     //!!!KELLY - this grunt is about to throw or fire a grenade at the player. Great place for "fire in the hole"  "frag out" etc
  2325.                     if (FOkToSpeak())
  2326.                     {
  2327.                         SENTENCEG_PlayRndSz( ENT(pev), "HG_GRENADE_THROW", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
  2328.                         JustSpoke();
  2329.                     }
  2330.                     return GetScheduleOfType( SCHED_RANGE_ATTACK2 );
  2331.                 }
  2332.                 else if ( OccupySlot( bits_SLOTS_HGRUNT_ENGAGE ) )
  2333.                 {
  2334.                     //!!!KELLY - grunt cannot see the enemy and has just decided to
  2335.                     // charge the enemy's position.
  2336.                     if (FOkToSpeak())// && RANDOM_LONG(0,1))
  2337.                     {
  2338.                         //SENTENCEG_PlayRndSz( ENT(pev), "HG_CHARGE", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
  2339.                         m_iSentence = HGRUNT_SENT_CHARGE;
  2340.                         //JustSpoke();
  2341.                     }
  2342.  
  2343.                     return GetScheduleOfType( SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE );
  2344.                 }
  2345.                 else
  2346.                 {
  2347.                     //!!!KELLY - grunt is going to stay put for a couple seconds to see if
  2348.                     // the enemy wanders back out into the open, or approaches the
  2349.                     // grunt's covered position. Good place for a taunt, I guess?
  2350.                     if (FOkToSpeak() && RANDOM_LONG(0,1))
  2351.                     {
  2352.                         SENTENCEG_PlayRndSz( ENT(pev), "HG_TAUNTS", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
  2353.                         JustSpoke();
  2354.                     }
  2355.                     return GetScheduleOfType( SCHED_STANDOFF );
  2356.                 }
  2357.             }
  2358.            
  2359.             if ( HasConditions( bits_COND_SEE_ENEMY ) && !HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) )
  2360.             {
  2361.                 return GetScheduleOfType ( SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE );
  2362.             }
  2363.         if ( m_hEnemy == NULL && IsFollowing() )
  2364.         {
  2365.             if ( !m_hTargetEnt->IsAlive() )
  2366.             {
  2367.                 // UNDONE: Comment about the recently dead player here?
  2368.                 StopFollowing( FALSE );
  2369.                 break;
  2370.             }
  2371.             else
  2372.             {
  2373.                 if ( HasConditions( bits_COND_CLIENT_PUSH ) )
  2374.                 {
  2375.                     return GetScheduleOfType( SCHED_MOVE_AWAY_FOLLOW );
  2376.                 }
  2377.                 return GetScheduleOfType( SCHED_TARGET_FACE );
  2378.             }
  2379.         }
  2380.  
  2381.         if ( HasConditions( bits_COND_CLIENT_PUSH ) )
  2382.         {
  2383.             return GetScheduleOfType( SCHED_MOVE_AWAY );
  2384.         }
  2385.  
  2386.         // try to say something about smells
  2387.         TrySmellTalk();
  2388.         }
  2389.     }
  2390.    
  2391.     // no special cases here, call the base class
  2392.     return CSquadMonster :: GetSchedule();
  2393. }
  2394.  
  2395. //=========================================================
  2396. //=========================================================
  2397. Schedule_t* CHGrunt :: GetScheduleOfType ( int Type )
  2398. {
  2399.     Schedule_t *psched;
  2400.  
  2401.     switch  ( Type )
  2402.     {
  2403.     case SCHED_TAKE_COVER_FROM_ENEMY:
  2404.         {
  2405.             if ( InSquad() )
  2406.             {
  2407.                 if ( g_iSkillLevel == SKILL_HARD && HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) )
  2408.                 {
  2409.                     if (FOkToSpeak())
  2410.                     {
  2411.                         SENTENCEG_PlayRndSz( ENT(pev), "HG_GRENADE_THROW", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch);
  2412.                         JustSpoke();
  2413.                     }
  2414.                     return slGruntTossGrenadeCover;
  2415.                 }
  2416.                 else
  2417.                 {
  2418.                     return &slGruntTakeCover[ 0 ];
  2419.                 }
  2420.             }
  2421.             else
  2422.             {
  2423.                 if ( RANDOM_LONG(0,1) )
  2424.                 {
  2425.                     return &slGruntTakeCover[ 0 ];
  2426.                 }
  2427.                 else
  2428.                 {
  2429.                     return &slGruntGrenadeCover[ 0 ];
  2430.                 }
  2431.             }
  2432.         }
  2433.     case SCHED_TAKE_COVER_FROM_BEST_SOUND:
  2434.         {
  2435.             return &slGruntTakeCoverFromBestSound[ 0 ];
  2436.         }
  2437.     case SCHED_GRUNT_TAKECOVER_FAILED:
  2438.         {
  2439.             if ( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) && OccupySlot( bits_SLOTS_HGRUNT_ENGAGE ) )
  2440.             {
  2441.                 return GetScheduleOfType( SCHED_RANGE_ATTACK1 );
  2442.             }
  2443.  
  2444.             return GetScheduleOfType ( SCHED_FAIL );
  2445.         }
  2446.         break;
  2447.     case SCHED_GRUNT_ELOF_FAIL:
  2448.         {
  2449.             // human grunt is unable to move to a position that allows him to attack the enemy.
  2450.             return GetScheduleOfType ( SCHED_TAKE_COVER_FROM_ENEMY );
  2451.         }
  2452.         break;
  2453.     case SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE:
  2454.         {
  2455.             return &slGruntEstablishLineOfFire[ 0 ];
  2456.         }
  2457.         break;
  2458.     case SCHED_RANGE_ATTACK1:
  2459.         {
  2460.             // randomly stand or crouch
  2461.             if (RANDOM_LONG(0,9) == 0)
  2462.                 m_fStanding = RANDOM_LONG(0,1);
  2463.          
  2464.             if (m_fStanding)
  2465.                 return &slGruntRangeAttack1B[ 0 ];
  2466.             else
  2467.                 return &slGruntRangeAttack1A[ 0 ];
  2468.         }
  2469.     case SCHED_RANGE_ATTACK2:
  2470.         {
  2471.             return &slGruntRangeAttack2[ 0 ];
  2472.         }
  2473.     case SCHED_COMBAT_FACE:
  2474.         {
  2475.             return &slGruntCombatFace[ 0 ];
  2476.         }
  2477.     case SCHED_GRUNT_WAIT_FACE_ENEMY:
  2478.         {
  2479.             return &slGruntWaitInCover[ 0 ];
  2480.         }
  2481.     case SCHED_GRUNT_SWEEP:
  2482.         {
  2483.             return &slGruntSweep[ 0 ];
  2484.         }
  2485.     case SCHED_GRUNT_COVER_AND_RELOAD:
  2486.         {
  2487.             return &slGruntHideReload[ 0 ];
  2488.         }
  2489.     case SCHED_GRUNT_FOUND_ENEMY:
  2490.         {
  2491.             return &slGruntFoundEnemy[ 0 ];
  2492.         }
  2493.     case SCHED_VICTORY_DANCE:
  2494.         {
  2495.             if ( InSquad() )
  2496.             {
  2497.                 if ( !IsLeader() )
  2498.                 {
  2499.                     return &slGruntFail[ 0 ];
  2500.                 }
  2501.             }
  2502.  
  2503.             return &slGruntVictoryDance[ 0 ];
  2504.         }
  2505.     case SCHED_GRUNT_SUPPRESS:
  2506.         {
  2507.             if ( m_hEnemy->IsPlayer() && m_fFirstEncounter )
  2508.             {
  2509.                 m_fFirstEncounter = FALSE;// after first encounter, leader won't issue handsigns anymore when he has a new enemy
  2510.                 return &slGruntSignalSuppress[ 0 ];
  2511.             }
  2512.             else
  2513.             {
  2514.                 return &slGruntSuppress[ 0 ];
  2515.             }
  2516.         }
  2517.     case SCHED_FAIL:
  2518.         {
  2519.             if ( m_hEnemy != NULL )
  2520.             {
  2521.                 // grunt has an enemy, so pick a different default fail schedule most likely to help recover.
  2522.                 return &slGruntCombatFail[ 0 ];
  2523.             }
  2524.  
  2525.             return &slGruntFail[ 0 ];
  2526.         }
  2527.     case SCHED_GRUNT_REPEL:
  2528.         {
  2529.             if (pev->velocity.z > -128)
  2530.                 pev->velocity.z -= 32;
  2531.             return &slGruntRepel[ 0 ];
  2532.         }
  2533.     case SCHED_GRUNT_REPEL_ATTACK:
  2534.         {
  2535.             if (pev->velocity.z > -128)
  2536.                 pev->velocity.z -= 32;
  2537.             return &slGruntRepelAttack[ 0 ];
  2538.         }
  2539.     case SCHED_GRUNT_REPEL_LAND:
  2540.         {
  2541.             return &slGruntRepelLand[ 0 ];
  2542.         }
  2543.     default:
  2544.         {
  2545.             return CSquadMonster :: GetScheduleOfType ( Type );
  2546.         }
  2547.     // Hook these to make a looping schedule
  2548.     case SCHED_TARGET_FACE:
  2549.         // call base class default so that barney will talk
  2550.         // when 'used'
  2551.         psched = CSquadMonster::GetScheduleOfType(Type);
  2552.  
  2553.         if (psched == slGruntFoundEnemy)
  2554.             return slGruntFoundEnemy;   // override this for different target face behavior
  2555.         else
  2556.             return psched;
  2557.  
  2558.     case SCHED_TARGET_CHASE:
  2559.         return slGruntFollow;
  2560.  
  2561.     case SCHED_IDLE_STAND:
  2562.         // call base class default so that scientist will talk
  2563.         // when standing during idle
  2564.         psched = CSquadMonster::GetScheduleOfType(Type);
  2565.  
  2566.         if (psched == slGruntFoundEnemy)
  2567.         {
  2568.             // just look straight ahead.
  2569.             return slGruntFoundEnemy;
  2570.         }
  2571.         else
  2572.             return psched; 
  2573.     }
  2574.     return CSquadMonster::GetScheduleOfType( Type );
  2575. }
  2576.  
  2577.  
  2578. //=========================================================
  2579. // CHGruntRepel - when triggered, spawns a monster_human_grunt
  2580. // repelling down a line.
  2581. //=========================================================
  2582.  
  2583. class CHGruntRepel : public CBaseMonster
  2584. {
  2585. public:
  2586.     void Spawn( void );
  2587.     void Precache( void );
  2588.     void EXPORT RepelUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
  2589.     int m_iSpriteTexture;   // Don't save, precache
  2590. };
  2591.  
  2592. LINK_ENTITY_TO_CLASS( monster_grunt_repel, CHGruntRepel );
  2593.  
  2594. void CHGruntRepel::Spawn( void )
  2595. {
  2596.     Precache( );
  2597.     pev->solid = SOLID_NOT;
  2598.  
  2599.     SetUse( &CHGruntRepel::RepelUse );
  2600. }
  2601.  
  2602. void CHGruntRepel::Precache( void )
  2603. {
  2604.     UTIL_PrecacheOther( "monster_human_grunt" );
  2605.     m_iSpriteTexture = PRECACHE_MODEL( "sprites/rope.spr" );
  2606. }
  2607.  
  2608. void CHGruntRepel::RepelUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  2609. {
  2610.     TraceResult tr;
  2611.     UTIL_TraceLine( pev->origin, pev->origin + Vector( 0, 0, -4096.0), dont_ignore_monsters, ENT(pev), &tr);
  2612.     /*
  2613.     if ( tr.pHit && Instance( tr.pHit )->pev->solid != SOLID_BSP)
  2614.         return NULL;
  2615.     */
  2616.  
  2617.     CBaseEntity *pEntity = Create( "monster_human_grunt", pev->origin, pev->angles );
  2618.     CBaseMonster *pGrunt = pEntity->MyMonsterPointer( );
  2619.     pGrunt->pev->movetype = MOVETYPE_FLY;
  2620.     pGrunt->pev->velocity = Vector( 0, 0, RANDOM_FLOAT( -196, -128 ) );
  2621.     pGrunt->SetActivity( ACT_GLIDE );
  2622.     // UNDONE: position?
  2623.     pGrunt->m_vecLastPosition = tr.vecEndPos;
  2624.  
  2625.     CBeam *pBeam = CBeam::BeamCreate( "sprites/rope.spr", 10 );
  2626.     pBeam->PointEntInit( pev->origin + Vector(0,0,112), pGrunt->entindex() );
  2627.     pBeam->SetFlags( BEAM_FSOLID );
  2628.     pBeam->SetColor( 255, 255, 255 );
  2629.     pBeam->SetThink( &CBaseEntity::SUB_Remove );
  2630.     pBeam->pev->nextthink = gpGlobals->time + -4096.0 * tr.flFraction / pGrunt->pev->velocity.z + 0.5;
  2631.  
  2632.     UTIL_Remove( this );
  2633. }
  2634.  
  2635.  
  2636.  
  2637. //=========================================================
  2638. // DEAD HGRUNT PROP
  2639. //=========================================================
  2640. class CDeadHGrunt : public CBaseMonster
  2641. {
  2642. public:
  2643.     void Spawn( void );
  2644.     int Classify ( void ) { return  CLASS_HUMAN_MILITARY; }
  2645.  
  2646.     void KeyValue( KeyValueData *pkvd );
  2647.  
  2648.     int m_iPose;// which sequence to display    -- temporary, don't need to save
  2649.     static char *m_szPoses[11];
  2650. };
  2651.  
  2652. char *CDeadHGrunt::m_szPoses[] = { "deadstomach", "deadside", "deadsitting", "deadsittingchair", "deadsitting2", "dead_on_stomach2", "deadback", "deadback2", "deadrail", "deadstomach2", "deadsittingchair2" };
  2653.  
  2654. void CDeadHGrunt::KeyValue( KeyValueData *pkvd )
  2655. {
  2656.     if (FStrEq(pkvd->szKeyName, "pose"))
  2657.     {
  2658.         m_iPose = atoi(pkvd->szValue);
  2659.         pkvd->fHandled = TRUE;
  2660.     }
  2661.     else
  2662.         CBaseMonster::KeyValue( pkvd );
  2663. }
  2664.  
  2665. LINK_ENTITY_TO_CLASS( monster_hgrunt_dead, CDeadHGrunt );
  2666.  
  2667. //=========================================================
  2668. // ********** DeadHGrunt SPAWN **********
  2669. //=========================================================
  2670. void CDeadHGrunt :: Spawn( void )
  2671. {
  2672.     PRECACHE_MODEL("models/hgrunt.mdl");
  2673.     SET_MODEL(ENT(pev), "models/hgrunt.mdl");
  2674.  
  2675.     pev->effects        = 0;
  2676.     pev->yaw_speed      = 8;
  2677.     pev->sequence       = 0;
  2678.     m_bloodColor        = BLOOD_COLOR_RED;
  2679.  
  2680.     pev->sequence = LookupSequence( m_szPoses[m_iPose] );
  2681.  
  2682.     if (pev->sequence == -1)
  2683.     {
  2684.         ALERT ( at_console, "Dead hgrunt with bad pose\n" );
  2685.     }
  2686.  
  2687.     // Corpses have less health
  2688.     pev->health         = 8;
  2689.  
  2690.     // map old bodies onto new bodies
  2691.     switch( pev->body )
  2692.     {
  2693.     case 0: // Grunt with Gun
  2694.         pev->body = 0;
  2695.         pev->skin = 0;
  2696.         SetBodygroup( HEAD_GROUP, HEAD_GRUNT );
  2697.         SetBodygroup( GUN_GROUP, GUN_MP5 );
  2698.         break;
  2699.     case 1: // Commander with Gun
  2700.         pev->body = 0;
  2701.         pev->skin = 0;
  2702.         SetBodygroup( HEAD_GROUP, HEAD_COMMANDER );
  2703.         SetBodygroup( GUN_GROUP, GUN_MP5 );
  2704.         break;
  2705.     case 2: // Grunt no Gun
  2706.         pev->body = 0;
  2707.         pev->skin = 0;
  2708.         SetBodygroup( HEAD_GROUP, HEAD_GRUNT );
  2709.         SetBodygroup( GUN_GROUP, GUN_NONE );
  2710.         break;
  2711.     case 3: // Commander no Gun
  2712.         pev->body = 0;
  2713.         pev->skin = 0;
  2714.         SetBodygroup( HEAD_GROUP, HEAD_COMMANDER );
  2715.         SetBodygroup( GUN_GROUP, GUN_NONE );
  2716.         break;
  2717.     }
  2718.  
  2719.     MonsterInitDead();
  2720. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement