Example #1
0
//=========================================================
//
// SquadMakeEnemy - makes everyone in the squad angry at
// the same entity.
//
//=========================================================
void CSquadMonster :: SquadMakeEnemy ( CBaseEntity *pEnemy )
{
    if (!InSquad())
        return;

    if ( !pEnemy )
    {
        ALERT ( at_console, "ERROR: SquadMakeEnemy() - pEnemy is NULL!\n" );
        return;
    }

    CSquadMonster *pSquadLeader = MySquadLeader( );
    for (int i = 0; i < MAX_SQUAD_MEMBERS; i++)
    {
        CSquadMonster *pMember = pSquadLeader->MySquadMember(i);
        if (pMember)
        {
            // reset members who aren't activly engaged in fighting
            if (pMember->m_hEnemy != pEnemy && !pMember->HasConditions( bits_COND_SEE_ENEMY))
            {
                if ( pMember->m_hEnemy != NULL)
                {
                    // 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;
                pMember->SetConditions ( bits_COND_NEW_ENEMY );
            }
        }
    }
}
Example #2
0
//=========================================================
// StartMonster
//=========================================================
void CSquadMonster :: StartMonster( void )
{
	CBaseMonster :: StartMonster();

	if ( ( m_afCapability & bits_CAP_SQUAD ) && !InSquad() )
	{
		if ( HasNetName() )
		{
			// if I have a groupname, I can only recruit if I'm flagged as leader
			if ( !GetSpawnFlags().Any( SF_SQUADMONSTER_LEADER ) )
			{
				return;
			}
		}

		// try to form squads now.
		int iSquadSize = SquadRecruit( 1024, 4 );

		if ( iSquadSize )
		{
		  ALERT ( at_aiconsole, "Squad of %d %s formed\n", iSquadSize, GetClassname() );
		}

		if ( IsLeader() && ClassnameIs( "monster_human_grunt" ) )
		{
			SetBodygroup( 1, 1 ); // UNDONE: truly ugly hack
			SetSkin( 0 );
		}

	}
}
Example #3
0
//=========================================================
// StartMonster
//=========================================================
void CSquadMonster :: StartMonster( void )
{
    CBaseMonster :: StartMonster();

    if ( ( m_afCapability & bits_CAP_SQUAD ) && !InSquad() )
    {
        if ( !FStringNull( pev->netname ) )
        {
            // if I have a groupname, I can only recruit if I'm flagged as leader
            if ( !( pev->spawnflags & SF_SQUADMONSTER_LEADER ) )
            {
                return;
            }
        }

        // try to form squads now.
        int iSquadSize = SquadRecruit( 1024, 4 );

        if ( iSquadSize )
        {
            ALERT ( at_aiconsole, "Squad of %d %s formed\n", iSquadSize, STRING( pev->classname ) );
        }

        if ( IsLeader() && FClassnameIs ( pev, "monster_human_grunt" ) )
        {
            SetBodygroup( 1, 1 ); // UNDONE: truly ugly hack
            pev->skin = 0;
        }

    }
}
//=========================================================
// Leader boid calls this to form a flock from surrounding boids
//=========================================================
void CFlockingFlyer :: FormFlock( void )
{
	if ( !InSquad() )
	{
		// I am my own leader
		m_pSquadLeader = this;
		m_pSquadNext = NULL;
		int squadCount = 1;

		CBaseEntity *pEntity = NULL;
		
		while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, AFLOCK_MAX_RECRUIT_RADIUS )) != NULL)
		{
			CBaseMonster *pRecruit = pEntity->MyMonsterPointer( );

			if ( pRecruit && pRecruit != this && pRecruit->IsAlive() && !pRecruit->m_pCine )
			{
				// Can we recruit this guy?
				if ( FClassnameIs ( pRecruit->pev, "monster_flyer" ) )
				{
					squadCount++;
					SquadAdd( (CFlockingFlyer *)pRecruit );
				}
			}
		}
	}

	SetThink( &CFlockingFlyer::IdleThink );// now that flock is formed, go to idle and wait for a player to come along.
	pev->nextthink = gpGlobals->time;
}
Example #5
0
//=========================================================
// VacateSlot
//=========================================================
void CSquadMonster :: VacateSlot()
{
    if ( m_iMySlot != bits_NO_SLOT && InSquad() )
    {
//		ALERT ( at_aiconsole, "Vacated Slot %d - %d\n", m_iMySlot, m_hSquadLeader->m_afSquadSlots );
        MySquadLeader()->m_afSquadSlots &= ~m_iMySlot;
        m_iMySlot = bits_NO_SLOT;
    }
}
Example #6
0
//=========================================================
// Killed
//=========================================================
void CSquadMonster :: Killed( entvars_t *pevAttacker, int iGib )
{
    VacateSlot();

    if ( InSquad() )
    {
        MySquadLeader()->SquadRemove( this );
    }

    CBaseMonster :: Killed ( pevAttacker, iGib );
}
Example #7
0
//=========================================================
// Killed
//=========================================================
void CSquadMonster::Killed( const CTakeDamageInfo& info, GibAction gibAction )
{
	VacateSlot();

	if ( InSquad() )
	{
		MySquadLeader()->SquadRemove( this );
	}

	CBaseMonster::Killed( info, gibAction );
}
Example #8
0
//=========================================================
//
// SquadCount(), return the number of members of this squad
// callable from leaders & followers
//
//=========================================================
int CSquadMonster :: SquadCount( void )
{
    if (!InSquad())
        return 0;

    CSquadMonster *pSquadLeader = MySquadLeader();
    int squadCount = 0;
    for (int i = 0; i < MAX_SQUAD_MEMBERS; i++)
    {
        if (pSquadLeader->MySquadMember(i) != NULL)
            squadCount++;
    }

    return squadCount;
}
Example #9
0
//=========================================================
// 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)
//=========================================================
BOOL CSquadMonster :: SquadMemberInRange ( const Vector &vecLocation, float flDist )
{
    if (!InSquad())
        return FALSE;

    CSquadMonster *pSquadLeader = MySquadLeader();

    for (int i = 0; i < MAX_SQUAD_MEMBERS; i++)
    {
        CSquadMonster *pSquadMember = pSquadLeader->MySquadMember(i);
        if (pSquadMember && (vecLocation - pSquadMember->pev->origin ).Length2D() <= flDist)
            return TRUE;
    }
    return FALSE;
}
Example #10
0
//=========================================================
// 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)
//=========================================================
BOOL CSquadMonster :: FValidateCover ( const Vector &vecCoverLocation )
{
    if ( !InSquad() )
    {
        return TRUE;
    }

    if (SquadMemberInRange( vecCoverLocation, 128 ))
    {
        // another squad member is too close to this piece of cover.
        return FALSE;
    }

    return TRUE;
}
Example #11
0
//=========================================================
// 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)
//=========================================================
bool CSquadMonster::SquadMemberInRange( const Vector &vecLocation, float flDist )
{
	if (!InSquad())
		return false;

	CSquadMonster *pSquadLeader = MySquadLeader();

	for (int i = 0; i < MAX_SQUAD_MEMBERS; i++)
	{
		CSquadMonster *pSquadMember = pSquadLeader->MySquadMember(i);
		if (pSquadMember && (vecLocation - pSquadMember->GetAbsOrigin() ).Length2D() <= flDist)
			return true;
	}
	return false;
}
Example #12
0
//=========================================================
// OccupySlot - if any slots of the passed slots are
// available, the monster will be assigned to one.
//=========================================================
BOOL CSquadMonster :: OccupySlot( int iDesiredSlots )
{
    int i;
    int iMask;
    int iSquadSlots;

    if ( !InSquad() )
    {
        return TRUE;
    }

    if ( SquadEnemySplit() )
    {
        // 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();

    if ( !( iDesiredSlots ^ pSquadLeader->m_afSquadSlots ) )
    {
        // none of the desired slots are available.
        return FALSE;
    }

    iSquadSlots = pSquadLeader->m_afSquadSlots;

    for ( i = 0; i < NUM_SLOTS; i++ )
    {
        iMask = 1<<i;
        if ( iDesiredSlots & iMask ) // am I looking for this bit?
        {
            if ( !(iSquadSlots & iMask) )	// Is it already taken?
            {
                // No, use this bit
                pSquadLeader->m_afSquadSlots |= iMask;
                m_iMySlot = iMask;
//				ALERT ( at_aiconsole, "Took slot %d - %d\n", i, m_hSquadLeader->m_afSquadSlots );
                return TRUE;
            }
        }
    }

    return FALSE;
}
Example #13
0
//=========================================================
// SquadEnemySplit- returns TRUE if not all squad members
// are fighting the same enemy.
//=========================================================
BOOL CSquadMonster :: SquadEnemySplit ( void )
{
    if (!InSquad())
        return FALSE;

    CSquadMonster	*pSquadLeader = MySquadLeader();
    CBaseEntity		*pEnemy	= pSquadLeader->m_hEnemy;

    for (int i = 0; i < MAX_SQUAD_MEMBERS; i++)
    {
        CSquadMonster *pMember = pSquadLeader->MySquadMember(i);
        if (pMember != NULL && pMember->m_hEnemy != NULL && pMember->m_hEnemy != pEnemy)
        {
            return TRUE;
        }
    }
    return FALSE;
}
Example #14
0
//=========================================================
// SquadEnemySplit- returns true if not all squad members
// are fighting the same enemy. 
//=========================================================
bool CSquadMonster::SquadEnemySplit()
{
	if (!InSquad())
		return false;

	CSquadMonster	*pSquadLeader = MySquadLeader();
	CBaseEntity		*pEnemy	= pSquadLeader->m_hEnemy;

	for (int i = 0; i < MAX_SQUAD_MEMBERS; i++)
	{
		CSquadMonster *pMember = pSquadLeader->MySquadMember(i);
		if (pMember != NULL && pMember->m_hEnemy != NULL && pMember->m_hEnemy != pEnemy)
		{
			return true;
		}
	}
	return false;
}
Example #15
0
//=========================================================
// WriteBeamColor - writes a color vector to the network 
// based on the size of the group. 
//=========================================================
void CHoundeye :: WriteBeamColor ( void )
{
	BYTE	bRed, bGreen, bBlue;

	if ( InSquad() )
	{
		switch ( SquadCount() )
		{
		case 2:
			// no case for 0 or 1, cause those are impossible for monsters in Squads.
			bRed	= 101;
			bGreen	= 133;
			bBlue	= 221;
			break;
		case 3:
			bRed	= 67;
			bGreen	= 85;
			bBlue	= 255;
			break;
		case 4:
			bRed	= 62;
			bGreen	= 33;
			bBlue	= 211;
			break;
		default:
			ALERT ( at_aiconsole, "Unsupported Houndeye SquadSize!\n" );
			bRed	= 188;
			bGreen	= 220;
			bBlue	= 255;
			break;
		}
	}
	else
	{
		// solo houndeye - weakest beam
		bRed	= 188;
		bGreen	= 220;
		bBlue	= 255;
	}
	
	WRITE_BYTE( bRed   );
	WRITE_BYTE( bGreen );
	WRITE_BYTE( bBlue  );
}
Example #16
0
//=========================================================
// GetIdealState - surveys the Conditions information available
// and finds the best new state for a monster.
//=========================================================
MONSTERSTATE CSquadMonster :: GetIdealState ( void )
{
    int	iConditions;

    iConditions = IScheduleFlags();

    // If no schedule conditions, the new ideal state is probably the reason we're in here.
    switch ( m_MonsterState )
    {
    case MONSTERSTATE_IDLE:
    case MONSTERSTATE_ALERT:
        if ( HasConditions ( bits_COND_NEW_ENEMY ) && InSquad() )
        {
            SquadMakeEnemy ( m_hEnemy );
        }
        break;
    }

    return CBaseMonster :: GetIdealState();
}
Example #17
0
//=========================================================
// CheckEnemy
//=========================================================
bool CSquadMonster::CheckEnemy( CBaseEntity *pEnemy )
{
	bool bUpdatedLKP = CBaseMonster::CheckEnemy( m_hEnemy );
	
	// communicate with squad members about the enemy IF this individual has the same enemy as the squad leader.
	if ( InSquad() && (CBaseEntity *)m_hEnemy == MySquadLeader()->m_hEnemy )
	{
		if ( bUpdatedLKP )
		{
			// have new enemy information, so paste to the squad.
			SquadPasteEnemyInfo();
		}
		else
		{
			// enemy unseen, copy from the squad knowledge.
			SquadCopyEnemyInfo();
		}
	}

	return bUpdatedLKP;
}
Example #18
0
//=========================================================
// AlertSound 
//=========================================================
void CHoundeye :: AlertSound ( void )
{

	if ( InSquad() && !IsLeader() )
	{
		return; // only leader makes ALERT sound.
	}

	switch ( RANDOM_LONG(0,2) )
	{
	case 0:	
		EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_alert1.wav", 1, ATTN_NORM );	
		break;
	case 1:	
		EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_alert2.wav", 1, ATTN_NORM );	
		break;
	case 2:	
		EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_alert3.wav", 1, ATTN_NORM );	
		break;
	}
}
Example #19
0
//=========================================================
// FCanActiveIdle
//=========================================================
BOOL CHoundeye :: FCanActiveIdle ( void )
{
	if ( InSquad() )
	{
		CSquadMonster *pSquadLeader = MySquadLeader();

		for (int i = 0; i < MAX_SQUAD_MEMBERS;i++)
		{
			CSquadMonster *pMember = pSquadLeader->MySquadMember(i);
			 
			if ( pMember != NULL && pMember != this && pMember->m_iHintNode != NO_NODE )
			{
				// someone else in the group is active idling right now!
				return FALSE;
			}
		}

		return TRUE;
	}

	return TRUE;
}
Example #20
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.
//=========================================================
BOOL CSquadMonster :: NoFriendlyFire( void )
{
    if ( !InSquad() )
    {
        return TRUE;
    }

    CPlane	backPlane;
    CPlane  leftPlane;
    CPlane	rightPlane;

    Vector	vecLeftSide;
    Vector	vecRightSide;
    Vector	v_left;

    //!!!BUGBUG - to fix this, the planes must be aligned to where the monster will be firing its gun, not the direction it is facing!!!

    if ( m_hEnemy != NULL )
    {
        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;
    }

    //UTIL_MakeVectors ( pev->angles );

    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;

    leftPlane.InitializePlane ( gpGlobals->v_right, vecLeftSide );
    rightPlane.InitializePlane ( v_left, vecRightSide );
    backPlane.InitializePlane ( gpGlobals->v_forward, pev->origin );

    /*
    	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 );
    */

    CSquadMonster *pSquadLeader = MySquadLeader();
    for (int i = 0; i < MAX_SQUAD_MEMBERS; i++)
    {
        CSquadMonster *pMember = pSquadLeader->MySquadMember(i);
        if (pMember && pMember != this)
        {

            if ( backPlane.PointInFront  ( pMember->pev->origin ) &&
                    leftPlane.PointInFront  ( pMember->pev->origin ) &&
                    rightPlane.PointInFront ( pMember->pev->origin) )
            {
                // this guy is in the check volume! Don't shoot!
                return FALSE;
            }
        }
    }

    return TRUE;
}
Example #21
0
//=========================================================
// GetScheduleOfType 
//=========================================================
Schedule_t* CHoundeye :: GetScheduleOfType ( int Type ) 
{
	if ( m_fAsleep )
	{
		// if the hound is sleeping, must wake and stand!
		if ( HasConditions( bits_COND_HEAR_SOUND ) )
		{
			CSound *pWakeSound;

			pWakeSound = PBestSound();
			ASSERT( pWakeSound != NULL );
			if ( pWakeSound )
			{
				MakeIdealYaw ( pWakeSound->m_vecOrigin );

				if ( FLSoundVolume ( pWakeSound ) >= HOUNDEYE_SOUND_STARTLE_VOLUME )
				{
					// awakened by a loud sound
					return &slHoundWakeUrgent[ 0 ];
				}
			}
			// sound was not loud enough to scare the bejesus out of houndeye
			return &slHoundWakeLazy[ 0 ];
		}
		else if ( HasConditions( bits_COND_NEW_ENEMY ) )
		{
			// get up fast, to fight.
			return &slHoundWakeUrgent[ 0 ];
		}

		else
		{
			// hound is waking up on its own
			return &slHoundWakeLazy[ 0 ];
		}
	}
	switch	( Type )
	{
	case SCHED_IDLE_STAND:
		{
			// we may want to sleep instead of stand!
			if ( InSquad() && !IsLeader() && !m_fAsleep && RANDOM_LONG(0,29) < 1 )
			{
				return &slHoundSleep[ 0 ];
			}
			else
			{
				return CSquadMonster :: GetScheduleOfType( Type );
			}
		}
	case SCHED_RANGE_ATTACK1:
		{
			return &slHoundRangeAttack[ 0 ];
/*
			if ( InSquad() )
			{
				return &slHoundRangeAttack[ RANDOM_LONG( 0, 1 ) ];
			}

			return &slHoundRangeAttack[ 1 ];
*/
		}
	case SCHED_SPECIAL_ATTACK1:
		{
			return &slHoundSpecialAttack1[ 0 ];
		}
	case SCHED_GUARD:
		{
			return &slHoundGuardPack[ 0 ];
		}
	case SCHED_HOUND_AGITATED:
		{
			return &slHoundAgitated[ 0 ];
		}
	case SCHED_HOUND_HOP_RETREAT:
		{
			return &slHoundHopRetreat[ 0 ];
		}
	case SCHED_FAIL:
		{
			if ( m_MonsterState == MONSTERSTATE_COMBAT )
			{
				if ( !FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) )
				{
					// client in PVS
					return &slHoundCombatFailPVS[ 0 ];
				}
				else
				{
					// client has taken off! 
					return &slHoundCombatFailNoPVS[ 0 ];
				}
			}
			else
			{
				return CSquadMonster :: GetScheduleOfType ( Type );
			}
		}
	default:
		{
			return CSquadMonster :: GetScheduleOfType ( Type );
		}
	}
}
Example #22
0
//=========================================================
//
// SquadRecruit(), get some monsters of my classification and
// link them as a group.  returns the group size
//
//=========================================================
int CSquadMonster :: SquadRecruit( int searchRadius, int maxMembers )
{
    int squadCount;
    int iMyClass = Classify();// cache this monster's class


    // Don't recruit if I'm already in a group
    if ( InSquad() )
        return 0;

    if ( maxMembers < 2 )
        return 0;

    // I am my own leader
    m_hSquadLeader = this;
    squadCount = 1;

    CBaseEntity *pEntity = NULL;

    if ( !FStringNull( pev->netname ) )
    {
        // I have a netname, so unconditionally recruit everyone else with that name.
        pEntity = UTIL_FindEntityByString( pEntity, "netname", STRING( pev->netname ) );
        while ( pEntity )
        {
            CSquadMonster *pRecruit = pEntity->MySquadMonsterPointer();

            if ( pRecruit )
            {
                if ( !pRecruit->InSquad() && pRecruit->Classify() == iMyClass && pRecruit != this )
                {
                    // minimum protection here against user error.in worldcraft.
                    if (!SquadAdd( pRecruit ))
                        break;
                    squadCount++;
                }
            }

            pEntity = UTIL_FindEntityByString( pEntity, "netname", STRING( pev->netname ) );
        }
    }
    else
    {
        while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, searchRadius )) != NULL)
        {
            CSquadMonster *pRecruit = pEntity->MySquadMonsterPointer( );

            if ( pRecruit && pRecruit != this && pRecruit->IsAlive() && !pRecruit->m_pCine )
            {
                // Can we recruit this guy?
                if ( !pRecruit->InSquad() && pRecruit->Classify() == iMyClass &&
                        ( (iMyClass != CLASS_ALIEN_MONSTER) || FStrEq(STRING(pev->classname), STRING(pRecruit->pev->classname))) &&
                        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.
                    if ( tr.flFraction == 1.0 )
                    {
                        if (!SquadAdd( pRecruit ))
                            break;

                        squadCount++;
                    }
                }
            }
        }
    }

    // no single member squads
    if (squadCount == 1)
    {
        m_hSquadLeader = NULL;
    }

    return squadCount;
}
//=========================================================
// follower boids execute this code when flocking
//=========================================================
void CFlockingFlyer :: FlockFollowerThink( void )	
{
	TraceResult		tr;
	Vector			vecDist;
	Vector			vecDir;
	Vector			vecDirToLeader;
	float			flDistToLeader;

	pev->nextthink = gpGlobals->time + 0.1;

	if ( IsLeader() || !InSquad() )
	{
		// the leader has been killed and this flyer suddenly finds himself the leader. 
		SetThink ( &CFlockingFlyer::FlockLeaderThink );
		return;
	}

	vecDirToLeader = ( m_pSquadLeader->pev->origin - pev->origin );
	flDistToLeader = vecDirToLeader.Length();
	
	// match heading with leader
	pev->angles = m_pSquadLeader->pev->angles;

	//
	// We can see the leader, so try to catch up to it
	//
	if ( FInViewCone ( m_pSquadLeader ) )
	{
		// if we're too far away, speed up
		if ( flDistToLeader > AFLOCK_TOO_FAR )
		{
			m_flGoalSpeed = m_pSquadLeader->pev->velocity.Length() * 1.5;
		}

		// if we're too close, slow down
		else if ( flDistToLeader < AFLOCK_TOO_CLOSE )
		{
			m_flGoalSpeed = m_pSquadLeader->pev->velocity.Length() * 0.5;
		}
	}
	else
	{
		// wait up! the leader isn't out in front, so we slow down to let him pass
		m_flGoalSpeed = m_pSquadLeader->pev->velocity.Length() * 0.5;
	}

	SpreadFlock2();

	pev->speed = pev->velocity.Length();
	pev->velocity = pev->velocity.Normalize();

	// if we are too far from leader, average a vector towards it into our current velocity
	if ( flDistToLeader > AFLOCK_TOO_FAR )
	{
		vecDirToLeader = vecDirToLeader.Normalize();
		pev->velocity = (pev->velocity + vecDirToLeader) * 0.5; 	
	}

	// clamp speeds and handle acceleration
	if ( m_flGoalSpeed > AFLOCK_FLY_SPEED * 2 )
	{
		m_flGoalSpeed  = AFLOCK_FLY_SPEED * 2;
	}

	if ( pev->speed < m_flGoalSpeed )
	{
		pev->speed += AFLOCK_ACCELERATE;
	}
	else if ( pev->speed > m_flGoalSpeed )
	{
		pev->speed -= AFLOCK_ACCELERATE;
	}

	pev->velocity = pev->velocity * pev->speed;

	BoidAdvanceFrame( );
}