From d30986e32862cce1edc8f0f4d57a078125002acb Mon Sep 17 00:00:00 2001 From: Roman Chistokhodov Date: Sat, 6 Aug 2022 17:42:09 +0300 Subject: [PATCH] Barney checks for player to avoid friendly fire (#305) --- dlls/barney.cpp | 102 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/dlls/barney.cpp b/dlls/barney.cpp index dd91de44..d610078a 100644 --- a/dlls/barney.cpp +++ b/dlls/barney.cpp @@ -27,6 +27,7 @@ #include "scripted.h" #include "weapons.h" #include "soundent.h" +#include "plane.h" //========================================================= // Monster's Anim Events Go Here @@ -40,6 +41,13 @@ #define BARNEY_BODY_GUNDRAWN 1 #define BARNEY_BODY_GUNGONE 2 +#define bits_COND_BARNEY_NOFIRE ( bits_COND_SPECIAL1 ) + +enum +{ + TASK_BARNEY_CHECK_FIRE = LAST_COMMON_TASK + 1, +}; + class CBarney : public CTalkMonster { public: @@ -73,6 +81,8 @@ public: void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); void Killed( entvars_t *pevAttacker, int iGib ); + BOOL NoFriendlyFire(); + virtual int Save( CSave &save ); virtual int Restore( CRestore &restore ); static TYPEDESCRIPTION m_SaveData[]; @@ -201,19 +211,57 @@ Schedule_t slIdleBaStand[] = }, }; +// primary range attack +Task_t tlBaRangeAttack1[] = +{ + { TASK_STOP_MOVING, 0 }, + { TASK_FACE_ENEMY, (float)0 }, + { TASK_BARNEY_CHECK_FIRE, (float)0 }, + { TASK_RANGE_ATTACK1, (float)0 }, +}; + +Schedule_t slBaRangeAttack1[] = +{ + { + tlBaRangeAttack1, + ARRAYSIZE( tlBaRangeAttack1 ), + bits_COND_NEW_ENEMY | + bits_COND_ENEMY_DEAD | + bits_COND_LIGHT_DAMAGE | + bits_COND_HEAVY_DAMAGE | + bits_COND_ENEMY_OCCLUDED | + bits_COND_NO_AMMO_LOADED | + bits_COND_BARNEY_NOFIRE | + bits_COND_HEAR_SOUND, + bits_SOUND_DANGER, + "Range Attack1" + }, +}; + DEFINE_CUSTOM_SCHEDULES( CBarney ) { slBaFollow, slBarneyEnemyDraw, slBaFaceTarget, slIdleBaStand, + slBaRangeAttack1, }; IMPLEMENT_CUSTOM_SCHEDULES( CBarney, CTalkMonster ) void CBarney::StartTask( Task_t *pTask ) { - CTalkMonster::StartTask( pTask ); + switch ( pTask->iTask ) { + case TASK_BARNEY_CHECK_FIRE: + if( !NoFriendlyFire() ) + { + SetConditions( bits_COND_BARNEY_NOFIRE ); + } + TaskComplete(); + break; + default: + CTalkMonster::StartTask( pTask ); + } } void CBarney::RunTask( Task_t *pTask ) @@ -663,6 +711,8 @@ Schedule_t *CBarney::GetScheduleOfType( int Type ) } else return psched; + case SCHED_RANGE_ATTACK1: + return slBaRangeAttack1; } return CTalkMonster::GetScheduleOfType( Type ); @@ -764,6 +814,56 @@ void CBarney::DeclineFollowing( void ) PlaySentence( "BA_POK", 2, VOL_NORM, ATTN_NORM ); } +BOOL CBarney::NoFriendlyFire() +{ + if( m_hEnemy != 0 ) + { + UTIL_MakeVectors( UTIL_VecToAngles( m_hEnemy->Center() - pev->origin ) ); + } + else + { + // if there's no enemy, pretend there's a friendly in the way, so the grunt won't shoot. + return FALSE; + } + + CPlane backPlane; + CPlane leftPlane; + CPlane rightPlane; + + Vector vecLeftSide; + Vector vecRightSide; + Vector v_left; + Vector v_dir; + + v_dir = gpGlobals->v_right * ( pev->size.x * 1.5f ); + vecLeftSide = pev->origin - v_dir; + vecRightSide = pev->origin + v_dir; + + v_left = gpGlobals->v_right * -1.0f; + + leftPlane.InitializePlane( gpGlobals->v_right, vecLeftSide ); + rightPlane.InitializePlane( v_left, vecRightSide ); + backPlane.InitializePlane( gpGlobals->v_forward, pev->origin ); + + for( int k = 1; k <= gpGlobals->maxClients; k++ ) + { + CBaseEntity* pPlayer = UTIL_PlayerByIndex(k); + if (pPlayer && pPlayer->IsPlayer() && IRelationship(pPlayer) == R_AL && pPlayer->IsAlive()) + { + if( backPlane.PointInFront( pPlayer->pev->origin ) && + leftPlane.PointInFront( pPlayer->pev->origin ) && + rightPlane.PointInFront( pPlayer->pev->origin ) ) + { + //ALERT(at_aiconsole, "%s: Ally player at fire plane!\n", STRING(pev->classname)); + // player is in the check volume! Don't shoot! + return FALSE; + } + } + } + + return TRUE; +} + //========================================================= // DEAD BARNEY PROP //