void CCycler :: Spawn( )
{
	InitBoneControllers();
	pev->solid			= SOLID_SLIDEBOX;
	pev->movetype		= MOVETYPE_NONE;
	pev->takedamage		= DAMAGE_YES;
	pev->effects		= 0;
	pev->health			= 80000;// no cycler should die
	pev->yaw_speed		= 5;
	pev->ideal_yaw		= pev->angles.y;
	ChangeYaw( 360 );
	
	m_flFrameRate		= 75;
	m_flGroundSpeed		= 0;

	pev->nextthink		+= 1.0;

	ResetSequenceInfo( );

	if (pev->sequence != 0 || pev->frame != 0)
	{
		m_animate = 0;
		pev->framerate = 0;
	}
	else
	{
		m_animate = 1;
	}
}
// [28/7/2012] Added Monster_StepDirection ~hogsy
bool Monster_StepDirection(edict_t *ent,float yaw,float dist)
{
	vec3_t	move,oldorg;
	float	delta;

	ent->v.ideal_yaw	= yaw;
	ChangeYaw(ent);

	yaw	*= (float)pMath_PI*2/360;
	move[0] = (vec_t)cos(yaw)*dist;
	move[1] = (vec_t)sin(yaw)*dist;
	move[2] = 0;

	Math_VectorCopy(ent->v.origin,oldorg);
	if(Monster_MoveStep(ent,move,false))
	{
		delta = ent->v.angles[YAW]-ent->v.ideal_yaw;
		if(delta > 45 && delta < 315)
			Math_VectorCopy(oldorg,ent->v.origin);

		Engine.LinkEntity(ent,true);
		return true;
	}

	Engine.LinkEntity(ent,true);
	return false;
}
Exemple #3
0
//=========================================================
// roach's move function
//=========================================================
void CRoach :: Move ( float flInterval ) 
{
	float		flWaypointDist;
	Vector		vecApex;

	// local move to waypoint.
	flWaypointDist = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Length2D();
	MakeIdealYaw ( m_Route[ m_iRouteIndex ].vecLocation );

	ChangeYaw ( pev->yaw_speed );
	UTIL_MakeVectors( pev->angles );

	if ( RANDOM_LONG(0,7) == 1 )
	{
		// randomly check for blocked path.(more random load balancing)
		if ( !WALK_MOVE( ENT(pev), pev->ideal_yaw, 4, WALKMOVE_NORMAL ) )
		{
			// stuck, so just pick a new spot to run off to
			PickNewDest( m_iMode );
		}
	}
	
	WALK_MOVE( ENT(pev), pev->ideal_yaw, m_flGroundSpeed * flInterval, WALKMOVE_NORMAL );

	// if the waypoint is closer than step size, then stop after next step (ok for roach to overshoot)
	if ( flWaypointDist <= m_flGroundSpeed * flInterval )
	{
		// take truncated step and stop

		SetActivity ( ACT_IDLE );
		m_flLastLightLevel = GETENTITYILLUM( ENT ( pev ) );// this is roach's new comfortable light level

		if ( m_iMode == ROACH_SMELL_FOOD )
		{
			m_iMode = ROACH_EAT;
		}
		else
		{
			m_iMode = ROACH_IDLE;
		}
	}

	if ( RANDOM_LONG(0,149) == 1 && m_iMode != ROACH_SCARED_BY_LIGHT && m_iMode != ROACH_SMELL_FOOD )
	{
		// random skitter while moving as long as not on a b-line to get out of light or going to food
		PickNewDest( FALSE );
	}
}
Exemple #4
0
//=========================================================
// RunTask 
//=========================================================
void CHAssassin :: RunTask ( Task_t *pTask )
{
	switch ( pTask->iTask )
	{
	case TASK_ASSASSIN_FALL_TO_GROUND:
		MakeIdealYaw( m_vecEnemyLKP );
		ChangeYaw( pev->yaw_speed );

		if (m_fSequenceFinished)
		{
			if (pev->velocity.z > 0)
			{
				pev->sequence = LookupSequence( "fly_up" );
			}
			else if (HasConditions ( bits_COND_SEE_ENEMY ))
			{
				pev->sequence = LookupSequence( "fly_attack" );
				pev->frame = 0;
			}
			else
			{
				pev->sequence = LookupSequence( "fly_down" );
				pev->frame = 0;
			}
			
			ResetSequenceInfo( );
			SetYawSpeed();
		}
		if (pev->flags & FL_ONGROUND)
		{
			// ALERT( at_console, "on ground\n");
			TaskComplete( );
		}
		break;
	default: 
		CBaseMonster :: RunTask ( pTask );
		break;
	}
}
void CCycler :: Spawn( )
{
	InitBoneControllers();
	pev->solid			= SOLID_SLIDEBOX;
	
	pev->movetype		= MOVETYPE_NONE;

	pev->takedamage		= DAMAGE_YES;
	pev->effects		= 0;
	pev->health			= 80000;// no cycler should die
	pev->yaw_speed		= 5;
	pev->ideal_yaw		= pev->angles.y;
	ChangeYaw( 360 );
	
	m_flFrameRate		= 75;
	m_flGroundSpeed		= 0;

	pev->nextthink		+= 1.0;

	ResetSequenceInfo( );

	if (pev->sequence != 0 || pev->frame != 0)
	{
		m_animate = 0;
		pev->framerate = 0;
	}
	else
	{
		m_animate = 1;
	}

	if ( FClassnameIs ( pev, "cine_entity" ) )
	{
		m_bloodColor = DONT_BLEED;

		pev->origin.z += 1;
		DROP_TO_FLOOR ( ENT(pev) );
	}
}
//=========================================================
// RunTask
//=========================================================
void CBullsquid :: RunTask ( Task_t *pTask )
{
	switch ( pTask->iTask )
	{
	case TASK_SQUID_HOPTURN:
		{
			MakeIdealYaw( m_vecEnemyLKP );
			ChangeYaw( pev->yaw_speed );

			if ( m_fSequenceFinished )
			{
				m_iTaskStatus = TASKSTATUS_COMPLETE;
			}
			break;
		}
	default:
		{
			CBaseMonster :: RunTask( pTask );
			break;
		}
	}
}
void CTentacle :: DieThink( void )
{
	pev->nextthink = gpGlobals-> time + 0.1;

	DispatchAnimEvents( );
	StudioFrameAdvance( );

	ChangeYaw( 24 );

	if (m_fSequenceFinished)
	{
		if (pev->sequence == m_iGoalAnim)
		{
			switch( m_iGoalAnim )
			{
			case TENTACLE_ANIM_Engine_Idle:
			case TENTACLE_ANIM_Engine_Sway:
			case TENTACLE_ANIM_Engine_Swat:
			case TENTACLE_ANIM_Engine_Bob:
				m_iGoalAnim = TENTACLE_ANIM_Engine_Sway + RANDOM_LONG( 0, 2 );
				break;
			case TENTACLE_ANIM_Engine_Death1:
			case TENTACLE_ANIM_Engine_Death2:
			case TENTACLE_ANIM_Engine_Death3:
				UTIL_Remove( this );
				return;
			}
		}

		// ALERT( at_console, "%d : %d => ", pev->sequence, m_iGoalAnim );
		pev->sequence = FindTransition( pev->sequence, m_iGoalAnim, &m_iDir );
		// ALERT( at_console, "%d\n", pev->sequence );

		if (m_iDir > 0)
		{
			pev->frame = 0;
		}
		else
		{
			pev->frame = 255;
		}
		ResetSequenceInfo( );

		float dy;
		switch( pev->sequence )
		{
		case TENTACLE_ANIM_Floor_Rear:
		case TENTACLE_ANIM_Floor_Rear_Idle:
		case TENTACLE_ANIM_Lev1_Rear:
		case TENTACLE_ANIM_Lev1_Rear_Idle:
		case TENTACLE_ANIM_Lev2_Rear:
		case TENTACLE_ANIM_Lev2_Rear_Idle:
		case TENTACLE_ANIM_Lev3_Rear:
		case TENTACLE_ANIM_Lev3_Rear_Idle:
		case TENTACLE_ANIM_Engine_Idle:
		case TENTACLE_ANIM_Engine_Sway:
		case TENTACLE_ANIM_Engine_Swat:
		case TENTACLE_ANIM_Engine_Bob:
		case TENTACLE_ANIM_Engine_Death1:
		case TENTACLE_ANIM_Engine_Death2:
		case TENTACLE_ANIM_Engine_Death3:
			pev->framerate = RANDOM_FLOAT( m_iDir - 0.2, m_iDir + 0.2 );
			dy = 180;
			break;
		default:
			pev->framerate = 1.5;
			dy = 0;
			break;
		}
		pev->ideal_yaw = m_flInitialYaw + dy;
	}
}
//
// TentacleThink
//
void CTentacle :: Cycle( void )
{
	// ALERT( at_console, "%s %.2f %d %d\n", STRING( pev->targetname ), pev->origin.z, m_MonsterState, m_IdealMonsterState );
	pev->nextthink = gpGlobals-> time + 0.1;

	// ALERT( at_console, "%s %d %d %d %f %f\n", STRING( pev->targetname ), pev->sequence, m_iGoalAnim, m_iDir, pev->framerate, pev->health );

	if (m_MonsterState == MONSTERSTATE_SCRIPT || m_IdealMonsterState == MONSTERSTATE_SCRIPT)
	{
		pev->angles.y = m_flInitialYaw;
		pev->ideal_yaw = m_flInitialYaw;	
		ClearConditions( IgnoreConditions() );
		MonsterThink( );
		m_iGoalAnim = TENTACLE_ANIM_Pit_Idle;
		return;
	}

	DispatchAnimEvents( );
	StudioFrameAdvance( );

	ChangeYaw( pev->yaw_speed );

	CSound *pSound;

	Listen( );

	// Listen will set this if there's something in my sound list
	if ( HasConditions( bits_COND_HEAR_SOUND ) )
		pSound = PBestSound();
	else
		pSound = NULL;

	if ( pSound )
	{
		Vector vecDir;
		if (gpGlobals->time - m_flPrevSoundTime < 0.5)
		{
			float dt = gpGlobals->time - m_flPrevSoundTime;
			vecDir = pSound->m_vecOrigin + (pSound->m_vecOrigin - m_vecPrevSound) / dt - pev->origin;
		}
		else
		{
			vecDir = pSound->m_vecOrigin - pev->origin;
		}
		m_flPrevSoundTime = gpGlobals->time;
		m_vecPrevSound = pSound->m_vecOrigin;

		m_flSoundYaw = UTIL_VecToYaw ( vecDir ) - m_flInitialYaw;
		m_iSoundLevel = Level( vecDir.z );

		if (m_flSoundYaw < -180)
			m_flSoundYaw += 360;
		if (m_flSoundYaw > 180)
			m_flSoundYaw -= 360;

		// ALERT( at_console, "sound %d %.0f\n", m_iSoundLevel, m_flSoundYaw );
		if (m_flSoundTime < gpGlobals->time)
		{
			// play "I hear new something" sound
			char *sound;	

			switch( RANDOM_LONG(0,1) )
			{
			case 0: sound = "tentacle/te_alert1.wav"; break;
			case 1: sound = "tentacle/te_alert2.wav"; break;
			}

			// UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), sound, 1.0, ATTN_NORM, 0, 100);
		}
		m_flSoundTime = gpGlobals->time + RANDOM_FLOAT( 5.0, 10.0 );
	}

	// clip ideal_yaw
	float dy = m_flSoundYaw;
	switch( pev->sequence )
	{
	case TENTACLE_ANIM_Floor_Rear:
	case TENTACLE_ANIM_Floor_Rear_Idle:
	case TENTACLE_ANIM_Lev1_Rear:
	case TENTACLE_ANIM_Lev1_Rear_Idle:
	case TENTACLE_ANIM_Lev2_Rear:
	case TENTACLE_ANIM_Lev2_Rear_Idle:
	case TENTACLE_ANIM_Lev3_Rear:
	case TENTACLE_ANIM_Lev3_Rear_Idle:
		if (dy < 0 && dy > -m_flMaxYaw)
			dy = -m_flMaxYaw;
		if (dy > 0 && dy < m_flMaxYaw)
			dy = m_flMaxYaw;
		break;
	default:
		if (dy < -m_flMaxYaw)
			dy = -m_flMaxYaw;
		if (dy > m_flMaxYaw)
			dy = m_flMaxYaw;
	}
	pev->ideal_yaw = m_flInitialYaw + dy;

	if (m_fSequenceFinished)
	{
		// ALERT( at_console, "%s done %d %d\n", STRING( pev->targetname ), pev->sequence, m_iGoalAnim );
		if (pev->health <= 1)
		{
			m_iGoalAnim = TENTACLE_ANIM_Pit_Idle;
			if (pev->sequence == TENTACLE_ANIM_Pit_Idle)
			{
				pev->health = 75;
			}
		}
		else if ( m_flSoundTime > gpGlobals->time )
		{
			if (m_flSoundYaw >= -(m_flMaxYaw + 30) && m_flSoundYaw <= (m_flMaxYaw + 30))
			{
				// strike
				m_iGoalAnim = LookupActivity( ACT_T_STRIKE + m_iSoundLevel );
			}
			else if (m_flSoundYaw >= -m_flMaxYaw * 2 && m_flSoundYaw <= m_flMaxYaw * 2) 
			{
				// tap
				m_iGoalAnim = LookupActivity( ACT_T_TAP + m_iSoundLevel );
			}
			else
			{
				// go into rear idle
				m_iGoalAnim = LookupActivity( ACT_T_REARIDLE + m_iSoundLevel );
			}
		}
		else if (pev->sequence == TENTACLE_ANIM_Pit_Idle)
		{
			// stay in pit until hear noise
			m_iGoalAnim = TENTACLE_ANIM_Pit_Idle;
		}
		else if (pev->sequence == m_iGoalAnim)
		{
			if (MyLevel() >= 0 && gpGlobals->time < m_flSoundTime)
			{
				if (RANDOM_LONG(0,9) < m_flSoundTime - gpGlobals->time)
				{
					// continue stike
					m_iGoalAnim = LookupActivity( ACT_T_STRIKE + m_iSoundLevel );
				}
				else
				{
					// tap
					m_iGoalAnim = LookupActivity( ACT_T_TAP + m_iSoundLevel );
				}
			}
			else if (MyLevel( ) < 0)
			{
				m_iGoalAnim = LookupActivity( ACT_T_IDLE + 0 );
			}
			else
			{
				if (m_flNextSong < gpGlobals->time)
				{
					// play "I hear new something" sound
					char *sound;	

					switch( RANDOM_LONG(0,1) )
					{
					case 0: sound = "tentacle/te_sing1.wav"; break;
					case 1: sound = "tentacle/te_sing2.wav"; break;
					}

					EMIT_SOUND(ENT(pev), CHAN_VOICE, sound, 1.0, ATTN_NORM);

					m_flNextSong = gpGlobals->time + RANDOM_FLOAT( 10, 20 );
				}

				if (RANDOM_LONG(0,15) == 0)
				{
					// idle on new level
					m_iGoalAnim = LookupActivity( ACT_T_IDLE + RANDOM_LONG(0,3) );
				}
				else if (RANDOM_LONG(0,3)  == 0)
				{
					// tap
					m_iGoalAnim = LookupActivity( ACT_T_TAP + MyLevel( ) );
				}
				else
				{
					// idle
					m_iGoalAnim = LookupActivity( ACT_T_IDLE + MyLevel( ) );
				}
			}
			if (m_flSoundYaw < 0)
				m_flSoundYaw += RANDOM_FLOAT( 2, 8 );
			else
				m_flSoundYaw -= RANDOM_FLOAT( 2, 8 );
		}

		pev->sequence = FindTransition( pev->sequence, m_iGoalAnim, &m_iDir );

		if (m_iDir > 0)
		{
			pev->frame = 0;
		}
		else
		{
			m_iDir = -1; // just to safe
			pev->frame = 255;
		}
		ResetSequenceInfo( );

		m_flFramerateAdj = RANDOM_FLOAT( -0.2, 0.2 );
		pev->framerate = m_iDir * 1.0 + m_flFramerateAdj;

		switch( pev->sequence)
		{
		case TENTACLE_ANIM_Floor_Tap:
		case TENTACLE_ANIM_Lev1_Tap:
		case TENTACLE_ANIM_Lev2_Tap:
		case TENTACLE_ANIM_Lev3_Tap:
			{
				Vector vecSrc;
				UTIL_MakeVectors( pev->angles );

				TraceResult tr1, tr2;

				vecSrc = pev->origin + Vector( 0, 0, MyHeight() - 4);
				UTIL_TraceLine( vecSrc, vecSrc + gpGlobals->v_forward * 512, ignore_monsters, ENT( pev ), &tr1 );

				vecSrc = pev->origin + Vector( 0, 0, MyHeight() + 8);
				UTIL_TraceLine( vecSrc, vecSrc + gpGlobals->v_forward * 512, ignore_monsters, ENT( pev ), &tr2 );

				// ALERT( at_console, "%f %f\n", tr1.flFraction * 512, tr2.flFraction * 512 );

				m_flTapRadius = SetBlending( 0, RANDOM_FLOAT( tr1.flFraction * 512, tr2.flFraction * 512 ) );
			}
			break;
		default:
			m_flTapRadius = 336; // 400 - 64
			break;
		}
		pev->view_ofs.z = MyHeight( );
		// ALERT( at_console, "seq %d\n", pev->sequence );
	}

	if (m_flPrevSoundTime + 2.0 > gpGlobals->time)
	{
		// 1.5 normal speed if hears sounds
		pev->framerate = m_iDir * 1.5 + m_flFramerateAdj;
	}
	else if (m_flPrevSoundTime + 5.0 > gpGlobals->time)
	{
		// slowdown to normal
		pev->framerate = m_iDir + m_iDir * (5 - (gpGlobals->time - m_flPrevSoundTime)) / 2 + m_flFramerateAdj;
	}
}
Exemple #9
0
//=========================================================
// RunTask 
//=========================================================
void CHoundeye :: RunTask ( Task_t *pTask )
{
	switch ( pTask->iTask )
	{
	case TASK_HOUND_THREAT_DISPLAY:
		{
			MakeIdealYaw ( m_vecEnemyLKP );
			ChangeYaw ( pev->yaw_speed );

			if ( m_fSequenceFinished )
			{
				TaskComplete();
			}
			
			break;
		}
	case TASK_HOUND_CLOSE_EYE:
		{
			if ( pev->skin < HOUNDEYE_EYE_FRAMES - 1 )
			{
				pev->skin++;
			}
			break;
		}
	case TASK_HOUND_HOP_BACK:
		{
			if ( m_fSequenceFinished )
			{
				TaskComplete();
			}
			break;
		}
	case TASK_SPECIAL_ATTACK1:
		{
			pev->skin = RANDOM_LONG(0, HOUNDEYE_EYE_FRAMES - 1);

			MakeIdealYaw ( m_vecEnemyLKP );
			ChangeYaw ( pev->yaw_speed );
			
			float life;
			life = ((255 - pev->frame) / (pev->framerate * m_flFrameRate));
			if (life < 0.1) life = 0.1;

			MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin );
				WRITE_BYTE(  TE_IMPLOSION);
				WRITE_COORD( pev->origin.x);
				WRITE_COORD( pev->origin.y);
				WRITE_COORD( pev->origin.z + 16);
				WRITE_BYTE( 50 * life + 100);  // radius
				WRITE_BYTE( pev->frame / 25.0 ); // count
				WRITE_BYTE( life * 10 ); // life
			MESSAGE_END();
			
			if ( m_fSequenceFinished )
			{
				SonicAttack(); 
				TaskComplete();
			}

			break;
		}
	default:
		{
			CSquadMonster :: RunTask(pTask);
			break;
		}
	}
}
//=========================================================
// RunTask 
//=========================================================
void CController :: RunTask ( Task_t *pTask )
{

	if (m_flShootEnd > gpGlobals->time)
	{
		Vector vecHand, vecAngle;
		
		GetAttachment( 2, vecHand, vecAngle );
	
		while (m_flShootTime < m_flShootEnd && m_flShootTime < gpGlobals->time)
		{
			Vector vecSrc = vecHand + pev->velocity * (m_flShootTime - gpGlobals->time);
			Vector vecDir;
			
			if (m_pCine != NULL || m_hEnemy != NULL)
			{
				if (m_pCine != NULL) // LRC- is this a script that's telling it to fire?
				{
					if (m_hTargetEnt != NULL && m_pCine->PreciseAttack())
					{
						vecDir = (m_hTargetEnt->pev->origin - pev->origin).Normalize() * gSkillData.controllerSpeedBall;
					}
					else
					{
						UTIL_MakeVectors(pev->angles);
						vecDir = gpGlobals->v_forward * gSkillData.controllerSpeedBall;
					}
				}
				else if (m_hEnemy != NULL)
				{
					if (HasConditions( bits_COND_SEE_ENEMY ))
					{
						m_vecEstVelocity = m_vecEstVelocity * 0.5 + m_hEnemy->pev->velocity * 0.5;
					}
					else
					{
						m_vecEstVelocity = m_vecEstVelocity * 0.8;
					}
					vecDir = Intersect( vecSrc, m_hEnemy->BodyTarget( pev->origin ), m_vecEstVelocity, gSkillData.controllerSpeedBall );
				}

				float delta = 0.03490; // +-2 degree
				vecDir = vecDir + Vector( RANDOM_FLOAT( -delta, delta ), RANDOM_FLOAT( -delta, delta ), RANDOM_FLOAT( -delta, delta ) ) * gSkillData.controllerSpeedBall;

				vecSrc = vecSrc + vecDir * (gpGlobals->time - m_flShootTime);
				CBaseMonster *pBall = (CBaseMonster*)Create( "controller_energy_ball", vecSrc, pev->angles, edict() );
				pBall->pev->velocity = vecDir;
			}
			m_flShootTime += 0.2;
		}

		if (m_flShootTime > m_flShootEnd)
		{
			m_iBall[0] = 64;
			m_iBallTime[0] = m_flShootEnd;
			m_iBall[1] = 64;
			m_iBallTime[1] = m_flShootEnd;
			m_fInCombat = FALSE;
		}
	}

	switch ( pTask->iTask )
	{
	case TASK_WAIT_FOR_MOVEMENT:
	case TASK_WAIT:
	case TASK_WAIT_FACE_ENEMY:
	case TASK_WAIT_PVS:
		MakeIdealYaw( m_vecEnemyLKP );
		ChangeYaw( pev->yaw_speed );

		if (m_fSequenceFinished)
		{
			m_fInCombat = FALSE;
		}

		CSquadMonster :: RunTask ( pTask );

		if (!m_fInCombat)
		{
			if (HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ))
			{
				pev->sequence = LookupActivity( ACT_RANGE_ATTACK1 );
				pev->frame = 0;
				ResetSequenceInfo( );
				m_fInCombat = TRUE;
			}
			else if (HasConditions ( bits_COND_CAN_RANGE_ATTACK2 ))
			{
				pev->sequence = LookupActivity( ACT_RANGE_ATTACK2 );
				pev->frame = 0;
				ResetSequenceInfo( );
				m_fInCombat = TRUE;
			}
			else
			{
				int iFloat = LookupFloat( );
				if (m_fSequenceFinished || iFloat != pev->sequence)
				{
					pev->sequence = iFloat;
					pev->frame = 0;
					ResetSequenceInfo( );
				}
			}
		}
		break;
	default: 
		CSquadMonster :: RunTask ( pTask );
		break;
	}
}
//=========================================================
// RunTask 
//=========================================================
void CBaseMonster :: RunTask ( Task_t *pTask )
{
	switch ( pTask->iTask )
	{
	case TASK_TURN_RIGHT:
	case TASK_TURN_LEFT:
		{
			ChangeYaw( pev->yaw_speed );

			if ( FacingIdeal() )
			{
				TaskComplete();
			}
			break;
		}

	case TASK_PLAY_SEQUENCE_FACE_ENEMY:
	case TASK_PLAY_SEQUENCE_FACE_TARGET:
		{
			CBaseEntity *pTarget;

			if ( pTask->iTask == TASK_PLAY_SEQUENCE_FACE_TARGET )
				pTarget = m_hTargetEnt;
			else
				pTarget = m_hEnemy;
			if ( pTarget )
			{
				pev->ideal_yaw = UTIL_VecToYaw( pTarget->pev->origin - pev->origin );
				ChangeYaw( pev->yaw_speed );
			}
			if ( m_fSequenceFinished )
				TaskComplete();
		}
		break;

	case TASK_PLAY_SEQUENCE:
	case TASK_PLAY_ACTIVE_IDLE:
		{
			if ( m_fSequenceFinished )
			{
				TaskComplete();
			}
			break;
		}


	case TASK_FACE_ENEMY:
		{
			MakeIdealYaw( m_vecEnemyLKP );

			ChangeYaw( pev->yaw_speed );

			if ( FacingIdeal() )
			{
				TaskComplete();
			}
			break;
		}
	case TASK_FACE_HINTNODE:
	case TASK_FACE_LASTPOSITION:
	case TASK_FACE_TARGET:
	case TASK_FACE_IDEAL:
	case TASK_FACE_ROUTE:
		{
			ChangeYaw( pev->yaw_speed );

			if ( FacingIdeal() )
			{
				TaskComplete();
			}
			break;
		}
	case TASK_WAIT_PVS:
		{
			if ( !FNullEnt(FIND_CLIENT_IN_PVS(edict())) )
			{
				TaskComplete();
			}
			break;
		}
	case TASK_WAIT_INDEFINITE:
		{
			// don't do anything.
			break;
		}
	case TASK_WAIT:
	case TASK_WAIT_RANDOM:
		{
			if ( gpGlobals->time >= m_flWaitFinished )
			{
				TaskComplete();
			}
			break;
		}
	case TASK_WAIT_FACE_ENEMY:
		{
			MakeIdealYaw ( m_vecEnemyLKP );
			ChangeYaw( pev->yaw_speed ); 

			if ( gpGlobals->time >= m_flWaitFinished )
			{
				TaskComplete();
			}
			break;
		}
	case TASK_MOVE_TO_TARGET_RANGE:
		{
			float distance;

			if ( m_hTargetEnt == NULL )
				TaskFail();
			else
			{
				distance = ( m_vecMoveGoal - pev->origin ).Length2D();
				// Re-evaluate when you think your finished, or the target has moved too far
				if ( (distance < pTask->flData) || (m_vecMoveGoal - m_hTargetEnt->pev->origin).Length() > pTask->flData * 0.5 )
				{
					m_vecMoveGoal = m_hTargetEnt->pev->origin;
					distance = ( m_vecMoveGoal - pev->origin ).Length2D();
					FRefreshRoute();
				}

				// Set the appropriate activity based on an overlapping range
				// overlap the range to prevent oscillation
				if ( distance < pTask->flData )
				{
					TaskComplete();
					RouteClear();		// Stop moving
				}
				else if ( distance < 190 && m_movementActivity != ACT_WALK )
					m_movementActivity = ACT_WALK;
				else if ( distance >= 270 && m_movementActivity != ACT_RUN )
					m_movementActivity = ACT_RUN;
			}

			break;
		}
	case TASK_WAIT_FOR_MOVEMENT:
		{
			if (MovementIsComplete())
			{
				TaskComplete();
				RouteClear();		// Stop moving
			}
			break;
		}
	case TASK_DIE:
		{
			if ( m_fSequenceFinished && pev->frame >= 255 )
			{
				pev->deadflag = DEAD_DEAD;
				
				SetThink ( NULL );
				StopAnimation();

				if ( !BBoxFlat() )
				{
					// a bit of a hack. If a corpses' bbox is positioned such that being left solid so that it can be attacked will
					// block the player on a slope or stairs, the corpse is made nonsolid. 
//					pev->solid = SOLID_NOT;
					UTIL_SetSize ( pev, Vector ( -4, -4, 0 ), Vector ( 4, 4, 1 ) );
				}
				else // !!!HACKHACK - put monster in a thin, wide bounding box until we fix the solid type/bounding volume problem
					UTIL_SetSize ( pev, Vector ( pev->mins.x, pev->mins.y, pev->mins.z ), Vector ( pev->maxs.x, pev->maxs.y, pev->mins.z + 1 ) );

				if ( ShouldFadeOnDeath() )
				{
					// this monster was created by a monstermaker... fade the corpse out.
					SUB_StartFadeOut();
				}
				else
				{
					// body is gonna be around for a while, so have it stink for a bit.
					CSoundEnt::InsertSound ( bits_SOUND_CARCASS, pev->origin, 384, 30 );
				}
			}
			break;
		}
	case TASK_RANGE_ATTACK1_NOTURN:
	case TASK_MELEE_ATTACK1_NOTURN:
	case TASK_MELEE_ATTACK2_NOTURN:
	case TASK_RANGE_ATTACK2_NOTURN:
	case TASK_RELOAD_NOTURN:
		{
			if ( m_fSequenceFinished )
			{
				m_Activity = ACT_RESET;
				TaskComplete();
			}
			break;
		}
	case TASK_RANGE_ATTACK1:
	case TASK_MELEE_ATTACK1:
	case TASK_MELEE_ATTACK2:
	case TASK_RANGE_ATTACK2:
	case TASK_SPECIAL_ATTACK1:
	case TASK_SPECIAL_ATTACK2:
	case TASK_RELOAD:
		{
			MakeIdealYaw ( m_vecEnemyLKP );
			ChangeYaw ( pev->yaw_speed );

			if ( m_fSequenceFinished )
			{
				m_Activity = ACT_RESET;
				TaskComplete();
			}
			break;
		}
	case TASK_SMALL_FLINCH:
		{
			if ( m_fSequenceFinished )
			{
				TaskComplete();
			}
		}
		break;
	case TASK_WAIT_FOR_SCRIPT:
		{
			if ( m_pCine->m_iDelay <= 0 && gpGlobals->time >= m_pCine->m_startTime )
			{
				TaskComplete();
			}
			break;
		}
	case TASK_PLAY_SCRIPT:
		{
//			ALERT(at_console, "Play Script\n");
			if (m_fSequenceFinished)
			{
//				ALERT(at_console, "Anim Finished\n");
				if (m_pCine->m_iRepeatsLeft > 0)
				{
//					ALERT(at_console, "Frame %f; Repeat %d from %f\n", pev->frame, m_pCine->m_iRepeatsLeft, m_pCine->m_fRepeatFrame);
					m_pCine->m_iRepeatsLeft--;
					pev->frame = m_pCine->m_fRepeatFrame;
					ResetSequenceInfo( );
				}
				else
				{
					TaskComplete();
				}
			}
			break;
		}
	}
}
Exemple #12
0
//=========================================================
// RunTask 
//=========================================================
void CLuciole :: RunTask ( Task_t *pTask )
{
	// petite loupiote

	MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, Center() );
		WRITE_BYTE(TE_DLIGHT);
		WRITE_COORD(Center().x);	// X
		WRITE_COORD(Center().y);	// Y
		WRITE_COORD(Center().z);	// Z
		WRITE_BYTE( 7 );		// radius * 0.1
		WRITE_BYTE( 150 );		// r
		WRITE_BYTE( 71 );		// g
		WRITE_BYTE( 245 );		// b
		WRITE_BYTE( 3 );		// time * 10
		WRITE_BYTE( 0 );		// decay * 0.1
	MESSAGE_END( );

	
	// position de tir

	if ( m_hEnemy != NULL &&  (Center()-m_hEnemy->Center()).Length() < ATTACK_DIST && gpGlobals->time - m_flLastAttack > ATTACK_DELAY )
	{
		m_flLastAttack = gpGlobals->time;

		EMIT_SOUND ( edict(), CHAN_ITEM, "debris/beamstart14.wav", 1.0, ATTN_NORM );


		for ( int i=0; i<3; i++ )
		{
			CBeam *pBeam = CBeam::BeamCreate( "sprites/laserbeam.spr", 2 );

			if ( RANDOM_LONG(0,1) )
				pBeam->SetColor( 206,118, 254 );
			else
				pBeam->SetColor( 223,224, 255 );

			pBeam->SetBrightness( 192 );

			pBeam->PointEntInit( m_hEnemy->Center(), entindex( ) );
			pBeam->SetEndAttachment( 0 );

			pBeam->RelinkBeam( );

			pBeam->SetNoise ( 30 );
			pBeam->LiveForTime ( 0.4 );

			m_hEnemy->TakeDamage ( pev, pev, gSkillData.LucioleDamage, DMG_SHOCK );
		}



		return;
	}



	MakeIdealYaw( m_vecEnemyLKP );
	ChangeYaw( pev->yaw_speed );


	// run task classique

	switch ( pTask->iTask )
	{
	case TASK_FLYBEE_WAIT_FOR_MOVEMENT:
		{
			if (MovementIsComplete())
			{
				TaskComplete();
				RouteClear();		// Stop moving
			}
			break;
		}

	case TASK_LUCIOLE_GET_PATH:
		{
			// considère l'objectif atteint à 10 units de distance
			BOOL bFinDeRoute = FALSE;

			if ( (pev->origin-m_vecRoute).Length() < 10 )
			{
				bFinDeRoute = TRUE;
			}


			// actualise la position ennemie

			if ( m_hEnemy == NULL )
			{
				TaskComplete ();
				break;
			}

			Vector vecEnemy = m_hEnemy->Center();

			// vérifie la visibilité du joueur

			TraceResult tr;
			UTIL_TraceLine ( pev->origin, vecEnemy, dont_ignore_monsters, dont_ignore_glass, edict(), &tr ); 

			if ( tr.flFraction == 1.0 || FClassnameIs(tr.pHit, "player") )
			{
				// champ libre jusqu'au joueur

				m_vecRoute = vecEnemy;

				m_iMouchard = MOUCHARD_OFF;
			}


			// joueur invisible

			else
			{
				// trajectoire non finie - on continue

				if ( bFinDeRoute == FALSE )
				{
					// active le mouchard

					if ( m_iMouchard == MOUCHARD_OFF )
					{
						m_iMouchard = MOUCHARD_LANCEMENT;
						m_vecMouchard1 = m_vecRoute;
					}
				}

				// pas de trajectoire définie 

				else
				{
					// tente d'utiliser le mouchard

					TraceResult trMouchard;
					UTIL_TraceLine ( pev->origin, m_vecMouchard2, dont_ignore_monsters, dont_ignore_glass, edict(), &trMouchard ); 

					if ( m_iMouchard == MOUCHARD_ON && ( trMouchard.flFraction == 1.0 || FClassnameIs(trMouchard.pHit, "player") ) )
					{
						// c parti

						m_vecRoute = m_vecMouchard2;

						// mouchard obsolète, on en relance un nouveau

						m_iMouchard = MOUCHARD_LANCEMENT;
					}

					else
					{
						TraceResult trTete;
						UTIL_TraceLine ( pev->origin, m_hEnemy->pev->view_ofs, dont_ignore_monsters, dont_ignore_glass, edict(), &trTete ); 

						TraceResult trPieds;
						UTIL_TraceLine ( pev->origin, m_hEnemy->pev->origin, dont_ignore_monsters, dont_ignore_glass, edict(), &trPieds ); 

						if ( trTete.flFraction == 1.0 || FClassnameIs(trTete.pHit, "player") )
						{
							// champ libre jusqu'au joueur
							m_vecRoute = m_hEnemy->pev->view_ofs;
						}
						else if ( trPieds.flFraction == 1.0 || FClassnameIs(trPieds.pHit, "player") )
						{
							// champ libre jusqu'au joueur

							m_vecRoute = m_hEnemy->pev->origin;
						}

						// ennemi totalement invisible

						else
						{

							// bloqué par de petits obstacles - on tente de monter ou descendre un peu

							TraceResult trEvite [2];

							UTIL_MakeVectors ( pev->angles );

							int ordre [4];

							switch ( RANDOM_LONG(0,3) )
							{
								case 0:	ordre[0] = 0; ordre[1] = 1; ordre[2] = 2; ordre[3] = 3; break;
								case 1:	ordre[0] = 0; ordre[1] = 3; ordre[2] = 2; ordre[3] = 1; break;
								case 2:	ordre[0] = 2; ordre[1] = 3; ordre[2] = 0; ordre[3] = 1; break;
								case 3:	ordre[0] = 3; ordre[1] = 1; ordre[2] = 0; ordre[3] = 2; break;
							}

							UTIL_TraceLine ( pev->origin, pev->origin + Vector (0,0,RANDOM_FLOAT(40,60)), dont_ignore_monsters, dont_ignore_glass, edict(), &trEvite[ordre[0]] ); 
							UTIL_TraceLine ( pev->origin, pev->origin - Vector (0,0,RANDOM_FLOAT(40,60)), dont_ignore_monsters, dont_ignore_glass, edict(), &trEvite[ordre[1]] );
							UTIL_TraceLine ( pev->origin, pev->origin + gpGlobals->v_right * RANDOM_FLOAT(40,60), dont_ignore_monsters, dont_ignore_glass, edict(), &trEvite[ordre[2]] );
							UTIL_TraceLine ( pev->origin, pev->origin - gpGlobals->v_right * RANDOM_FLOAT(40,60), dont_ignore_monsters, dont_ignore_glass, edict(), &trEvite[ordre[3]] );
							

							for ( int i=0; i<4; i++ )
							{
								if ( trEvite[i].flFraction >= 0.5 )

								m_vecRoute = trEvite[i].vecEndPos - (trEvite[i].vecEndPos-pev->origin).Normalize() * 5;

								break;
							}
						}
					}
				}
			}



			// actualise le mouchard

			if ( m_iMouchard != MOUCHARD_OFF )
			{

				if ( m_iMouchard == MOUCHARD_LANCEMENT )
				{
					m_vecMouchard2 = m_vecMouchard1;
				}


				// vérifie si le joueur est visible depuis sa dernière position connue

				TraceResult trMouchard;
				UTIL_TraceLine ( m_vecMouchard1, vecEnemy, dont_ignore_monsters, dont_ignore_glass, edict(), &trMouchard ); 

				if ( trMouchard.flFraction == 1.0 || FClassnameIs(trMouchard.pHit, "player") )
				{
					m_vecMouchard2 = vecEnemy;
					m_iMouchard = MOUCHARD_ON;
				}
			}


			// trajectoire établie - application des vitesses

			float flDot = DotProduct ( pev->velocity.Normalize(), (m_vecRoute-pev->origin).Normalize() );

			float flRatio = 0.6 + (flDot+1)*0.6;

			float speed = pev->velocity.Length() * flRatio;

			speed = max ( 100, speed );
			speed = min ( speed, 250 );

			pev->velocity = (m_vecRoute - pev->origin).Normalize() * speed;

			break;
		}



	default: 
		CBaseMonster :: RunTask ( pTask );
		break;
	}
}
Exemple #13
0
void CTalkMonster :: RunTask( const Task_t& task )
{
	switch( task.iTask )
	{
	case TASK_TLK_CLIENT_STARE:
	case TASK_TLK_LOOK_AT_CLIENT:
		{
			edict_t *pPlayer;

			// track head to the client for a while.
			if( m_MonsterState == MONSTERSTATE_IDLE &&
				!IsMoving() &&
				!IsTalking() )
			{
				// Get edict for one player
				pPlayer = g_engfuncs.pfnPEntityOfEntIndex( 1 );

				if( pPlayer )
				{
					IdleHeadTurn( pPlayer->v.origin );
				}
			}
			else
			{
				// started moving or talking
				TaskFail();
				return;
			}

			if( pPlayer )
			{
				if( task.iTask == TASK_TLK_CLIENT_STARE )
				{
					// fail out if the player looks away or moves away.
					if( ( pPlayer->v.origin - GetAbsOrigin() ).Length2D() > TLK_STARE_DIST )
					{
						// player moved away.
						TaskFail();
					}

					UTIL_MakeVectors( pPlayer->v.angles );
					if( UTIL_DotPoints( pPlayer->v.origin, GetAbsOrigin(), gpGlobals->v_forward ) < m_flFieldOfView )
					{
						// player looked away
						TaskFail();
					}
				}
			}
			else
			{
				TaskFail();
			}

			if( gpGlobals->time > m_flWaitFinished )
			{
				TaskComplete();
			}
			break;
		}

	case TASK_FACE_PLAYER:
		{
			// Get edict for one player
			edict_t *pPlayer = g_engfuncs.pfnPEntityOfEntIndex( 1 );

			if( pPlayer )
			{
				MakeIdealYaw( pPlayer->v.origin );
				ChangeYaw( GetYawSpeed() );
				IdleHeadTurn( pPlayer->v.origin );
				if( gpGlobals->time > m_flWaitFinished && FlYawDiff() < 10 )
				{
					TaskComplete();
				}
			}
			else
			{
				TaskFail();
			}

			break;
		}

	case TASK_TLK_EYECONTACT:
		{
			if( !IsMoving() && IsTalking() && m_hTalkTarget != NULL )
			{
				// ALERT( at_console, "waiting %f\n", m_flStopTalkTime - gpGlobals->time );
				IdleHeadTurn( m_hTalkTarget->GetAbsOrigin() );
			}
			else
			{
				TaskComplete();
			}
			break;
		}

	case TASK_WALK_PATH_FOR_UNITS:
		{
			float distance;

			distance = (m_vecLastPosition - GetAbsOrigin()).Length2D();

			// Walk path until far enough away
			if ( distance > task.flData || MovementIsComplete() )
			{
				TaskComplete();
				RouteClear();		// Stop moving
			}

			break;
		}
		
	case TASK_WAIT_FOR_MOVEMENT:
		{
			if( IsTalking() && m_hTalkTarget != NULL )
			{
				// ALERT(at_console, "walking, talking\n");
				IdleHeadTurn( m_hTalkTarget->GetAbsOrigin() );
			}
			else
			{
				IdleHeadTurn( GetAbsOrigin() );
				// override so that during walk, a scientist may talk and greet player
				FIdleHello();
				if( RANDOM_LONG( 0, m_nSpeak * 20 ) == 0 )
				{
					FIdleSpeak();
				}
			}

			CBaseMonster::RunTask( task );
			if( TaskIsComplete() )
				IdleHeadTurn( GetAbsOrigin() );
			break;
		}

	default:
		{
			if( IsTalking() && m_hTalkTarget != NULL )
			{
				IdleHeadTurn( m_hTalkTarget->GetAbsOrigin() );
			}
			else
			{
				SetBoneController( 0, 0 );
			}
			CBaseMonster::RunTask( task );

			break;
		}
	}
}
Exemple #14
0
void CScientist :: RunTask( Task_t *pTask )
{
	switch ( pTask->iTask )
	{
	case TASK_RUN_PATH_SCARED:
		if ( MovementIsComplete() )
			TaskComplete();
		if ( RANDOM_LONG(0,31) < 8 )
			Scream();
		break;

	case TASK_MOVE_TO_TARGET_RANGE_SCARED:
		{
			if ( RANDOM_LONG(0,63)< 8 )
				Scream();

			if ( m_hEnemy == NULL )
			{
				TaskFail();
			}
			else
			{
				float distance;

				distance = ( m_vecMoveGoal - pev->origin ).Length2D();
				// Re-evaluate when you think your finished, or the target has moved too far
				if ( (distance < pTask->flData) || (m_vecMoveGoal - m_hTargetEnt->pev->origin).Length() > pTask->flData * 0.5 )
				{
					m_vecMoveGoal = m_hTargetEnt->pev->origin;
					distance = ( m_vecMoveGoal - pev->origin ).Length2D();
					FRefreshRoute();
				}

				// Set the appropriate activity based on an overlapping range
				// overlap the range to prevent oscillation
				if ( distance < pTask->flData )
				{
					TaskComplete();
					RouteClear();		// Stop moving
				}
				else if ( distance < 190 && m_movementActivity != ACT_WALK_SCARED )
					m_movementActivity = ACT_WALK_SCARED;
				else if ( distance >= 270 && m_movementActivity != ACT_RUN_SCARED )
					m_movementActivity = ACT_RUN_SCARED;
			}
		}
		break;

	case TASK_HEAL:
		if ( m_fSequenceFinished )
		{
			TaskComplete();
		}
		else
		{
			if ( TargetDistance() > 90 )
				TaskComplete();
			pev->ideal_yaw = UTIL_VecToYaw( m_hTargetEnt->pev->origin - pev->origin );
			ChangeYaw( pev->yaw_speed );
		}
		break;
	default:
		CTalkMonster::RunTask( pTask );
		break;
	}
}
void Bot_Think(edict_t *eBot)
{
	// If the bot isn't dead, then add animations.
	if(eBot->monster.iState != STATE_DEAD)
	{
		if(eBot->v.flags & FL_ONGROUND)
		{
			if((	(eBot->v.velocity[0] < -4.0f || eBot->v.velocity[0] > 4.0f)	|| 
					(eBot->v.velocity[1] < -4.0f || eBot->v.velocity[1] > 4.0f))	&& 
					(!eBot->local.dAnimationTime || eBot->local.iAnimationEnd == 9))
				Entity_Animate(eBot,PlayerAnimation_Walk);
			else if((eBot->v.velocity[0] == 0 || eBot->v.velocity[1] == 0) && (!eBot->local.dAnimationTime || eBot->local.iAnimationEnd > 9))
			{
	#ifdef GAME_OPENKATANA
				if(eBot->v.iActiveWeapon == WEAPON_DAIKATANA)
					Entity_Animate(eBot,PlayerAnimation_KatanaIdle);
				else
	#endif
					Entity_Animate(eBot,PlayerAnimation_Idle);
			}
		}
	}

	switch(eBot->monster.iThink)
	{
	case THINK_IDLE:
#if 1
		// Add some random movement. ~hogsy
		if(rand()%120 == 0)
		{
			int	iResult = rand()%3;

			if(iResult == 0)
				eBot->v.velocity[0] += BOT_MIN_SPEED;
			else if(iResult == 1)
				eBot->v.velocity[0] -= BOT_MIN_SPEED;

			iResult = rand()%3;
			if(iResult == 0)
				eBot->v.velocity[1] += BOT_MIN_SPEED;
			else if(iResult == 1)
				eBot->v.velocity[1] -= BOT_MIN_SPEED;

			eBot->v.angles[1] = Math_VectorToYaw(eBot->v.velocity);
		}
		else if(rand()%150 == 0)
		{
			Monster_Jump(eBot,200.0f);

			Entity_Animate(eBot,PlayerAnimation_Jump);
		}
#endif
		break;
	case THINK_WANDERING:
		{
			edict_t		*eTarget;
			Waypoint_t	*wPoint;
//			Weapon_t	*wMyWeapon;
//			vec3_t		vAngle;

			eTarget = Monster_GetTarget(eBot);
			if(eTarget)
			{
				if(Monster_GetRelationship(eBot,eTarget) == RELATIONSHIP_HATE)
				{
					// [22/3/2013] Begin attacking next frame ~hogsy
					Monster_SetThink(eBot,THINK_ATTACKING);
					return;
				}
			}

			if(!eBot->monster.vTarget)
			{
				// [28/7/2012] TODO: Find specific waypoint such as an item ~hogsy
				wPoint = Waypoint_GetByVisibility(eBot->v.origin);
				if(wPoint)
				{
					if(wPoint->bOpen)
					{
						// [22/3/2013] TODO: Tell that current entity it's time to move... ~hogsy
					}

					Math_VectorCopy(wPoint->position,eBot->monster.vTarget);
				}
			}

#if 0
			wMyWeapon = Weapon_GetCurrentWeapon(eBot);
			if(MONSTER_GetRange(eBot,eBot->v.enemy->v.origin) > 4000)
				return;
			else if(wMyWeapon->iPrimaryType == AM_MELEE && MONSTER_GetRange(eBot,eBot->v.enemy->v.origin) > MONSTER_RANGE_MELEE)
				return;
			else if(Monster_IsVisible(eBot,eBot->v.enemy))
			{
				// [5/8/2012] No ammo and it's not a melee weapon? ~hogsy
				if(!Weapon_CheckPrimaryAmmo(eBot) && wMyWeapon->iPrimaryType != AM_MELEE)
				{
					// [5/8/2012] Should probably flee ~hogsy
					Monster_SetThink(eBot,THINK_FLEEING);
					return;
				}

				Math_VectorSubtract(eBot->v.enemy->v.origin,eBot->v.origin,vAngle);

		//		ent->v.ideal_yaw	= VectorToAngles(vAngle);

				ChangeYaw(eBot);
			}
#endif
		}
		break;
	}
}
Exemple #16
0
void CController :: RunTask ( const Task_t& task )
{

	if (m_flShootEnd > gpGlobals->time)
	{
		Vector vecHand, vecAngle;
		
		GetAttachment( 2, vecHand, vecAngle );
	
		while (m_flShootTime < m_flShootEnd && m_flShootTime < gpGlobals->time)
		{
			Vector vecSrc = vecHand + GetAbsVelocity() * (m_flShootTime - gpGlobals->time);
			Vector vecDir;
			
			if (m_hEnemy != NULL)
			{
				if (HasConditions( bits_COND_SEE_ENEMY ))
				{
					m_vecEstVelocity = m_vecEstVelocity * 0.5 + m_hEnemy->GetAbsVelocity() * 0.5;
				}
				else
				{
					m_vecEstVelocity = m_vecEstVelocity * 0.8;
				}
				vecDir = Intersect( vecSrc, m_hEnemy->BodyTarget( GetAbsOrigin() ), m_vecEstVelocity, gSkillData.GetControllerSpeedBall() );
				float delta = 0.03490; // +-2 degree
				vecDir = vecDir + Vector( RANDOM_FLOAT( -delta, delta ), RANDOM_FLOAT( -delta, delta ), RANDOM_FLOAT( -delta, delta ) ) * gSkillData.GetControllerSpeedBall();

				vecSrc = vecSrc + vecDir * (gpGlobals->time - m_flShootTime);
				CBaseMonster *pBall = (CBaseMonster*)Create( "controller_energy_ball", vecSrc, GetAbsAngles(), edict() );
				pBall->SetAbsVelocity( vecDir );
			}
			m_flShootTime += 0.2;
		}

		if (m_flShootTime > m_flShootEnd)
		{
			m_iBall[0] = 64;
			m_iBallTime[0] = m_flShootEnd;
			m_iBall[1] = 64;
			m_iBallTime[1] = m_flShootEnd;
			m_fInCombat = false;
		}
	}

	switch ( task.iTask )
	{
	case TASK_WAIT_FOR_MOVEMENT:
	case TASK_WAIT:
	case TASK_WAIT_FACE_ENEMY:
	case TASK_WAIT_PVS:
		MakeIdealYaw( m_vecEnemyLKP );
		ChangeYaw( GetYawSpeed() );

		if (m_fSequenceFinished)
		{
			m_fInCombat = false;
		}

		CSquadMonster :: RunTask ( task );

		if (!m_fInCombat)
		{
			if (HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ))
			{
				SetSequence( LookupActivity( ACT_RANGE_ATTACK1 ) );
				SetFrame( 0 );
				ResetSequenceInfo( );
				m_fInCombat = true;
			}
			else if (HasConditions ( bits_COND_CAN_RANGE_ATTACK2 ))
			{
				SetSequence( LookupActivity( ACT_RANGE_ATTACK2 ) );
				SetFrame( 0 );
				ResetSequenceInfo( );
				m_fInCombat = true;
			}
			else
			{
				int iFloat = LookupFloat( );
				if (m_fSequenceFinished || iFloat != GetSequence() )
				{
					SetSequence( iFloat );
					SetFrame( 0 );
					ResetSequenceInfo( );
				}
			}
		}
		break;
	default: 
		CSquadMonster :: RunTask ( task );
		break;
	}
}