2016-06-04 15:24:23 +02:00
/***
*
* Copyright ( c ) 1996 - 2002 , Valve LLC . All rights reserved .
*
* This product contains software technology licensed from Id
* Software , Inc . ( " Id Technology " ) . Id Technology ( c ) 1996 Id Software , Inc .
* All Rights Reserved .
*
* This source code contains proprietary and confidential information of
* Valve LLC and its suppliers . Access to this code is restricted to
* persons who have executed a written SDK license with Valve . Any access ,
* use or distribution of this code by or to any unlicensed person is illegal .
*
* * * */
//=========================================================
// Squadmonster functions
//=========================================================
2016-06-25 18:33:39 +02:00
2016-06-04 15:24:23 +02:00
# include "extdll.h"
# include "util.h"
# include "cbase.h"
# include "nodes.h"
# include "monsters.h"
# include "animation.h"
# include "saverestore.h"
# include "squadmonster.h"
# include "plane.h"
//=========================================================
// Save/Restore
//=========================================================
2016-06-25 18:33:39 +02:00
TYPEDESCRIPTION CSquadMonster : : m_SaveData [ ] =
2016-06-04 15:24:23 +02:00
{
DEFINE_FIELD ( CSquadMonster , m_hSquadLeader , FIELD_EHANDLE ) ,
DEFINE_ARRAY ( CSquadMonster , m_hSquadMember , FIELD_EHANDLE , MAX_SQUAD_MEMBERS - 1 ) ,
// DEFINE_FIELD( CSquadMonster, m_afSquadSlots, FIELD_INTEGER ), // these need to be reset after transitions!
DEFINE_FIELD ( CSquadMonster , m_fEnemyEluded , FIELD_BOOLEAN ) ,
DEFINE_FIELD ( CSquadMonster , m_flLastEnemySightTime , FIELD_TIME ) ,
DEFINE_FIELD ( CSquadMonster , m_iMySlot , FIELD_INTEGER ) ,
} ;
2016-06-25 18:33:39 +02:00
IMPLEMENT_SAVERESTORE ( CSquadMonster , CBaseMonster )
2016-06-04 15:24:23 +02:00
//=========================================================
// OccupySlot - if any slots of the passed slots are
// available, the monster will be assigned to one.
//=========================================================
2016-07-31 15:48:50 +02:00
BOOL CSquadMonster : : OccupySlot ( int iDesiredSlots )
2016-06-04 15:24:23 +02:00
{
int i ;
int iMask ;
int iSquadSlots ;
2016-07-31 15:48:50 +02:00
if ( ! InSquad ( ) )
2016-06-04 15:24:23 +02:00
{
return TRUE ;
}
2016-07-31 15:48:50 +02:00
if ( SquadEnemySplit ( ) )
2016-06-04 15:24:23 +02:00
{
// if the squad members aren't all fighting the same enemy, slots are disabled
// so that a squad member doesn't get stranded unable to engage his enemy because
// all of the attack slots are taken by squad members fighting other enemies.
m_iMySlot = bits_SLOT_SQUAD_SPLIT ;
return TRUE ;
}
CSquadMonster * pSquadLeader = MySquadLeader ( ) ;
2016-07-31 15:48:50 +02:00
if ( ! ( iDesiredSlots ^ pSquadLeader - > m_afSquadSlots ) )
2016-06-04 15:24:23 +02:00
{
// none of the desired slots are available.
return FALSE ;
}
iSquadSlots = pSquadLeader - > m_afSquadSlots ;
2016-07-31 15:48:50 +02:00
for ( i = 0 ; i < NUM_SLOTS ; i + + )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
iMask = 1 < < i ;
if ( iDesiredSlots & iMask ) // am I looking for this bit?
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( ! ( iSquadSlots & iMask ) ) // Is it already taken?
2016-06-04 15:24:23 +02:00
{
// No, use this bit
pSquadLeader - > m_afSquadSlots | = iMask ;
m_iMySlot = iMask ;
2016-07-31 15:48:50 +02:00
//ALERT( at_aiconsole, "Took slot %d - %d\n", i, m_hSquadLeader->m_afSquadSlots );
2016-06-04 15:24:23 +02:00
return TRUE ;
}
}
}
return FALSE ;
}
//=========================================================
2016-07-31 15:48:50 +02:00
// VacateSlot
2016-06-04 15:24:23 +02:00
//=========================================================
2016-07-31 15:48:50 +02:00
void CSquadMonster : : VacateSlot ( )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( m_iMySlot ! = bits_NO_SLOT & & InSquad ( ) )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
//ALERT( at_aiconsole, "Vacated Slot %d - %d\n", m_iMySlot, m_hSquadLeader->m_afSquadSlots );
2016-06-04 15:24:23 +02:00
MySquadLeader ( ) - > m_afSquadSlots & = ~ m_iMySlot ;
m_iMySlot = bits_NO_SLOT ;
}
}
//=========================================================
// ScheduleChange
//=========================================================
2016-07-31 15:48:50 +02:00
void CSquadMonster : : ScheduleChange ( void )
2016-06-04 15:24:23 +02:00
{
VacateSlot ( ) ;
}
//=========================================================
// Killed
//=========================================================
2016-07-31 15:48:50 +02:00
void CSquadMonster : : Killed ( entvars_t * pevAttacker , int iGib )
2016-06-04 15:24:23 +02:00
{
VacateSlot ( ) ;
2016-07-31 15:48:50 +02:00
if ( InSquad ( ) )
2016-06-04 15:24:23 +02:00
{
MySquadLeader ( ) - > SquadRemove ( this ) ;
}
2016-07-31 15:48:50 +02:00
CBaseMonster : : Killed ( pevAttacker , iGib ) ;
2016-06-04 15:24:23 +02:00
}
// These functions are still awaiting conversion to CSquadMonster
//=========================================================
//
// SquadRemove(), remove pRemove from my squad.
// If I am pRemove, promote m_pSquadNext to leader
//
//=========================================================
2016-07-31 15:48:50 +02:00
void CSquadMonster : : SquadRemove ( CSquadMonster * pRemove )
2016-06-04 15:24:23 +02:00
{
ASSERT ( pRemove ! = NULL ) ;
ASSERT ( this - > IsLeader ( ) ) ;
ASSERT ( pRemove - > m_hSquadLeader = = this ) ;
// If I'm the leader, get rid of my squad
2016-07-31 15:48:50 +02:00
if ( pRemove = = MySquadLeader ( ) )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
for ( int i = 0 ; i < MAX_SQUAD_MEMBERS - 1 ; i + + )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
CSquadMonster * pMember = MySquadMember ( i ) ;
if ( pMember )
2016-06-04 15:24:23 +02:00
{
pMember - > m_hSquadLeader = NULL ;
m_hSquadMember [ i ] = NULL ;
}
}
}
else
{
CSquadMonster * pSquadLeader = MySquadLeader ( ) ;
2016-07-31 15:48:50 +02:00
if ( pSquadLeader )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
for ( int i = 0 ; i < MAX_SQUAD_MEMBERS - 1 ; i + + )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( pSquadLeader - > m_hSquadMember [ i ] = = this )
2016-06-04 15:24:23 +02:00
{
pSquadLeader - > m_hSquadMember [ i ] = NULL ;
break ;
}
}
}
}
pRemove - > m_hSquadLeader = NULL ;
}
//=========================================================
//
// SquadAdd(), add pAdd to my squad
//
//=========================================================
2016-07-31 15:48:50 +02:00
BOOL CSquadMonster : : SquadAdd ( CSquadMonster * pAdd )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
ASSERT ( pAdd ! = NULL ) ;
2016-06-04 15:24:23 +02:00
ASSERT ( ! pAdd - > InSquad ( ) ) ;
ASSERT ( this - > IsLeader ( ) ) ;
2016-07-31 15:48:50 +02:00
for ( int i = 0 ; i < MAX_SQUAD_MEMBERS - 1 ; i + + )
2016-06-04 15:24:23 +02:00
{
2017-06-29 15:56:03 +02:00
if ( m_hSquadMember [ i ] = = 0 )
2016-06-04 15:24:23 +02:00
{
m_hSquadMember [ i ] = pAdd ;
pAdd - > m_hSquadLeader = this ;
return TRUE ;
}
}
return FALSE ;
// should complain here
}
//=========================================================
//
// SquadPasteEnemyInfo - called by squad members that have
// current info on the enemy so that it can be stored for
// members who don't have current info.
//
//=========================================================
2016-07-31 15:48:50 +02:00
void CSquadMonster : : SquadPasteEnemyInfo ( void )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
CSquadMonster * pSquadLeader = MySquadLeader ( ) ;
if ( pSquadLeader )
2016-06-04 15:24:23 +02:00
pSquadLeader - > m_vecEnemyLKP = m_vecEnemyLKP ;
}
//=========================================================
//
// SquadCopyEnemyInfo - called by squad members who don't
// have current info on the enemy. Reads from the same fields
// in the leader's data that other squad members write to,
// so the most recent data is always available here.
//
//=========================================================
2016-07-31 15:48:50 +02:00
void CSquadMonster : : SquadCopyEnemyInfo ( void )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
CSquadMonster * pSquadLeader = MySquadLeader ( ) ;
if ( pSquadLeader )
2016-06-04 15:24:23 +02:00
m_vecEnemyLKP = pSquadLeader - > m_vecEnemyLKP ;
}
//=========================================================
//
// SquadMakeEnemy - makes everyone in the squad angry at
// the same entity.
//
//=========================================================
2016-07-31 15:48:50 +02:00
void CSquadMonster : : SquadMakeEnemy ( CBaseEntity * pEnemy )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( ! InSquad ( ) )
2016-06-04 15:24:23 +02:00
return ;
2016-07-31 15:48:50 +02:00
if ( ! pEnemy )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
ALERT ( at_console , " ERROR: SquadMakeEnemy() - pEnemy is NULL! \n " ) ;
2016-06-04 15:24:23 +02:00
return ;
}
2016-07-31 15:48:50 +02:00
CSquadMonster * pSquadLeader = MySquadLeader ( ) ;
for ( int i = 0 ; i < MAX_SQUAD_MEMBERS ; i + + )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
CSquadMonster * pMember = pSquadLeader - > MySquadMember ( i ) ;
if ( pMember )
2016-06-04 15:24:23 +02:00
{
// reset members who aren't activly engaged in fighting
2016-07-31 15:48:50 +02:00
if ( pMember - > m_hEnemy ! = pEnemy & & ! pMember - > HasConditions ( bits_COND_SEE_ENEMY ) )
2016-06-04 15:24:23 +02:00
{
2017-06-29 15:56:03 +02:00
if ( pMember - > m_hEnemy ! = 0 )
2016-06-04 15:24:23 +02:00
{
// remember their current enemy
pMember - > PushEnemy ( pMember - > m_hEnemy , pMember - > m_vecEnemyLKP ) ;
}
// give them a new enemy
pMember - > m_hEnemy = pEnemy ;
pMember - > m_vecEnemyLKP = pEnemy - > pev - > origin ;
2016-07-31 15:48:50 +02:00
pMember - > SetConditions ( bits_COND_NEW_ENEMY ) ;
2016-06-04 15:24:23 +02:00
}
}
}
}
//=========================================================
//
// SquadCount(), return the number of members of this squad
// callable from leaders & followers
//
//=========================================================
2016-07-31 15:48:50 +02:00
int CSquadMonster : : SquadCount ( void )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( ! InSquad ( ) )
2016-06-04 15:24:23 +02:00
return 0 ;
CSquadMonster * pSquadLeader = MySquadLeader ( ) ;
int squadCount = 0 ;
2016-07-31 15:48:50 +02:00
for ( int i = 0 ; i < MAX_SQUAD_MEMBERS ; i + + )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( pSquadLeader - > MySquadMember ( i ) ! = NULL )
2016-06-04 15:24:23 +02:00
squadCount + + ;
}
return squadCount ;
}
//=========================================================
//
// SquadRecruit(), get some monsters of my classification and
// link them as a group. returns the group size
//
//=========================================================
2016-07-31 15:48:50 +02:00
int CSquadMonster : : SquadRecruit ( int searchRadius , int maxMembers )
2016-06-04 15:24:23 +02:00
{
int squadCount ;
int iMyClass = Classify ( ) ; // cache this monster's class
// Don't recruit if I'm already in a group
2016-07-31 15:48:50 +02:00
if ( InSquad ( ) )
2016-06-04 15:24:23 +02:00
return 0 ;
2016-07-31 15:48:50 +02:00
if ( maxMembers < 2 )
2016-06-04 15:24:23 +02:00
return 0 ;
// I am my own leader
m_hSquadLeader = this ;
squadCount = 1 ;
CBaseEntity * pEntity = NULL ;
2016-07-31 15:48:50 +02:00
if ( ! FStringNull ( pev - > netname ) )
2016-06-04 15:24:23 +02:00
{
// I have a netname, so unconditionally recruit everyone else with that name.
pEntity = UTIL_FindEntityByString ( pEntity , " netname " , STRING ( pev - > netname ) ) ;
2016-07-31 15:48:50 +02:00
while ( pEntity )
2016-06-04 15:24:23 +02:00
{
CSquadMonster * pRecruit = pEntity - > MySquadMonsterPointer ( ) ;
2016-07-31 15:48:50 +02:00
if ( pRecruit )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( ! pRecruit - > InSquad ( ) & & pRecruit - > Classify ( ) = = iMyClass & & pRecruit ! = this )
2016-06-04 15:24:23 +02:00
{
// minimum protection here against user error.in worldcraft.
2016-07-31 15:48:50 +02:00
if ( ! SquadAdd ( pRecruit ) )
2016-06-04 15:24:23 +02:00
break ;
squadCount + + ;
}
}
2016-06-25 18:33:39 +02:00
2016-06-04 15:24:23 +02:00
pEntity = UTIL_FindEntityByString ( pEntity , " netname " , STRING ( pev - > netname ) ) ;
}
}
else
{
2016-07-31 15:48:50 +02:00
while ( ( pEntity = UTIL_FindEntityInSphere ( pEntity , pev - > origin , searchRadius ) ) ! = NULL )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
CSquadMonster * pRecruit = pEntity - > MySquadMonsterPointer ( ) ;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
if ( pRecruit & & pRecruit ! = this & & pRecruit - > IsAlive ( ) & & ! pRecruit - > m_pCine )
2016-06-04 15:24:23 +02:00
{
// Can we recruit this guy?
2016-07-31 15:48:50 +02:00
if ( ! pRecruit - > InSquad ( ) & & pRecruit - > Classify ( ) = = iMyClass & &
( ( iMyClass ! = CLASS_ALIEN_MONSTER ) | | FStrEq ( STRING ( pev - > classname ) , STRING ( pRecruit - > pev - > classname ) ) ) & &
2016-06-04 15:24:23 +02:00
FStringNull ( pRecruit - > pev - > netname ) )
{
TraceResult tr ;
UTIL_TraceLine ( pev - > origin + pev - > view_ofs , pRecruit - > pev - > origin + pev - > view_ofs , ignore_monsters , pRecruit - > edict ( ) , & tr ) ; // try to hit recruit with a traceline.
2019-10-13 13:49:25 +02:00
if ( tr . flFraction = = 1.0f )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( ! SquadAdd ( pRecruit ) )
2016-06-04 15:24:23 +02:00
break ;
squadCount + + ;
}
}
}
}
}
// no single member squads
2016-07-31 15:48:50 +02:00
if ( squadCount = = 1 )
2016-06-04 15:24:23 +02:00
{
m_hSquadLeader = NULL ;
}
return squadCount ;
}
//=========================================================
// CheckEnemy
//=========================================================
2016-07-31 15:48:50 +02:00
int CSquadMonster : : CheckEnemy ( CBaseEntity * pEnemy )
2016-06-04 15:24:23 +02:00
{
int iUpdatedLKP ;
2016-07-31 15:48:50 +02:00
iUpdatedLKP = CBaseMonster : : CheckEnemy ( m_hEnemy ) ;
2016-06-04 15:24:23 +02:00
// communicate with squad members about the enemy IF this individual has the same enemy as the squad leader.
2016-07-31 15:48:50 +02:00
if ( InSquad ( ) & & ( CBaseEntity * ) m_hEnemy = = MySquadLeader ( ) - > m_hEnemy )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( iUpdatedLKP )
2016-06-04 15:24:23 +02:00
{
// have new enemy information, so paste to the squad.
SquadPasteEnemyInfo ( ) ;
}
else
{
// enemy unseen, copy from the squad knowledge.
SquadCopyEnemyInfo ( ) ;
}
}
return iUpdatedLKP ;
}
//=========================================================
// StartMonster
//=========================================================
2016-07-31 15:48:50 +02:00
void CSquadMonster : : StartMonster ( void )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
CBaseMonster : : StartMonster ( ) ;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
if ( ( m_afCapability & bits_CAP_SQUAD ) & & ! InSquad ( ) )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( ! FStringNull ( pev - > netname ) )
2016-06-04 15:24:23 +02:00
{
// if I have a groupname, I can only recruit if I'm flagged as leader
2016-07-31 15:48:50 +02:00
if ( ! ( pev - > spawnflags & SF_SQUADMONSTER_LEADER ) )
2016-06-04 15:24:23 +02:00
{
return ;
}
}
// try to form squads now.
int iSquadSize = SquadRecruit ( 1024 , 4 ) ;
2016-07-31 15:48:50 +02:00
if ( iSquadSize )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
ALERT ( at_aiconsole , " Squad of %d %s formed \n " , iSquadSize , STRING ( pev - > classname ) ) ;
2016-06-04 15:24:23 +02:00
}
2016-07-31 15:48:50 +02:00
if ( IsLeader ( ) & & FClassnameIs ( pev , " monster_human_grunt " ) )
2016-06-04 15:24:23 +02:00
{
SetBodygroup ( 1 , 1 ) ; // UNDONE: truly ugly hack
pev - > skin = 0 ;
}
}
}
//=========================================================
// NoFriendlyFire - checks for possibility of friendly fire
//
// Builds a large box in front of the grunt and checks to see
// if any squad members are in that box.
//=========================================================
2016-07-31 15:48:50 +02:00
BOOL CSquadMonster : : NoFriendlyFire ( void )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( ! InSquad ( ) )
2016-06-04 15:24:23 +02:00
{
return TRUE ;
}
2016-07-31 15:48:50 +02:00
CPlane backPlane ;
CPlane leftPlane ;
CPlane rightPlane ;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
Vector vecLeftSide ;
Vector vecRightSide ;
Vector v_left ;
2019-10-13 13:49:25 +02:00
Vector v_dir ;
2016-06-04 15:24:23 +02:00
//!!!BUGBUG - to fix this, the planes must be aligned to where the monster will be firing its gun, not the direction it is facing!!!
2017-06-29 15:56:03 +02:00
if ( m_hEnemy ! = 0 )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
UTIL_MakeVectors ( UTIL_VecToAngles ( m_hEnemy - > Center ( ) - pev - > origin ) ) ;
2016-06-04 15:24:23 +02:00
}
else
{
// if there's no enemy, pretend there's a friendly in the way, so the grunt won't shoot.
return FALSE ;
}
2016-07-31 15:48:50 +02:00
//UTIL_MakeVectors( pev->angles );
2019-10-13 13:49:25 +02:00
// vecLeftSide = pev->origin - ( gpGlobals->v_right * ( pev->size.x * 1.5f ) );
// vecRightSide = pev->origin + ( gpGlobals->v_right * ( pev->size.x * 1.5f ) );
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 ;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
leftPlane . InitializePlane ( gpGlobals - > v_right , vecLeftSide ) ;
rightPlane . InitializePlane ( v_left , vecRightSide ) ;
backPlane . InitializePlane ( gpGlobals - > v_forward , pev - > origin ) ;
2016-06-04 15:24:23 +02:00
/*
2016-07-31 15:48:50 +02:00
ALERT ( at_console , " LeftPlane: %f %f %f : %f \n " , leftPlane . m_vecNormal . x , leftPlane . m_vecNormal . y , leftPlane . m_vecNormal . z , leftPlane . m_flDist ) ;
ALERT ( at_console , " RightPlane: %f %f %f : %f \n " , rightPlane . m_vecNormal . x , rightPlane . m_vecNormal . y , rightPlane . m_vecNormal . z , rightPlane . m_flDist ) ;
ALERT ( at_console , " BackPlane: %f %f %f : %f \n " , backPlane . m_vecNormal . x , backPlane . m_vecNormal . y , backPlane . m_vecNormal . z , backPlane . m_flDist ) ;
2016-06-04 15:24:23 +02:00
*/
CSquadMonster * pSquadLeader = MySquadLeader ( ) ;
2016-07-31 15:48:50 +02:00
for ( int i = 0 ; i < MAX_SQUAD_MEMBERS ; i + + )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
CSquadMonster * pMember = pSquadLeader - > MySquadMember ( i ) ;
if ( pMember & & pMember ! = this )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( backPlane . PointInFront ( pMember - > pev - > origin ) & &
leftPlane . PointInFront ( pMember - > pev - > origin ) & &
rightPlane . PointInFront ( pMember - > pev - > origin ) )
2016-06-04 15:24:23 +02:00
{
// this guy is in the check volume! Don't shoot!
return FALSE ;
}
}
}
return TRUE ;
}
//=========================================================
// GetIdealState - surveys the Conditions information available
// and finds the best new state for a monster.
//=========================================================
2016-07-31 15:48:50 +02:00
MONSTERSTATE CSquadMonster : : GetIdealState ( void )
2016-06-04 15:24:23 +02:00
{
2017-06-29 15:56:03 +02:00
IScheduleFlags ( ) ;
2016-06-25 18:33:39 +02:00
2016-06-04 15:24:23 +02:00
// If no schedule conditions, the new ideal state is probably the reason we're in here.
2016-07-31 15:48:50 +02:00
switch ( m_MonsterState )
2016-06-04 15:24:23 +02:00
{
case MONSTERSTATE_IDLE :
case MONSTERSTATE_ALERT :
2016-07-31 15:48:50 +02:00
if ( HasConditions ( bits_COND_NEW_ENEMY ) & & InSquad ( ) )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
SquadMakeEnemy ( m_hEnemy ) ;
2016-06-04 15:24:23 +02:00
}
break ;
2016-06-13 16:29:45 +02:00
default :
break ;
2016-06-04 15:24:23 +02:00
}
2016-07-31 15:48:50 +02:00
return CBaseMonster : : GetIdealState ( ) ;
2016-06-04 15:24:23 +02:00
}
//=========================================================
// FValidateCover - determines whether or not the chosen
// cover location is a good one to move to. (currently based
// on proximity to others in the squad)
//=========================================================
2016-07-31 15:48:50 +02:00
BOOL CSquadMonster : : FValidateCover ( const Vector & vecCoverLocation )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( ! InSquad ( ) )
2016-06-04 15:24:23 +02:00
{
return TRUE ;
}
2016-07-31 15:48:50 +02:00
if ( SquadMemberInRange ( vecCoverLocation , 128 ) )
2016-06-04 15:24:23 +02:00
{
// another squad member is too close to this piece of cover.
return FALSE ;
}
return TRUE ;
}
//=========================================================
// SquadEnemySplit- returns TRUE if not all squad members
// are fighting the same enemy.
//=========================================================
2016-07-31 15:48:50 +02:00
BOOL CSquadMonster : : SquadEnemySplit ( void )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( ! InSquad ( ) )
2016-06-04 15:24:23 +02:00
return FALSE ;
2016-07-31 15:48:50 +02:00
CSquadMonster * pSquadLeader = MySquadLeader ( ) ;
CBaseEntity * pEnemy = pSquadLeader - > m_hEnemy ;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
for ( int i = 0 ; i < MAX_SQUAD_MEMBERS ; i + + )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
CSquadMonster * pMember = pSquadLeader - > MySquadMember ( i ) ;
2017-06-29 15:56:03 +02:00
if ( pMember ! = NULL & & pMember - > m_hEnemy ! = 0 & & pMember - > m_hEnemy ! = pEnemy )
2016-06-04 15:24:23 +02:00
{
return TRUE ;
}
}
return FALSE ;
}
//=========================================================
// FValidateCover - determines whether or not the chosen
// cover location is a good one to move to. (currently based
// on proximity to others in the squad)
//=========================================================
2016-07-31 15:48:50 +02:00
BOOL CSquadMonster : : SquadMemberInRange ( const Vector & vecLocation , float flDist )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if ( ! InSquad ( ) )
2016-06-04 15:24:23 +02:00
return FALSE ;
CSquadMonster * pSquadLeader = MySquadLeader ( ) ;
2016-07-31 15:48:50 +02:00
for ( int i = 0 ; i < MAX_SQUAD_MEMBERS ; i + + )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
CSquadMonster * pSquadMember = pSquadLeader - > MySquadMember ( i ) ;
if ( pSquadMember & & ( vecLocation - pSquadMember - > pev - > origin ) . Length2D ( ) < = flDist )
2016-06-04 15:24:23 +02:00
return TRUE ;
}
return FALSE ;
}
2016-07-31 15:48:50 +02:00
extern Schedule_t slChaseEnemyFailed [ ] ;
2016-06-04 15:24:23 +02:00
Schedule_t * CSquadMonster : : GetScheduleOfType ( int iType )
{
2016-07-31 15:48:50 +02:00
switch ( iType )
2016-06-04 15:24:23 +02:00
{
case SCHED_CHASE_ENEMY_FAILED :
{
2016-07-31 15:48:50 +02:00
return & slChaseEnemyFailed [ 0 ] ;
2016-06-04 15:24:23 +02:00
}
default :
return CBaseMonster : : GetScheduleOfType ( iType ) ;
}
}