Advertisement
Guest User

Barney Santa code

a guest
Feb 27th, 2015
186
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 22.41 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. // monster template
  17. //=========================================================
  18. // UNDONE: Holster weapon?
  19.  
  20. #include    "extdll.h"
  21. #include    "util.h"
  22. #include    "cbase.h"
  23. #include    "monsters.h"
  24. #include    "talkmonster.h"
  25. #include    "schedule.h"
  26. #include    "defaultai.h"
  27. #include    "scripted.h"
  28. #include    "weapons.h"
  29. #include    "soundent.h"
  30. #include    <time.h>
  31.  
  32. //=========================================================
  33. // Monster's Anim Events Go Here
  34. //=========================================================
  35. // first flag is barney dying for scripted sequences?
  36. #define     BARNEY_AE_DRAW      ( 2 )
  37. #define     BARNEY_AE_SHOOT     ( 3 )
  38. #define     BARNEY_AE_HOLSTER   ( 4 )
  39.  
  40. #define BARNEY_BODY_GUNHOLSTERED    0
  41. #define BARNEY_BODY_GUNDRAWN        1
  42. #define BARNEY_BODY_GUNGONE         2
  43.  
  44. class CBarney : public CTalkMonster
  45. {
  46. public:
  47.     void Spawn( void );
  48.     void Precache( void );
  49.     void SetYawSpeed( void );
  50.     int  ISoundMask( void );
  51.     void BarneyFirePistol( void );
  52.     void AlertSound( void );
  53.     int  Classify ( void );
  54.     void HandleAnimEvent( MonsterEvent_t *pEvent );
  55.    
  56.     void RunTask( Task_t *pTask );
  57.     void StartTask( Task_t *pTask );
  58.     virtual int ObjectCaps( void ) { return CTalkMonster :: ObjectCaps() | FCAP_IMPULSE_USE; }
  59.     int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType);
  60.     BOOL CheckRangeAttack1 ( float flDot, float flDist );
  61.    
  62.     void DeclineFollowing( void );
  63.  
  64.     // Override these to set behavior
  65.     Schedule_t *GetScheduleOfType ( int Type );
  66.     Schedule_t *GetSchedule ( void );
  67.     MONSTERSTATE GetIdealState ( void );
  68.  
  69.     void DeathSound( void );
  70.     void PainSound( void );
  71.    
  72.     void TalkInit( void );
  73.  
  74.     void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);
  75.     void Killed( entvars_t *pevAttacker, int iGib );
  76.    
  77.     virtual int     Save( CSave &save );
  78.     virtual int     Restore( CRestore &restore );
  79.     static  TYPEDESCRIPTION m_SaveData[];
  80.  
  81.     BOOL    m_fGunDrawn;
  82.     float   m_painTime;
  83.     float   m_checkAttackTime;
  84.     BOOL    m_lastAttackCheck;
  85.  
  86.     // UNDONE: What is this for?  It isn't used?
  87.     float   m_flPlayerDamage;// how much pain has the player inflicted on me?
  88.  
  89.     CUSTOM_SCHEDULES;
  90. };
  91.  
  92. LINK_ENTITY_TO_CLASS( monster_barney, CBarney );
  93.  
  94. TYPEDESCRIPTION CBarney::m_SaveData[] =
  95. {
  96.     DEFINE_FIELD( CBarney, m_fGunDrawn, FIELD_BOOLEAN ),
  97.     DEFINE_FIELD( CBarney, m_painTime, FIELD_TIME ),
  98.     DEFINE_FIELD( CBarney, m_checkAttackTime, FIELD_TIME ),
  99.     DEFINE_FIELD( CBarney, m_lastAttackCheck, FIELD_BOOLEAN ),
  100.     DEFINE_FIELD( CBarney, m_flPlayerDamage, FIELD_FLOAT ),
  101. };
  102.  
  103. IMPLEMENT_SAVERESTORE( CBarney, CTalkMonster );
  104.  
  105. //=========================================================
  106. // AI Schedules Specific to this monster
  107. //=========================================================
  108. Task_t  tlBaFollow[] =
  109. {
  110.     { TASK_MOVE_TO_TARGET_RANGE,(float)128      }// Move within 128 of target ent (client)
  111.     { TASK_SET_SCHEDULE,        (float)SCHED_TARGET_FACE },
  112. };
  113.  
  114. Schedule_t  slBaFollow[] =
  115. {
  116.     {
  117.         tlBaFollow,
  118.         ARRAYSIZE ( tlBaFollow ),
  119.         bits_COND_NEW_ENEMY     |
  120.         bits_COND_LIGHT_DAMAGE  |
  121.         bits_COND_HEAVY_DAMAGE  |
  122.         bits_COND_HEAR_SOUND |
  123.         bits_COND_PROVOKED,
  124.         bits_SOUND_DANGER,
  125.         "Follow"
  126.     },
  127. };
  128.  
  129. //=========================================================
  130. // BarneyDraw- much better looking draw schedule for when
  131. // barney knows who he's gonna attack.
  132. //=========================================================
  133. Task_t  tlBarneyEnemyDraw[] =
  134. {
  135.     { TASK_STOP_MOVING,                 0               },
  136.     { TASK_FACE_ENEMY,                  0               },
  137.     { TASK_PLAY_SEQUENCE_FACE_ENEMY,    (float) ACT_ARM },
  138. };
  139.  
  140. Schedule_t slBarneyEnemyDraw[] =
  141. {
  142.     {
  143.         tlBarneyEnemyDraw,
  144.         ARRAYSIZE ( tlBarneyEnemyDraw ),
  145.         0,
  146.         0,
  147.         "Barney Enemy Draw"
  148.     }
  149. };
  150.  
  151. Task_t  tlBaFaceTarget[] =
  152. {
  153.     { TASK_SET_ACTIVITY,        (float)ACT_IDLE },
  154.     { TASK_FACE_TARGET,         (float)0        },
  155.     { TASK_SET_ACTIVITY,        (float)ACT_IDLE },
  156.     { TASK_SET_SCHEDULE,        (float)SCHED_TARGET_CHASE },
  157. };
  158.  
  159. Schedule_t  slBaFaceTarget[] =
  160. {
  161.     {
  162.         tlBaFaceTarget,
  163.         ARRAYSIZE ( tlBaFaceTarget ),
  164.         bits_COND_CLIENT_PUSH   |
  165.         bits_COND_NEW_ENEMY     |
  166.         bits_COND_LIGHT_DAMAGE  |
  167.         bits_COND_HEAVY_DAMAGE  |
  168.         bits_COND_HEAR_SOUND |
  169.         bits_COND_PROVOKED,
  170.         bits_SOUND_DANGER,
  171.         "FaceTarget"
  172.     },
  173. };
  174.  
  175.  
  176. Task_t  tlIdleBaStand[] =
  177. {
  178.     { TASK_STOP_MOVING,         0               },
  179.     { TASK_SET_ACTIVITY,        (float)ACT_IDLE },
  180.     { TASK_WAIT,                (float)2        }, // repick IDLESTAND every two seconds.
  181.     { TASK_TLK_HEADRESET,       (float)0        }, // reset head position
  182. };
  183.  
  184. Schedule_t  slIdleBaStand[] =
  185. {
  186.     {
  187.         tlIdleBaStand,
  188.         ARRAYSIZE ( tlIdleBaStand ),
  189.         bits_COND_NEW_ENEMY     |
  190.         bits_COND_LIGHT_DAMAGE  |
  191.         bits_COND_HEAVY_DAMAGE  |
  192.         bits_COND_HEAR_SOUND    |
  193.         bits_COND_SMELL         |
  194.         bits_COND_PROVOKED,
  195.  
  196.         bits_SOUND_COMBAT       |// sound flags - change these, and you'll break the talking code.
  197.         //bits_SOUND_PLAYER     |
  198.         //bits_SOUND_WORLD      |
  199.        
  200.         bits_SOUND_DANGER       |
  201.         bits_SOUND_MEAT         |// scents
  202.         bits_SOUND_CARCASS      |
  203.         bits_SOUND_GARBAGE,
  204.         "IdleStand"
  205.     },
  206. };
  207.  
  208. DEFINE_CUSTOM_SCHEDULES( CBarney )
  209. {
  210.     slBaFollow,
  211.     slBarneyEnemyDraw,
  212.     slBaFaceTarget,
  213.     slIdleBaStand,
  214. };
  215.  
  216.  
  217. IMPLEMENT_CUSTOM_SCHEDULES( CBarney, CTalkMonster );
  218.  
  219. void CBarney :: StartTask( Task_t *pTask )
  220. {
  221.     CTalkMonster::StartTask( pTask );  
  222. }
  223.  
  224. void CBarney :: RunTask( Task_t *pTask )
  225. {
  226.     switch ( pTask->iTask )
  227.     {
  228.     case TASK_RANGE_ATTACK1:
  229.         if (m_hEnemy != NULL && (m_hEnemy->IsPlayer()))
  230.         {
  231.             pev->framerate = 1.5;
  232.         }
  233.         CTalkMonster::RunTask( pTask );
  234.         break;
  235.     default:
  236.         CTalkMonster::RunTask( pTask );
  237.         break;
  238.     }
  239. }
  240.  
  241.  
  242.  
  243.  
  244. //=========================================================
  245. // ISoundMask - returns a bit mask indicating which types
  246. // of sounds this monster regards.
  247. //=========================================================
  248. int CBarney :: ISoundMask ( void)
  249. {
  250.     return  bits_SOUND_WORLD    |
  251.             bits_SOUND_COMBAT   |
  252.             bits_SOUND_CARCASS  |
  253.             bits_SOUND_MEAT     |
  254.             bits_SOUND_GARBAGE  |
  255.             bits_SOUND_DANGER   |
  256.             bits_SOUND_PLAYER;
  257. }
  258.  
  259. //=========================================================
  260. // Classify - indicates this monster's place in the
  261. // relationship table.
  262. //=========================================================
  263. int CBarney :: Classify ( void )
  264. {
  265.     return  CLASS_PLAYER_ALLY;
  266. }
  267.  
  268. //=========================================================
  269. // ALertSound - barney says "Freeze!"
  270. //=========================================================
  271. void CBarney :: AlertSound( void )
  272. {
  273.     if ( m_hEnemy != NULL )
  274.     {
  275.         if ( FOkToSpeak() )
  276.         {
  277.             PlaySentence( "BA_ATTACK", RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE );
  278.         }
  279.     }
  280.  
  281. }
  282. //=========================================================
  283. // SetYawSpeed - allows each sequence to have a different
  284. // turn rate associated with it.
  285. //=========================================================
  286. void CBarney :: SetYawSpeed ( void )
  287. {
  288.     int ys;
  289.  
  290.     ys = 0;
  291.  
  292.     switch ( m_Activity )
  293.     {
  294.     case ACT_IDLE:     
  295.         ys = 70;
  296.         break;
  297.     case ACT_WALK:
  298.         ys = 70;
  299.         break;
  300.     case ACT_RUN:
  301.         ys = 90;
  302.         break;
  303.     default:
  304.         ys = 70;
  305.         break;
  306.     }
  307.  
  308.     pev->yaw_speed = ys;
  309. }
  310.  
  311.  
  312. //=========================================================
  313. // CheckRangeAttack1
  314. //=========================================================
  315. BOOL CBarney :: CheckRangeAttack1 ( float flDot, float flDist )
  316. {
  317.     if ( flDist <= 1024 && flDot >= 0.5 )
  318.     {
  319.         if ( gpGlobals->time > m_checkAttackTime )
  320.         {
  321.             TraceResult tr;
  322.            
  323.             Vector shootOrigin = pev->origin + Vector( 0, 0, 55 );
  324.             CBaseEntity *pEnemy = m_hEnemy;
  325.             Vector shootTarget = ( (pEnemy->BodyTarget( shootOrigin ) - pEnemy->pev->origin) + m_vecEnemyLKP );
  326.             UTIL_TraceLine( shootOrigin, shootTarget, dont_ignore_monsters, ENT(pev), &tr );
  327.             m_checkAttackTime = gpGlobals->time + 1;
  328.             if ( tr.flFraction == 1.0 || (tr.pHit != NULL && CBaseEntity::Instance(tr.pHit) == pEnemy) )
  329.                 m_lastAttackCheck = TRUE;
  330.             else
  331.                 m_lastAttackCheck = FALSE;
  332.             m_checkAttackTime = gpGlobals->time + 1.5;
  333.         }
  334.         return m_lastAttackCheck;
  335.     }
  336.     return FALSE;
  337. }
  338.  
  339.  
  340. //=========================================================
  341. // BarneyFirePistol - shoots one round from the pistol at
  342. // the enemy barney is facing.
  343. //=========================================================
  344. void CBarney :: BarneyFirePistol ( void )
  345. {
  346.     Vector vecShootOrigin;
  347.  
  348.     UTIL_MakeVectors(pev->angles);
  349.     vecShootOrigin = pev->origin + Vector( 0, 0, 55 );
  350.     Vector vecShootDir = ShootAtEnemy( vecShootOrigin );
  351.  
  352.     Vector angDir = UTIL_VecToAngles( vecShootDir );
  353.     SetBlending( 0, angDir.x );
  354.     pev->effects = EF_MUZZLEFLASH;
  355.  
  356.     FireBullets(1, vecShootOrigin, vecShootDir, VECTOR_CONE_2DEGREES, 1024, BULLET_MONSTER_9MM );
  357.    
  358.     int pitchShift = RANDOM_LONG( 0, 20 );
  359.    
  360.     // Only shift about half the time
  361.     if ( pitchShift > 10 )
  362.         pitchShift = 0;
  363.     else
  364.         pitchShift -= 5;
  365.     EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "barney/ba_attack2.wav", 1, ATTN_NORM, 0, 100 + pitchShift );
  366.  
  367.     CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 384, 0.3 );
  368.  
  369.     // UNDONE: Reload?
  370.     m_cAmmoLoaded--;// take away a bullet!
  371. }
  372.        
  373. //=========================================================
  374. // HandleAnimEvent - catches the monster-specific messages
  375. // that occur when tagged animation frames are played.
  376. //
  377. // Returns number of events handled, 0 if none.
  378. //=========================================================
  379. void CBarney :: HandleAnimEvent( MonsterEvent_t *pEvent )
  380. {
  381.     switch( pEvent->event )
  382.     {
  383.     case BARNEY_AE_SHOOT:
  384.         BarneyFirePistol();
  385.         break;
  386.  
  387.     case BARNEY_AE_DRAW:
  388.         // barney's bodygroup switches here so he can pull gun from holster
  389.         pev->body = BARNEY_BODY_GUNDRAWN;
  390.         m_fGunDrawn = TRUE;
  391.         break;
  392.  
  393.     case BARNEY_AE_HOLSTER:
  394.         // change bodygroup to replace gun in holster
  395.         pev->body = BARNEY_BODY_GUNHOLSTERED;
  396.         m_fGunDrawn = FALSE;
  397.         break;
  398.  
  399.     default:
  400.         CTalkMonster::HandleAnimEvent( pEvent );
  401.     }
  402. }
  403.  
  404. //=========================================================
  405. // Spawn
  406. //=========================================================
  407. void CBarney :: Spawn()
  408. {
  409.     Precache( );
  410.  
  411.         LPSYSTEMTIME sysDate;
  412.  
  413.         sysDate = (LPSYSTEMTIME) malloc(sizeof(SYSTEMTIME));
  414.        GetLocalTime(sysDate);
  415.  
  416.         if (sysDate->wMonth == 12 &amp;&amp; sysDate->wDay == 25 ) {
  417.                 SET_MODEL(ENT(pev), "models/barney_santa.mdl");
  418.         }
  419.         else {
  420.                 SET_MODEL(ENT(pev), "models/barney.mdl");
  421.         }
  422.     UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
  423.  
  424.     pev->solid          = SOLID_SLIDEBOX;
  425.     pev->movetype       = MOVETYPE_STEP;
  426.     m_bloodColor        = BLOOD_COLOR_RED;
  427.     pev->health         = gSkillData.barneyHealth;
  428.     pev->view_ofs       = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin.
  429.     m_flFieldOfView     = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello
  430.     m_MonsterState      = MONSTERSTATE_NONE;
  431.  
  432.     pev->body           = 0; // gun in holster
  433.     m_fGunDrawn         = FALSE;
  434.  
  435.     m_afCapability      = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;
  436.  
  437.     MonsterInit();
  438.     SetUse( &CTalkMonster::FollowerUse );
  439. }
  440.  
  441. //=========================================================
  442. // Precache - precaches all resources this monster needs
  443. //=========================================================
  444. void CBarney :: Precache()
  445. {
  446.     PRECACHE_MODEL("models/barney.mdl");
  447.     PRECACHE_MODEL("models/barney_santa.mdl");
  448.  
  449.     PRECACHE_SOUND("barney/ba_attack1.wav" );
  450.     PRECACHE_SOUND("barney/ba_attack2.wav" );
  451.  
  452.     PRECACHE_SOUND("barney/ba_pain1.wav");
  453.     PRECACHE_SOUND("barney/ba_pain2.wav");
  454.     PRECACHE_SOUND("barney/ba_pain3.wav");
  455.  
  456.     PRECACHE_SOUND("barney/ba_die1.wav");
  457.     PRECACHE_SOUND("barney/ba_die2.wav");
  458.     PRECACHE_SOUND("barney/ba_die3.wav");
  459.    
  460.     // every new barney must call this, otherwise
  461.     // when a level is loaded, nobody will talk (time is reset to 0)
  462.     TalkInit();
  463.     CTalkMonster::Precache();
  464. }  
  465.  
  466. // Init talk data
  467. void CBarney :: TalkInit()
  468. {
  469.    
  470.     CTalkMonster::TalkInit();
  471.  
  472.     // scientists speach group names (group names are in sentences.txt)
  473.  
  474.     m_szGrp[TLK_ANSWER]  =  "BA_ANSWER";
  475.     m_szGrp[TLK_QUESTION] = "BA_QUESTION";
  476.     m_szGrp[TLK_IDLE] =     "BA_IDLE";
  477.     m_szGrp[TLK_STARE] =        "BA_STARE";
  478.     m_szGrp[TLK_USE] =      "BA_OK";
  479.     m_szGrp[TLK_UNUSE] =    "BA_WAIT";
  480.     m_szGrp[TLK_STOP] =     "BA_STOP";
  481.  
  482.     m_szGrp[TLK_NOSHOOT] =  "BA_SCARED";
  483.     m_szGrp[TLK_HELLO] =    "BA_HELLO";
  484.  
  485.     m_szGrp[TLK_PLHURT1] =  "!BA_CUREA";
  486.     m_szGrp[TLK_PLHURT2] =  "!BA_CUREB";
  487.     m_szGrp[TLK_PLHURT3] =  "!BA_CUREC";
  488.  
  489.     m_szGrp[TLK_PHELLO] =   NULL;   //"BA_PHELLO";      // UNDONE
  490.     m_szGrp[TLK_PIDLE] =    NULL;   //"BA_PIDLE";           // UNDONE
  491.     m_szGrp[TLK_PQUESTION] = "BA_PQUEST";       // UNDONE
  492.  
  493.     m_szGrp[TLK_SMELL] =    "BA_SMELL";
  494.    
  495.     m_szGrp[TLK_WOUND] =    "BA_WOUND";
  496.     m_szGrp[TLK_MORTAL] =   "BA_MORTAL";
  497.  
  498.     // get voice for head - just one barney voice for now
  499.     m_voicePitch = 100;
  500. }
  501.  
  502.  
  503. static BOOL IsFacing( entvars_t *pevTest, const Vector &reference )
  504. {
  505.     Vector vecDir = (reference - pevTest->origin);
  506.     vecDir.z = 0;
  507.     vecDir = vecDir.Normalize();
  508.     Vector forward, angle;
  509.     angle = pevTest->v_angle;
  510.     angle.x = 0;
  511.     UTIL_MakeVectorsPrivate( angle, forward, NULL, NULL );
  512.     // He's facing me, he meant it
  513.     if ( DotProduct( forward, vecDir ) > 0.96 ) // +/- 15 degrees or so
  514.     {
  515.         return TRUE;
  516.     }
  517.     return FALSE;
  518. }
  519.  
  520.  
  521. int CBarney :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType)
  522. {
  523.     // make sure friends talk about it if player hurts talkmonsters...
  524.     int ret = CTalkMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType);
  525.     if ( !IsAlive() || pev->deadflag == DEAD_DYING )
  526.         return ret;
  527.  
  528.     if ( m_MonsterState != MONSTERSTATE_PRONE && (pevAttacker->flags & FL_CLIENT) )
  529.     {
  530.         m_flPlayerDamage += flDamage;
  531.  
  532.         // This is a heurstic to determine if the player intended to harm me
  533.         // If I have an enemy, we can't establish intent (may just be crossfire)
  534.         if ( m_hEnemy == NULL )
  535.         {
  536.             // If the player was facing directly at me, or I'm already suspicious, get mad
  537.             if ( (m_afMemory & bits_MEMORY_SUSPICIOUS) || IsFacing( pevAttacker, pev->origin ) )
  538.             {
  539.                 // Alright, now I'm pissed!
  540.                 PlaySentence( "BA_MAD", 4, VOL_NORM, ATTN_NORM );
  541.  
  542.                 Remember( bits_MEMORY_PROVOKED );
  543.                 StopFollowing( TRUE );
  544.             }
  545.             else
  546.             {
  547.                 // Hey, be careful with that
  548.                 PlaySentence( "BA_SHOT", 4, VOL_NORM, ATTN_NORM );
  549.                 Remember( bits_MEMORY_SUSPICIOUS );
  550.             }
  551.         }
  552.         else if ( !(m_hEnemy->IsPlayer()) && pev->deadflag == DEAD_NO )
  553.         {
  554.             PlaySentence( "BA_SHOT", 4, VOL_NORM, ATTN_NORM );
  555.         }
  556.     }
  557.  
  558.     return ret;
  559. }
  560.  
  561.    
  562. //=========================================================
  563. // PainSound
  564. //=========================================================
  565. void CBarney :: PainSound ( void )
  566. {
  567.     if (gpGlobals->time < m_painTime)
  568.         return;
  569.    
  570.     m_painTime = gpGlobals->time + RANDOM_FLOAT(0.5, 0.75);
  571.  
  572.     switch (RANDOM_LONG(0,2))
  573.     {
  574.     case 0: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_pain1.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
  575.     case 1: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_pain2.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
  576.     case 2: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_pain3.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
  577.     }
  578. }
  579.  
  580. //=========================================================
  581. // DeathSound
  582. //=========================================================
  583. void CBarney :: DeathSound ( void )
  584. {
  585.     switch (RANDOM_LONG(0,2))
  586.     {
  587.     case 0: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_die1.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
  588.     case 1: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_die2.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
  589.     case 2: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_die3.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
  590.     }
  591. }
  592.  
  593.  
  594. void CBarney::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType)
  595. {
  596.     switch( ptr->iHitgroup)
  597.     {
  598.     case HITGROUP_CHEST:
  599.     case HITGROUP_STOMACH:
  600.         if (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_BLAST))
  601.         {
  602.             flDamage = flDamage / 2;
  603.         }
  604.         break;
  605.     case 10:
  606.         if (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_CLUB))
  607.         {
  608.             flDamage -= 20;
  609.             if (flDamage <= 0)
  610.             {
  611.                 UTIL_Ricochet( ptr->vecEndPos, 1.0 );
  612.                 flDamage = 0.01;
  613.             }
  614.         }
  615.         // always a head shot
  616.         ptr->iHitgroup = HITGROUP_HEAD;
  617.         break;
  618.     }
  619.  
  620.     CTalkMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType );
  621. }
  622.  
  623.  
  624. void CBarney::Killed( entvars_t *pevAttacker, int iGib )
  625. {
  626.     if ( pev->body < BARNEY_BODY_GUNGONE )
  627.     {// drop the gun!
  628.         Vector vecGunPos;
  629.         Vector vecGunAngles;
  630.  
  631.         pev->body = BARNEY_BODY_GUNGONE;
  632.  
  633.         GetAttachment( 0, vecGunPos, vecGunAngles );
  634.        
  635.         CBaseEntity *pGun = DropItem( "weapon_9mmhandgun", vecGunPos, vecGunAngles );
  636.     }
  637.  
  638.     SetUse( NULL );
  639.     CTalkMonster::Killed( pevAttacker, iGib );
  640. }
  641.  
  642. //=========================================================
  643. // AI Schedules Specific to this monster
  644. //=========================================================
  645.  
  646. Schedule_t* CBarney :: GetScheduleOfType ( int Type )
  647. {
  648.     Schedule_t *psched;
  649.  
  650.     switch( Type )
  651.     {
  652.     case SCHED_ARM_WEAPON:
  653.         if ( m_hEnemy != NULL )
  654.         {
  655.             // face enemy, then draw.
  656.             return slBarneyEnemyDraw;
  657.         }
  658.         break;
  659.  
  660.     // Hook these to make a looping schedule
  661.     case SCHED_TARGET_FACE:
  662.         // call base class default so that barney will talk
  663.         // when 'used'
  664.         psched = CTalkMonster::GetScheduleOfType(Type);
  665.  
  666.         if (psched == slIdleStand)
  667.             return slBaFaceTarget;  // override this for different target face behavior
  668.         else
  669.             return psched;
  670.  
  671.     case SCHED_TARGET_CHASE:
  672.         return slBaFollow;
  673.  
  674.     case SCHED_IDLE_STAND:
  675.         // call base class default so that scientist will talk
  676.         // when standing during idle
  677.         psched = CTalkMonster::GetScheduleOfType(Type);
  678.  
  679.         if (psched == slIdleStand)
  680.         {
  681.             // just look straight ahead.
  682.             return slIdleBaStand;
  683.         }
  684.         else
  685.             return psched; 
  686.     }
  687.  
  688.     return CTalkMonster::GetScheduleOfType( Type );
  689. }
  690.  
  691. //=========================================================
  692. // GetSchedule - Decides which type of schedule best suits
  693. // the monster's current state and conditions. Then calls
  694. // monster's member function to get a pointer to a schedule
  695. // of the proper type.
  696. //=========================================================
  697. Schedule_t *CBarney :: GetSchedule ( void )
  698. {
  699.     if ( HasConditions( bits_COND_HEAR_SOUND ) )
  700.     {
  701.         CSound *pSound;
  702.         pSound = PBestSound();
  703.  
  704.         ASSERT( pSound != NULL );
  705.         if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) )
  706.             return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND );
  707.     }
  708.     if ( HasConditions( bits_COND_ENEMY_DEAD ) && FOkToSpeak() )
  709.     {
  710.         PlaySentence( "BA_KILL", 4, VOL_NORM, ATTN_NORM );
  711.     }
  712.  
  713.     switch( m_MonsterState )
  714.     {
  715.     case MONSTERSTATE_COMBAT:
  716.         {
  717. // dead enemy
  718.             if ( HasConditions( bits_COND_ENEMY_DEAD ) )
  719.             {
  720.                 // call base class, all code to handle dead enemies is centralized there.
  721.                 return CBaseMonster :: GetSchedule();
  722.             }
  723.  
  724.             // always act surprized with a new enemy
  725.             if ( HasConditions( bits_COND_NEW_ENEMY ) && HasConditions( bits_COND_LIGHT_DAMAGE) )
  726.                 return GetScheduleOfType( SCHED_SMALL_FLINCH );
  727.                
  728.             // wait for one schedule to draw gun
  729.             if (!m_fGunDrawn )
  730.                 return GetScheduleOfType( SCHED_ARM_WEAPON );
  731.  
  732.             if ( HasConditions( bits_COND_HEAVY_DAMAGE ) )
  733.                 return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY );
  734.         }
  735.         break;
  736.  
  737.     case MONSTERSTATE_ALERT:   
  738.     case MONSTERSTATE_IDLE:
  739.         if ( HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE))
  740.         {
  741.             // flinch if hurt
  742.             return GetScheduleOfType( SCHED_SMALL_FLINCH );
  743.         }
  744.  
  745.         if ( m_hEnemy == NULL && IsFollowing() )
  746.         {
  747.             if ( !m_hTargetEnt->IsAlive() )
  748.             {
  749.                 // UNDONE: Comment about the recently dead player here?
  750.                 StopFollowing( FALSE );
  751.                 break;
  752.             }
  753.             else
  754.             {
  755.                 if ( HasConditions( bits_COND_CLIENT_PUSH ) )
  756.                 {
  757.                     return GetScheduleOfType( SCHED_MOVE_AWAY_FOLLOW );
  758.                 }
  759.                 return GetScheduleOfType( SCHED_TARGET_FACE );
  760.             }
  761.         }
  762.  
  763.         if ( HasConditions( bits_COND_CLIENT_PUSH ) )
  764.         {
  765.             return GetScheduleOfType( SCHED_MOVE_AWAY );
  766.         }
  767.  
  768.         // try to say something about smells
  769.         TrySmellTalk();
  770.         break;
  771.     }
  772.    
  773.     return CTalkMonster::GetSchedule();
  774. }
  775.  
  776. MONSTERSTATE CBarney :: GetIdealState ( void )
  777. {
  778.     return CTalkMonster::GetIdealState();
  779. }
  780.  
  781.  
  782.  
  783. void CBarney::DeclineFollowing( void )
  784. {
  785.     PlaySentence( "BA_POK", 2, VOL_NORM, ATTN_NORM );
  786. }
  787.  
  788.  
  789.  
  790.  
  791.  
  792. //=========================================================
  793. // DEAD BARNEY PROP
  794. //
  795. // Designer selects a pose in worldcraft, 0 through num_poses-1
  796. // this value is added to what is selected as the 'first dead pose'
  797. // among the monster's normal animations. All dead poses must
  798. // appear sequentially in the model file. Be sure and set
  799. // the m_iFirstPose properly!
  800. //
  801. //=========================================================
  802. class CDeadBarney : public CBaseMonster
  803. {
  804. public:
  805.     void Spawn( void );
  806.     int Classify ( void ) { return  CLASS_PLAYER_ALLY; }
  807.  
  808.     void KeyValue( KeyValueData *pkvd );
  809.  
  810.     int m_iPose;// which sequence to display    -- temporary, don't need to save
  811.     static char *m_szPoses[3];
  812. };
  813.  
  814. char *CDeadBarney::m_szPoses[] = { "lying_on_back", "lying_on_side", "lying_on_stomach" };
  815.  
  816. void CDeadBarney::KeyValue( KeyValueData *pkvd )
  817. {
  818.     if (FStrEq(pkvd->szKeyName, "pose"))
  819.     {
  820.         m_iPose = atoi(pkvd->szValue);
  821.         pkvd->fHandled = TRUE;
  822.     }
  823.     else
  824.         CBaseMonster::KeyValue( pkvd );
  825. }
  826.  
  827. LINK_ENTITY_TO_CLASS( monster_barney_dead, CDeadBarney );
  828.  
  829. //=========================================================
  830. // ********** DeadBarney SPAWN **********
  831. //=========================================================
  832. void CDeadBarney :: Spawn( )
  833. {
  834.     PRECACHE_MODEL("models/barney.mdl");
  835.     SET_MODEL(ENT(pev), "models/barney.mdl");
  836.  
  837.     pev->effects        = 0;
  838.     pev->yaw_speed      = 8;
  839.     pev->sequence       = 0;
  840.     m_bloodColor        = BLOOD_COLOR_RED;
  841.  
  842.     pev->sequence = LookupSequence( m_szPoses[m_iPose] );
  843.     if (pev->sequence == -1)
  844.     {
  845.         ALERT ( at_console, "Dead barney with bad pose\n" );
  846.     }
  847.     // Corpses have less health
  848.     pev->health         = 8;//gSkillData.barneyHealth;
  849.  
  850.     MonsterInitDead();
  851. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement