From db60d88b23d1ca80daea279349ca75ffdd5bfd25 Mon Sep 17 00:00:00 2001 From: Roman Chistokhodov Date: Wed, 31 Jul 2019 01:48:16 +0300 Subject: [PATCH] Update gonome --- dlls/gearbox/gonome.cpp | 489 +++++++++++++++++++++++++--------------- 1 file changed, 309 insertions(+), 180 deletions(-) diff --git a/dlls/gearbox/gonome.cpp b/dlls/gearbox/gonome.cpp index f8d66b25..a3518f56 100644 --- a/dlls/gearbox/gonome.cpp +++ b/dlls/gearbox/gonome.cpp @@ -27,15 +27,12 @@ #include "decals.h" #include "animation.h" #include "studio.h" -#include "zombie.h" -#define GONOME_SPRINT_DIST 256 // how close the squid has to get before starting to sprint and refusing to swerve - -#define GONOME_TOLERANCE_MELEE1_RANGE 85 -#define GONOME_TOLERANCE_MELEE2_RANGE 48 - -#define GONOME_TOLERANCE_MELEE1_DOT 0.7 -#define GONOME_TOLERANCE_MELEE2_DOT 0.7 +/* Whether gonome locks the player during the bite attack. + * This may have undesired side-effects, e.g. in combination with trigger_playerfreeze or trigger_camera, + * since both gonome and the trigger use the same technique to lock the player. + */ +#define FEATURE_GONOME_LOCK_PLAYER 1 #define GONOME_MELEE_ATTACK_RADIUS 70 @@ -50,7 +47,7 @@ enum #define GONOME_AE_SLASH_RIGHT ( 1 ) #define GONOME_AE_SLASH_LEFT ( 2 ) -#define GONOME_AE_SPIT ( 3 ) +#define GONOME_AE_SPIT ( 3 ) #define GONOME_AE_THROW ( 4 ) #define GONOME_AE_BITE1 ( 19 ) @@ -58,6 +55,8 @@ enum #define GONOME_AE_BITE3 ( 21 ) #define GONOME_AE_BITE4 ( 22 ) +#define GONOME_SCRIPT_EVENT_SOUND ( 1011 ) + //========================================================= // Gonome's guts projectile //========================================================= @@ -65,7 +64,6 @@ class CGonomeGuts : public CSquidSpit { public: void Spawn(void); - static void Shoot(entvars_t *pevOwner, Vector vecStart, Vector vecVelocity); void Touch(CBaseEntity *pOther); }; @@ -78,28 +76,16 @@ void CGonomeGuts::Spawn() pev->rendermode = kRenderTransAlpha; pev->renderamt = 255; - SET_MODEL( ENT( pev ), "sprites/blood_chnk.spr" ); + SET_MODEL( ENT( pev ), "sprites/bigspit.spr" ); pev->frame = 0; pev->scale = 0.5; + pev->rendercolor.x = 255; UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); m_maxFrame = (float)MODEL_FRAMES( pev->modelindex ) - 1; } -void CGonomeGuts::Shoot( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ) -{ - CGonomeGuts *pSpit = GetClassPtr( (CGonomeGuts *)NULL ); - pSpit->Spawn(); - - UTIL_SetOrigin( pSpit->pev, vecStart ); - pSpit->pev->velocity = vecVelocity; - pSpit->pev->owner = ENT( pevOwner ); - - pSpit->SetThink( &CSquidSpit::Animate ); - pSpit->pev->nextthink = gpGlobals->time + 0.1; -} - void CGonomeGuts::Touch( CBaseEntity *pOther ) { TraceResult tr; @@ -125,7 +111,7 @@ void CGonomeGuts::Touch( CBaseEntity *pOther ) // make a splat on the wall UTIL_TraceLine( pev->origin, pev->origin + pev->velocity * 10, dont_ignore_monsters, ENT( pev ), &tr ); UTIL_BloodDecalTrace( &tr, BLOOD_COLOR_RED ); - UTIL_BloodDrips( tr.vecEndPos, UTIL_RandomBloodVector(), BLOOD_COLOR_RED, 35 ); + UTIL_BloodDrips( tr.vecEndPos, UTIL_RandomBloodVector(), BLOOD_COLOR_RED, 35 ); } else { @@ -139,29 +125,36 @@ void CGonomeGuts::Touch( CBaseEntity *pOther ) //========================================================= // CGonome //========================================================= -class CGonome : public CZombie +class CGonome : public CBaseMonster { public: void Spawn(void); void Precache(void); + int Classify(void); + void SetYawSpeed(); void HandleAnimEvent(MonsterEvent_t *pEvent); - void StartTask(Task_t *pTask); - - BOOL CheckMeleeAttack1(float flDot, float flDist); - BOOL CheckMeleeAttack2(float flDot, float flDist); - BOOL CheckRangeAttack1(float flDot, float flDist); - void RunAI(void); - Schedule_t *GetSchedule(); - Schedule_t *GetScheduleOfType( int Type ); - int TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType); - - void SetActivity( Activity NewActivity ); - + int IgnoreConditions(); + void IdleSound( void ); void PainSound( void ); void DeathSound( void ); - void IdleSound( void ); + void AlertSound( void ); + void StartTask(Task_t *pTask); + + BOOL CheckMeleeAttack2(float flDot, float flDist); + BOOL CheckRangeAttack1(float flDot, float flDist); + void SetActivity( Activity NewActivity ); + + Schedule_t *GetSchedule(); + Schedule_t *GetScheduleOfType( int Type ); + + int TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType); + void Killed(entvars_t *pevAttacker, int iGib); + + void UnlockPlayer(); + CGonomeGuts* GetGonomeGuts(const Vector& pos); + void ClearGuts(); int Save(CSave &save); int Restore(CRestore &restore); @@ -172,11 +165,18 @@ public: static const char* pPainSounds[]; static const char* pIdleSounds[]; static const char* pDeathSounds[]; + static const char *pAttackHitSounds[]; + static const char *pAttackMissSounds[]; + + virtual int SizeForGrapple() { return GRAPPLE_LARGE; } protected: - int GonomeLookupActivity( void *pmodel, int activity ); - float m_flLastHurtTime;// we keep track of this, because if something hurts a squid, it will forget about its love of headcrabs for a while. - float m_flNextSpitTime;// last time the gonome used the spit attack. - bool gonnaAttack1; + float m_flNextFlinch; + float m_flNextThrowTime;// last time the gonome used the guts attack. + CGonomeGuts* m_pGonomeGuts; +#if FEATURE_GONOME_LOCK_PLAYER + BOOL m_fPlayerLocked; + EHANDLE m_lockedPlayer; +#endif }; LINK_ENTITY_TO_CLASS(monster_gonome, CGonome) @@ -200,27 +200,92 @@ const char* CGonome::pDeathSounds[] = { "gonome/gonome_death4.wav" }; +const char* CGonome::pAttackHitSounds[] = +{ + "zombie/claw_strike1.wav", + "zombie/claw_strike2.wav", + "zombie/claw_strike3.wav", +}; + +const char* CGonome::pAttackMissSounds[] = +{ + "zombie/claw_miss1.wav", + "zombie/claw_miss2.wav", +}; + TYPEDESCRIPTION CGonome::m_SaveData[] = { - DEFINE_FIELD( CGonome, m_flLastHurtTime, FIELD_TIME ), - DEFINE_FIELD( CGonome, m_flNextSpitTime, FIELD_TIME ), + DEFINE_FIELD( CGonome, m_flNextFlinch, FIELD_TIME ), + DEFINE_FIELD( CGonome, m_flNextThrowTime, FIELD_TIME ), +#if FEATURE_GONOME_LOCK_PLAYER + DEFINE_FIELD( CGonome, m_fPlayerLocked, FIELD_BOOLEAN ), +#endif }; IMPLEMENT_SAVERESTORE( CGonome, CBaseMonster ) +void CGonome::Killed(entvars_t *pevAttacker, int iGib) +{ + ClearGuts(); + UnlockPlayer(); + CBaseMonster::Killed(pevAttacker, iGib); +} + +void CGonome::UnlockPlayer() +{ +#if FEATURE_GONOME_LOCK_PLAYER + if (m_fPlayerLocked) + { + CBasePlayer* player = 0; + if (m_lockedPlayer != 0 && m_lockedPlayer->IsPlayer()) + player = (CBasePlayer*)((CBaseEntity*)m_lockedPlayer); + else // if ehandle is empty for some reason just unlock the first player + player = (CBasePlayer*)UTIL_FindEntityByClassname(0, "player"); + + if (player && player->IsAlive()) + player->EnableControl(TRUE); + + m_lockedPlayer = 0; + m_fPlayerLocked = FALSE; + } +#endif +} + +CGonomeGuts* CGonome::GetGonomeGuts(const Vector &pos) +{ + if (m_pGonomeGuts) + return m_pGonomeGuts; + CGonomeGuts *pGuts = GetClassPtr( (CGonomeGuts *)NULL ); + pGuts->Spawn(); + + UTIL_SetOrigin( pGuts->pev, pos ); + + m_pGonomeGuts = pGuts; + return m_pGonomeGuts; +} + +void CGonome::ClearGuts() +{ + if (m_pGonomeGuts) + { + UTIL_Remove(m_pGonomeGuts); + m_pGonomeGuts = 0; + } +} + void CGonome::PainSound( void ) { int pitch = 95 + RANDOM_LONG( 0, 9 ); if( RANDOM_LONG( 0, 5 ) < 2 ) - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, pPainSounds[RANDOM_LONG( 0, ARRAYSIZE( pPainSounds ) - 1 )], 1.0, ATTN_NORM, 0, pitch ); + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, RANDOM_SOUND_ARRAY(pPainSounds), 1.0, ATTN_NORM, 0, pitch ); } void CGonome::DeathSound( void ) { int pitch = 95 + RANDOM_LONG( 0, 9 ); - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, pAlertSounds[ RANDOM_LONG( 0, ARRAYSIZE( pDeathSounds ) - 1 )], 1.0, ATTN_NORM, 0, pitch ); + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, RANDOM_SOUND_ARRAY(pDeathSounds), 1.0, ATTN_NORM, 0, pitch ); } void CGonome::IdleSound( void ) @@ -228,76 +293,92 @@ void CGonome::IdleSound( void ) int pitch = 95 + RANDOM_LONG( 0, 9 ); // Play a random idle sound - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, pIdleSounds[RANDOM_LONG( 0, ARRAYSIZE( pIdleSounds ) -1 )], 1.0, ATTN_NORM, 0, pitch ); + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, RANDOM_SOUND_ARRAY(pIdleSounds), 1.0, ATTN_NORM, 0, pitch ); } -/* - * Hack to ignore activity weights when choosing melee attack animation - */ -int CGonome::GonomeLookupActivity( void *pmodel, int activity ) +void CGonome::AlertSound( void ) { - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if( !pstudiohdr ) - return 0; - - mstudioseqdesc_t *pseqdesc; - - pseqdesc = (mstudioseqdesc_t *)( (byte *)pstudiohdr + pstudiohdr->seqindex ); - - int sameActivityNum = 0; - for( int i = 0; i < pstudiohdr->numseq && sameActivityNum < 2; i++ ) - { - if( pseqdesc[i].activity == activity ) - { - sameActivityNum++; - if (sameActivityNum == 1 && gonnaAttack1) { - return i; - } else if (sameActivityNum == 2) { - return i; - } - } - } - - return ACTIVITY_NOT_AVAILABLE; + const int iPitch = RANDOM_LONG(0, 9) + 95; + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, RANDOM_SOUND_ARRAY(pIdleSounds), 1, ATTN_NORM, 0, iPitch); } void CGonome::SetActivity( Activity NewActivity ) { - if (NewActivity != ACT_MELEE_ATTACK1) { - CBaseMonster::SetActivity(NewActivity); - } else { - ASSERT( NewActivity != 0 ); - void *pmodel = GET_MODEL_PTR( ENT( pev ) ); - int iSequence = GonomeLookupActivity( pmodel, NewActivity ); + Activity OldActivity = m_Activity; + int iSequence = ACTIVITY_NOT_AVAILABLE; - // Set to the desired anim, or default anim if the desired is not present - if( iSequence > ACTIVITY_NOT_AVAILABLE ) + if (NewActivity != ACT_RANGE_ATTACK1) + { + ClearGuts(); + } + if (NewActivity == ACT_MELEE_ATTACK1 && m_hEnemy != 0) + { + // special melee animations + if ((pev->origin - m_hEnemy->pev->origin).Length2D() >= 48 ) { - if( pev->sequence != iSequence || !m_fSequenceLoops ) - { - // don't reset frame between walk and run - if( !( m_Activity == ACT_WALK || m_Activity == ACT_RUN ) || !( NewActivity == ACT_WALK || NewActivity == ACT_RUN ) ) - pev->frame = 0; - } - - pev->sequence = iSequence; // Set to the reset anim (if it's there) - ResetSequenceInfo(); - SetYawSpeed(); + iSequence = LookupSequence("attack1"); } else { - // Not available try to get default anim - ALERT( at_aiconsole, "%s has no sequence for act:%d\n", STRING( pev->classname ), NewActivity ); - pev->sequence = 0; // Set to the reset anim (if it's there) + iSequence = LookupSequence("attack2"); + } + } + else + { + UnlockPlayer(); + + if (NewActivity == ACT_RUN && m_hEnemy != 0) + { + // special run animations + if ((pev->origin - m_hEnemy->pev->origin).Length2D() <= 512 ) + { + iSequence = LookupSequence("runshort"); + } + else + { + iSequence = LookupSequence("runlong"); + } + } + else + { + iSequence = LookupActivity(NewActivity); + } + } + + m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present + + // In case someone calls this with something other than the ideal activity + m_IdealActivity = m_Activity; + + // Set to the desired anim, or default anim if the desired is not present + if( iSequence > ACTIVITY_NOT_AVAILABLE ) + { + if( pev->sequence != iSequence || !m_fSequenceLoops ) + { + // don't reset frame between walk and run + if( !( OldActivity == ACT_WALK || OldActivity == ACT_RUN ) || !( NewActivity == ACT_WALK || NewActivity == ACT_RUN ) ) + pev->frame = 0; } - m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present - - // In case someone calls this with something other than the ideal activity - m_IdealActivity = m_Activity; + pev->sequence = iSequence; // Set to the reset anim (if it's there) + ResetSequenceInfo(); + SetYawSpeed(); } + else + { + // Not available try to get default anim + ALERT( at_aiconsole, "%s has no sequence for act:%d\n", STRING( pev->classname ), NewActivity ); + pev->sequence = 0; // Set to the reset anim (if it's there) + } +} + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CGonome::Classify(void) +{ + return CLASS_ALIEN_MONSTER; } //========================================================= @@ -328,13 +409,16 @@ int CGonome::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float f //========================================================= BOOL CGonome::CheckRangeAttack1(float flDot, float flDist) { + if (flDist < 256) + return FALSE; + if (IsMoving() && flDist >= 512) { // squid will far too far behind if he stops running to spit at this distance from the enemy. return FALSE; } - if (flDist > 64 && flDist <= 784 && flDot >= 0.5 && gpGlobals->time >= m_flNextSpitTime) + if (flDist > 64 && flDist <= 784 && flDot >= 0.5 && gpGlobals->time >= m_flNextThrowTime) { if (m_hEnemy != 0) { @@ -348,12 +432,12 @@ BOOL CGonome::CheckRangeAttack1(float flDot, float flDist) if (IsMoving()) { // don't spit again for a long time, resume chasing enemy. - m_flNextSpitTime = gpGlobals->time + 5; + m_flNextThrowTime = gpGlobals->time + 5; } else { // not moving, so spit again pretty soon. - m_flNextSpitTime = gpGlobals->time + 0.5; + m_flNextThrowTime = gpGlobals->time + 0.5; } return TRUE; @@ -362,24 +446,6 @@ BOOL CGonome::CheckRangeAttack1(float flDot, float flDist) return FALSE; } -//========================================================= -// CheckMeleeAttack1 - gonome is a big guy, so has a longer -// melee range than most monsters. -//========================================================= -BOOL CGonome::CheckMeleeAttack1(float flDot, float flDist) -{ - if (flDist <= GONOME_TOLERANCE_MELEE2_RANGE && flDot >= GONOME_TOLERANCE_MELEE2_DOT && RANDOM_LONG(0,1) == 0) { - gonnaAttack1 = false; - return TRUE; - } - else if (flDist <= GONOME_TOLERANCE_MELEE1_RANGE && flDot >= GONOME_TOLERANCE_MELEE1_DOT) - { - gonnaAttack1 = true; - return TRUE; - } - return FALSE; -} - //========================================================= // CheckMeleeAttack2 - both gonome's melee attacks are ACT_MELEE_ATTACK1 //========================================================= @@ -388,6 +454,15 @@ BOOL CGonome::CheckMeleeAttack2(float flDot, float flDist) return FALSE; } +//========================================================= +// SetYawSpeed - allows each sequence to have a different +// turn rate associated with it. +//========================================================= +void CGonome::SetYawSpeed( void ) +{ + pev->yaw_speed = 120; +} + //========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. @@ -396,31 +471,57 @@ void CGonome::HandleAnimEvent(MonsterEvent_t *pEvent) { switch (pEvent->event) { - case 1011: - // This may play sound twice - //EMIT_SOUND(ENT(pev), CHAN_VOICE, pEvent->options, 1, ATTN_NORM); + case GONOME_SCRIPT_EVENT_SOUND: + EMIT_SOUND(ENT(pev), CHAN_BODY, pEvent->options, 1, ATTN_NORM); break; case GONOME_AE_SPIT: + { + Vector vecArmPos, vecArmAng; + GetAttachment(0, vecArmPos, vecArmAng); + + if (GetGonomeGuts(vecArmPos)) + { + m_pGonomeGuts->pev->body = 1; + m_pGonomeGuts->pev->aiment = ENT(pev); + m_pGonomeGuts->pev->movetype = MOVETYPE_FOLLOW; + } + UTIL_BloodDrips( vecArmPos, UTIL_RandomBloodVector(), BLOOD_COLOR_RED, 35 ); + } + break; case GONOME_AE_THROW: { - Vector vecSpitOffset; - Vector vecSpitDir; - UTIL_MakeVectors(pev->angles); Vector vecArmPos, vecArmAng; GetAttachment(0, vecArmPos, vecArmAng); - vecSpitOffset = vecArmPos; - UTIL_BloodDrips( vecSpitOffset, UTIL_RandomBloodVector(), BLOOD_COLOR_RED, 35 ); - if( pEvent->event == GONOME_AE_THROW ) + if (GetGonomeGuts(vecArmPos)) { - vecSpitDir = ((m_hEnemy->pev->origin + m_hEnemy->pev->view_ofs) - vecSpitOffset).Normalize(); + Vector vecSpitDir; + + Vector vecEnemyPosition; + if (m_hEnemy != 0) + vecEnemyPosition = (m_hEnemy->pev->origin + m_hEnemy->pev->view_ofs); + else + vecEnemyPosition = m_vecEnemyLKP; + vecSpitDir = (vecEnemyPosition - vecArmPos).Normalize(); vecSpitDir.x += RANDOM_FLOAT(-0.05, 0.05); vecSpitDir.y += RANDOM_FLOAT(-0.05, 0.05); vecSpitDir.z += RANDOM_FLOAT(-0.05, 0); - CGonomeGuts::Shoot(pev, vecSpitOffset, vecSpitDir * 1200); // Default: 900 + + m_pGonomeGuts->pev->body = 0; + m_pGonomeGuts->pev->skin = 0; + m_pGonomeGuts->pev->owner = ENT( pev ); + m_pGonomeGuts->pev->aiment = 0; + m_pGonomeGuts->pev->movetype = MOVETYPE_FLY; + m_pGonomeGuts->pev->velocity = vecSpitDir * 900; + m_pGonomeGuts->SetThink( &CGonomeGuts::Animate ); + m_pGonomeGuts->pev->nextthink = gpGlobals->time + 0.1; + UTIL_SetOrigin(m_pGonomeGuts->pev, vecArmPos); + + m_pGonomeGuts = 0; } + UTIL_BloodDrips( vecArmPos, UTIL_RandomBloodVector(), BLOOD_COLOR_RED, 35 ); } break; @@ -429,9 +530,17 @@ void CGonome::HandleAnimEvent(MonsterEvent_t *pEvent) CBaseEntity *pHurt = CheckTraceHullAttack(GONOME_MELEE_ATTACK_RADIUS, gSkillData.gonomeDmgOneSlash, DMG_SLASH); if (pHurt) { - pHurt->pev->punchangle.z = 9; - pHurt->pev->punchangle.x = 5; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * 25; + if (FBitSet(pHurt->pev->flags, FL_MONSTER|FL_CLIENT)) + { + pHurt->pev->punchangle.z = 9; + pHurt->pev->punchangle.x = 5; + pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * 25; + } + EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pAttackHitSounds), 1, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5)); + } + else + { + EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pAttackMissSounds), 1, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5)); } } break; @@ -441,9 +550,17 @@ void CGonome::HandleAnimEvent(MonsterEvent_t *pEvent) CBaseEntity *pHurt = CheckTraceHullAttack(GONOME_MELEE_ATTACK_RADIUS, gSkillData.gonomeDmgOneSlash, DMG_SLASH); if (pHurt) { - pHurt->pev->punchangle.z = -9; - pHurt->pev->punchangle.x = 5; - pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_right * 25; + if (FBitSet(pHurt->pev->flags, FL_MONSTER|FL_CLIENT)) + { + pHurt->pev->punchangle.z = -9; + pHurt->pev->punchangle.x = 5; + pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * -25; + } + EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pAttackHitSounds), 1, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5)); + } + else + { + EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pAttackMissSounds), 1, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5)); } } break; @@ -452,14 +569,14 @@ void CGonome::HandleAnimEvent(MonsterEvent_t *pEvent) case GONOME_AE_BITE2: case GONOME_AE_BITE3: case GONOME_AE_BITE4: - { + { int iPitch; - CBaseEntity *pHurt = CheckTraceHullAttack(GONOME_TOLERANCE_MELEE2_RANGE, gSkillData.gonomeDmgOneBite, DMG_SLASH); + CBaseEntity *pHurt = CheckTraceHullAttack(GONOME_MELEE_ATTACK_RADIUS, gSkillData.gonomeDmgOneBite, DMG_SLASH); if (pHurt) { // croonchy bite sound - iPitch = PITCH_NORM + RANDOM_FLOAT(-5, 5); + iPitch = RANDOM_FLOAT(90, 110); switch (RANDOM_LONG(0, 1)) { case 0: @@ -470,24 +587,65 @@ void CGonome::HandleAnimEvent(MonsterEvent_t *pEvent) break; } - if( pEvent->event == GONOME_AE_BITE4 ) + if (FBitSet(pHurt->pev->flags, FL_MONSTER|FL_CLIENT)) { - pHurt->pev->punchangle.x = 15; - pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_forward * 75; + if (pEvent->event == GONOME_AE_BITE4) + { + pHurt->pev->punchangle.x = 15; + pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_forward * 75; + } + else + { + pHurt->pev->punchangle.x = 9; + pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_forward * 25; + } } - else +#if FEATURE_GONOME_LOCK_PLAYER + if (pEvent->event == GONOME_AE_BITE4) { - pHurt->pev->punchangle.x = 9; - pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_forward * 25; + UnlockPlayer(); } + else if (pHurt->IsPlayer() && pHurt->IsAlive()) + { + if (!m_fPlayerLocked) + { + CBasePlayer* player = (CBasePlayer*)pHurt; + player->EnableControl(FALSE); + m_lockedPlayer = player; + m_fPlayerLocked = TRUE; + } + } +#endif } } break; + default: CBaseMonster::HandleAnimEvent(pEvent); } } +#define GONOME_FLINCH_DELAY 2 + +int CGonome::IgnoreConditions( void ) +{ + int iIgnore = CBaseMonster::IgnoreConditions(); + + if( m_Activity == ACT_MELEE_ATTACK1 ) + { + if( m_flNextFlinch >= gpGlobals->time ) + iIgnore |= ( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ); + } + + if( ( m_Activity == ACT_SMALL_FLINCH ) || ( m_Activity == ACT_BIG_FLINCH ) ) + { + if( m_flNextFlinch < gpGlobals->time ) + m_flNextFlinch = gpGlobals->time + GONOME_FLINCH_DELAY; + } + + return iIgnore; +} + //========================================================= // Spawn //========================================================= @@ -506,7 +664,7 @@ void CGonome::Spawn() m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) m_MonsterState = MONSTERSTATE_NONE; - m_flNextSpitTime = gpGlobals->time; + m_flNextThrowTime = gpGlobals->time; MonsterInit(); } @@ -518,7 +676,7 @@ void CGonome::Precache() { PRECACHE_MODEL("models/gonome.mdl"); - PRECACHE_MODEL("sprites/blood_chnk.spr");// spit projectile. + PRECACHE_MODEL("sprites/bigspit.spr");// spit projectile. PRECACHE_SOUND("zombie/claw_miss2.wav");// because we use the basemonster SWIPE animation event @@ -542,25 +700,6 @@ void CGonome::Precache() PRECACHE_SOUND("bullchicken/bc_spithit2.wav"); } -//======================================================== -// RunAI - overridden for gonome because there are things -// that need to be checked every think. -//======================================================== -void CGonome::RunAI(void) -{ - // first, do base class stuff - CBaseMonster::RunAI(); - - if (m_hEnemy != 0 && m_Activity == ACT_RUN) - { - // chasing enemy. Sprint for last bit - if ((pev->origin - m_hEnemy->pev->origin).Length2D() < GONOME_SPRINT_DIST) - { - pev->framerate = 1.25; - } - } -} - //========================================================= // GetSchedule //========================================================= @@ -723,16 +862,6 @@ void CGonome::StartTask(Task_t *pTask) switch (pTask->iTask) { - case TASK_MELEE_ATTACK1: - { - if (gonnaAttack1) - EMIT_SOUND(ENT(pev), CHAN_VOICE, "gonome/gonome_melee1.wav", 1, ATTN_NORM); - else - EMIT_SOUND(ENT(pev), CHAN_VOICE, "gonome/gonome_melee2.wav", 1, ATTN_NORM); - CBaseMonster::StartTask(pTask); - } - break; - case TASK_GONOME_GET_PATH_TO_ENEMY_CORPSE: { UTIL_MakeVectors( pev->angles );