2
0
mirror of https://github.com/FWGS/hlsdk-xash3d synced 2024-11-10 20:29:35 +01:00
hlsdk-xash3d/dlls/squadmonster.cpp

611 lines
16 KiB
C++
Raw Normal View History

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-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
//=========================================================
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 ),
};
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
{
2016-07-31 15:48:50 +02:00
if( m_hSquadMember[i] == NULL )
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
{
2016-07-31 15:48:50 +02:00
if( pMember->m_hEnemy != NULL )
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-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.
2016-07-31 15:48:50 +02:00
if( tr.flFraction == 1.0 )
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;
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!!!
2016-07-31 15:48:50 +02:00
if( m_hEnemy != NULL )
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 );
2016-06-04 15:24:23 +02:00
vecLeftSide = pev->origin - ( gpGlobals->v_right * ( pev->size.x * 1.5 ) );
vecRightSide = pev->origin + ( gpGlobals->v_right * ( pev->size.x * 1.5 ) );
v_left = gpGlobals->v_right * -1;
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
{
2016-07-31 15:48:50 +02:00
int iConditions;
2016-06-04 15:24:23 +02:00
iConditions = IScheduleFlags();
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 );
if( pMember != NULL && pMember->m_hEnemy != NULL && 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 );
}
}