//=============================================================================
//
//	mechron.txt
//
//	This is the script for the E1L3 boss, Mechron. For his intro sequence,
//	he rolls out of his start room and plays an animation. For his attacks,
//	he descends into one of his 3 pipes. The one he emerges from determines
//	his attack. For the center pillar, he fires an unblockable attack that
//	you must stun him out of to avoid. For the left pillar, 8 ceiling
//	turrets from each direction fire one after the other. A guard pillar
//	is lowered which must be used in evading the attack. For the right
//	pillar, 3 powerful turrets raise from the pillars where Mechron is, and
//	fire a powerful attack all at once which must be crouched under.
//
//	For documentation on scripting, please consult the Wrack Wiki at:
//	http://wrack.wikia.com/
//
//=============================================================================

#include "commondefines.h"

//== DEFINITIONS ==============================================================

#define	THRUST_HORIZONTAL	25
#define	THRUST_VERTICAL		20

//== VARIABLES ================================================================

// Keep track of the last attack we did so we don't do the same attack twice in
// a row.
int	g_iLastAttack;

//== STATE PROTOTYPES =========================================================

state	Spawn;
state	IntroSequence;
state	Main;
state	Attack1;
state	Attack2start;
state	Attack2;
state	Attack3;
state	DeathSequence;

//== EVENTS ===================================================================

event_instant( "killed" )
	ChangeState( DeathSequence );

//-----------------------------------------------------------------------------
event_instant( "gibbed" )
	ChangeState( DeathSequence );

//-----------------------------------------------------------------------------
event_instant( "player revived" )
{
	// Destroy gibs, puddles, etc.
	DestroyChildren( );

	DestroySelf( );
}

//-----------------------------------------------------------------------------
event_instant( "player continued" )
{
	// Destroy gibs, puddles, etc.
	DestroyChildren( );

	DestroySelf( );
}

//== FUNCTIONS ================================================================

int CalcHorizontalGibThrust( void )
{
	return (( rand( 0, RAND_MAX ) - ( RAND_MAX / 2 )) * 2 * THRUST_HORIZONTAL );
}

//-----------------------------------------------------------------------------
int CalcVerticalGibThrust( void )
{
	return ( rand( 0, RAND_MAX ) * 2 * ( THRUST_VERTICAL / 2 ));
}

//-----------------------------------------------------------------------------
void TweakSpreadPosition( int iSide )
{
	if ( iSide == 1 )
		MoveLinearFromOrigin( 32, 16, -320 );
	else if ( iSide == -1 )
		MoveLinearFromOrigin( -32, 16, -320 );
	else
		MoveLinearFromOrigin( 0, 0, -320 );
}

//== STATES ===================================================================

state Spawn
{
	OnEnter
	{

		// Play the first part of our intro animation.
		SetAnimation( "intro_a", -1, ANIMF_LOOP );

		// Play the first part of our intro sound.
		PlaySound( "mechron_intro_a.wav", 100, SFXF_LOOP | SFXF_NON3D, SFXPRIORITY_HIGHEST );

		// Make our last attack his center attack so he doesn't start
		// by lowering down and then coming back in the same place.
		g_iLastAttack = 2;
	}

	MainLoop
	{
		// Begin our intro sequence.
		ChangeState( IntroSequence );
	}
}

//-----------------------------------------------------------------------------
state IntroSequence
{
	int	iAnimationOver;
	int	iZDistance;

	event( "animation over" )
		iAnimationOver = 1;

	OnEnter
	{
		iZDistance = 0;
		iAnimationOver = 0;

		// Don't let the door collide with us.
	}

	MainLoop
	{
		// Move out to our initial spot in the arena.
		MoveLinearFromOrigin( 0, 0, iZDistance );
		if ( iZDistance == -320 )
		{
			// Once we're in position, wait a bit, start the boss music,
			// and fill the life bar.

			// Play the second part of our intro animation.
			SetAnimation( "intro_b", -1, 0 );

			// Play the second part of our intro sound.
			PlaySound( "mechron_intro_b.wav", 100, SFXF_STOPEXISTING_ALL | SFXF_NON3D, SFXPRIORITY_HIGHEST );

			// When the animation is done, we'll fill the life bar and begin
			// fighting!
			while ( iAnimationOver == 0 )
				delay( 1 );

			// Un-freeze everything now that the intro sequence is complete.

			changestate( Attack2Start );
		}

		iZDistance -= 1;
	}
}

//-----------------------------------------------------------------------------
state Main
{
	int	iAttack;

	MainLoop
	{
		// Set our idle animation.
		SetAnimation( "idle", -1, ANIMF_LOOP );

		// Determine the delay between attacks.If the skill setting calls for
		// the  monsters to be more aggressive, then there's a higher chance
		// that the monster should attack.
		if ( GetSkillSettingFlags( ) & SKILL_VERYAGGRESSIVE )
			delay( rand( 0, FPS * 1 ));
		else if ( GetSkillSettingFlags( ) & SKILL_AGGRESSIVE )
			delay( rand( 0, FPS * 2 ));
		else
			delay( rand( 0, FPS * 3 ));

		// Randomly pick our attack.
		iAttack = rand( 1, 3 );

		// Make sure we don't do the same attack twice in a row.
		while ( iAttack == g_iLastAttack )
			iAttack = rand( 1, 3 );

		// Save the attack.
		g_iLastAttack = iAttack;

		// Prevent Mechron from dying while being lowered on the
		// pillars. Otherwise, the death sequence can occur during
		// a scripted attack.
		AddFlag( FLAG_IMMUNETODEATH );
		delay( 1 );

		switch ( iAttack )
		{
		case 1:

			changestate( Attack1 );
			break;
		case 2:

			changestate( Attack2 );
			break;
		case 3:

			changestate( Attack3 );
			break;
		}
	}
}

//-----------------------------------------------------------------------------
state Attack1
{
	int	iNumAttacks;

	MainLoop
	{
		// First, move onto the left pillar.
		SetAnimation( "Move", -1, 0 );
		ExecuteMapScript( "MechronMove", 1, 0, 0, 0 );
		delay( 120 );
		ClearFlag( FLAG_IMMUNETODEATH );
		SetTarget( SETTARGET_PLAYER, -1, false );
		delay( 180 );

		// Set up the number of attacks.
		if ( GetDifficulty( ) == DIFFICULTY_HARD )
			iNumAttacks = 4;
		else if ( GetDifficulty( ) == DIFFICULTY_MEDIUM )
			iNumAttacks = 3;
		else
			iNumAttacks = 2;

		while ( iNumAttacks > 0 )
		{
			// Play the attack animation and sound.
			SetAnimation( "attack", -1, 0 );
			PlaySound( "mechron_attack.wav", 100, 0, SFXPRIORITY_HIGHEST );

			// Launch the attack. The number of rockets and delay depend on the difficulty.
			SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron_Strong" );
			if ( GetDifficulty( ) == DIFFICULTY_HARD )
			{
				FireProjectileAtTarget( "Rocket_Mechron_Strong1", 8, ANGLE_1 * 3, 0 );
				delay( 60 );
			}
			else if ( GetDifficulty( ) == DIFFICULTY_MEDIUM )
			{
				FireProjectileAtTarget( "Rocket_Mechron_Strong1", 6, ANGLE_1 * 3, 0 );
				delay( 90 );
			}
			else
			{
				FireProjectileAtTarget( "Rocket_Mechron_Strong1", 3, 0, 0 );
				delay( 120 );
			}

			iNumAttacks--;
		}

		delay( 60 );

		// All done!
		changestate( Main );		
	}
}
//-----------------------------------------------------------------------------
state Attack2Start
{
	OnEnter
	{
		delay( 150 );

		// First wave - gap in right/center.
		SetAnimation( "attack", -1, 0 );
		PlaySound( "mechron_attack.wav", 100, 0, SFXPRIORITY_HIGHEST );

		TweakSpreadPosition( -1 );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron" );
		SetTarget( SETTARGET_TAG, 19, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 20, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 21, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 22, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );

		TweakSpreadPosition( -1 );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron" );
		SetTarget( SETTARGET_TAG, 23, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 24, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 25, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 26, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );

		TweakSpreadPosition( 1 );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron" );
		SetTarget( SETTARGET_TAG, 31, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 32, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 33, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 34, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );

		TweakSpreadPosition( 0 );

		// The delay between waves depends on the difficulty.
		if ( GetDifficulty( ) == DIFFICULTY_HARD )
			delay( 90 );
		else if ( GetDifficulty( ) == DIFFICULTY_MEDIUM )
			delay( 105 );
		else
			delay( 120 );

		// Second wave - gap in leftmost.
		SetAnimation( "attack", -1, 0 );
		PlaySound( "mechron_attack.wav", 100, 0, SFXPRIORITY_HIGHEST );

		TweakSpreadPosition( -1 );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron" );
		SetTarget( SETTARGET_TAG, 23, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 24, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 25, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 26, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );

		TweakSpreadPosition( 1 );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron" );
		SetTarget( SETTARGET_TAG, 27, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 28, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 29, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 30, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );

		TweakSpreadPosition( 1 );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron" );
		SetTarget( SETTARGET_TAG, 31, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 32, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 33, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 34, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );

		TweakSpreadPosition( 0 );

		// The delay between waves depends on the difficulty.
		if ( GetDifficulty( ) == DIFFICULTY_HARD )
			delay( 90 );
		else if ( GetDifficulty( ) == DIFFICULTY_MEDIUM )
			delay( 105 );
		else
			delay( 120 );

		// Third wave - gap in rightmost.
		SetAnimation( "attack", -1, 0 );
		PlaySound( "mechron_attack.wav", 100, 0, SFXPRIORITY_HIGHEST );

		TweakSpreadPosition( -1 );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron" );
		SetTarget( SETTARGET_TAG, 19, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 20, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 21, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 22, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );

		TweakSpreadPosition( -1 );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron" );
		SetTarget( SETTARGET_TAG, 23, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 24, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 25, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 26, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );

		TweakSpreadPosition( 1 );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron" );
		SetTarget( SETTARGET_TAG, 27, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 28, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 29, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 30, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );

		TweakSpreadPosition( 0 );

		// The delay between waves depends on the difficulty.
		if ( GetDifficulty( ) == DIFFICULTY_HARD )
			delay( 90 );
		else if ( GetDifficulty( ) == DIFFICULTY_MEDIUM )
			delay( 105 );
		else
			delay( 120 );

		// Fourth (and final) wave - gap in left/center.
		SetAnimation( "attack", -1, 0 );
		PlaySound( "mechron_attack.wav", 100, 0, SFXPRIORITY_HIGHEST );

		TweakSpreadPosition( -1 );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron" );
		SetTarget( SETTARGET_TAG, 19, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 20, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 21, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 22, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );

		TweakSpreadPosition( 1 );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron" );
		SetTarget( SETTARGET_TAG, 27, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 28, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 29, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 30, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );

		TweakSpreadPosition( 1 );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron" );
		SetTarget( SETTARGET_TAG, 31, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 32, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 33, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 34, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );

		TweakSpreadPosition( 0 );

		// The delay between waves depends on the difficulty.
		if ( GetDifficulty( ) == DIFFICULTY_HARD )
			delay( 90 );
		else if ( GetDifficulty( ) == DIFFICULTY_MEDIUM )
			delay( 105 );
		else
			delay( 120 );

		delay( 60 );

		// All done!
		changestate( Main );		
	}

	MainLoop
	{
	}
}

//-----------------------------------------------------------------------------
state Attack2
{
	OnEnter
	{
		// First, move onto the center pillar.
		SetAnimation( "Move", -1, 0 );
		ExecuteMapScript( "MechronMove", 2, 0, 0, 0 );
		delay( 120 );
		ClearFlag( FLAG_IMMUNETODEATH );
		delay( 180 );

		// First wave - gap in right/center.
		SetAnimation( "attack", -1, 0 );
		PlaySound( "mechron_attack.wav", 100, 0, SFXPRIORITY_HIGHEST );

		TweakSpreadPosition( -1 );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron" );
		SetTarget( SETTARGET_TAG, 19, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 20, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 21, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 22, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );

		TweakSpreadPosition( -1 );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron" );
		SetTarget( SETTARGET_TAG, 23, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 24, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 25, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 26, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );

		TweakSpreadPosition( 1 );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron" );
		SetTarget( SETTARGET_TAG, 31, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 32, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 33, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 34, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );

		TweakSpreadPosition( 0 );

		// The delay between waves depends on the difficulty.
		if ( GetDifficulty( ) == DIFFICULTY_HARD )
			delay( 90 );
		else if ( GetDifficulty( ) == DIFFICULTY_MEDIUM )
			delay( 105 );
		else
			delay( 120 );

		// Second wave - gap in leftmost.
		SetAnimation( "attack", -1, 0 );
		PlaySound( "mechron_attack.wav", 100, 0, SFXPRIORITY_HIGHEST );

		TweakSpreadPosition( -1 );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron" );
		SetTarget( SETTARGET_TAG, 23, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 24, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 25, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 26, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );

		TweakSpreadPosition( 1 );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron" );
		SetTarget( SETTARGET_TAG, 27, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 28, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 29, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 30, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );

		TweakSpreadPosition( 1 );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron" );
		SetTarget( SETTARGET_TAG, 31, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 32, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 33, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 34, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );

		TweakSpreadPosition( 0 );

		// The delay between waves depends on the difficulty.
		if ( GetDifficulty( ) == DIFFICULTY_HARD )
			delay( 90 );
		else if ( GetDifficulty( ) == DIFFICULTY_MEDIUM )
			delay( 105 );
		else
			delay( 120 );

		// Third wave - gap in rightmost.
		SetAnimation( "attack", -1, 0 );
		PlaySound( "mechron_attack.wav", 100, 0, SFXPRIORITY_HIGHEST );

		TweakSpreadPosition( -1 );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron" );
		SetTarget( SETTARGET_TAG, 19, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 20, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 21, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 22, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );

		TweakSpreadPosition( -1 );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron" );
		SetTarget( SETTARGET_TAG, 23, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 24, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 25, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 26, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );

		TweakSpreadPosition( 1 );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron" );
		SetTarget( SETTARGET_TAG, 27, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 28, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 29, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 30, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );

		TweakSpreadPosition( 0 );

		// The delay between waves depends on the difficulty.
		if ( GetDifficulty( ) == DIFFICULTY_HARD )
			delay( 90 );
		else if ( GetDifficulty( ) == DIFFICULTY_MEDIUM )
			delay( 105 );
		else
			delay( 120 );

		// Fourth (and final) wave - gap in left/center.
		SetAnimation( "attack", -1, 0 );
		PlaySound( "mechron_attack.wav", 100, 0, SFXPRIORITY_HIGHEST );

		TweakSpreadPosition( -1 );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron" );
		SetTarget( SETTARGET_TAG, 19, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 20, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 21, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 22, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );

		TweakSpreadPosition( 1 );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron" );
		SetTarget( SETTARGET_TAG, 27, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 28, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 29, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 30, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );

		TweakSpreadPosition( 1 );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron" );
		SetTarget( SETTARGET_TAG, 31, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 32, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 33, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );
		SetTarget( SETTARGET_TAG, 34, false );
		FireProjectileAtTarget( "Rocket_Mechron", 1, 0, FPF_DIRECTLYATTARGET );

		TweakSpreadPosition( 0 );

		// The delay between waves depends on the difficulty.
		if ( GetDifficulty( ) == DIFFICULTY_HARD )
			delay( 90 );
		else if ( GetDifficulty( ) == DIFFICULTY_MEDIUM )
			delay( 105 );
		else
			delay( 120 );

		delay( 60 );

		// All done!
		changestate( Main );		
	}

	MainLoop
	{
	}
}

//-----------------------------------------------------------------------------
state Attack3
{
	int	iNumAttacks;

	MainLoop
	{
		// First, move onto the right pillar.
		SetAnimation( "Move", -1, 0 );
		ExecuteMapScript( "MechronMove", 3, 0, 0, 0 );
		delay( 120 );
		ClearFlag( FLAG_IMMUNETODEATH );
		SetTarget( SETTARGET_PLAYER, -1, false );
		delay( 180 );

		// Set up the number of attacks.
		if ( GetDifficulty( ) == DIFFICULTY_HARD )
			iNumAttacks = 5;
		else if ( GetDifficulty( ) == DIFFICULTY_MEDIUM )
			iNumAttacks = 3;
		else
			iNumAttacks = 1;

		while ( iNumAttacks > 0 )
		{
			// Play the attack animation and sound.
			SetAnimation( "attack", -1, 0 );
			PlaySound( "mechron_attack.wav", 100, 0, SFXPRIORITY_HIGHEST );

			// Launch the attack. The number of rockets and delay depend on the difficulty.
			SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Rocket_Mechron_Seeking" );
			if ( GetDifficulty( ) == DIFFICULTY_HARD )
			{
				FireProjectileAtTarget( "Rocket_Mechron_Seeking1", 1, 0, 0 );
				delay( 60 );
			}
			else if ( GetDifficulty( ) == DIFFICULTY_MEDIUM )
			{
				FireProjectileAtTarget( "Rocket_Mechron_Seeking1", 1, 0, 0 );
				delay( 90 );
			}
			else
			{
				FireProjectileAtTarget( "Rocket_Mechron_Seeking1", 1, 0, 0 );
				delay( 120 );
			}

			iNumAttacks--;
		}

		delay( 60 );

		// All done!
		changestate( Main );		
	}
}

//-----------------------------------------------------------------------------
state DeathSequence
{
	event_instant( "animation over" )
	{
		// Spawn an explosion particle.
		SetSpawnPosition( SPAWNPOSITION_FROMCENTER, GetIntProperty( "height" ) / 2, false, "" );
		SpawnParticles( "ExplosionParticle", 1, true, 0, ANGLE_90 * -1 );

		// Make our body disappear.
		AddFlag( FLAG_DONTRENDER );

		// Toss some gibs.
		SetSpawnPosition( SPAWNPOSITION_FROMCENTER, 0, false, "" );
		SpawnItem( "Mechron_Gib1" );
		SetSpawnPosition( SPAWNPOSITION_FROMCENTER, GetIntProperty( "height" ) / 2, false, "" );
		TossGib( "Mechron_Gib2", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), true );
		TossGib( "Mechron_Gib3", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), true );
		TossGib( "Mechron_Gib4", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), true );
		TossGib( "Mechron_Gib5", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), true );
		TossGib( "Mechron_Gib6", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), true );
		TossGib( "Mechron_Gib7", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), true );
		TossGib( "Mechron_Gib8", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), true );

		// Fade from white and pause for a couple seconds.
		FadeFromColor( 255, 255, 255, 60 );
		delay( 120 );
	}

	// One second before the end of the death animation, begin fading to
	// white.
	event_instant( "fade to white" )
	{

		// Also, play the screen shaking script.
		ExecuteMapScript( "MechronScreenShake", 0, 0, 0, 0 );
	}

	OnEnter
	{
		// Face the boss as it blows apart.
		ExecuteMapScript( "MechronSpecialDeath", 0, 0, 0, 0 );

		// Play our death sound.
		PlaySound( "mechron_death.wav", 100, SFXF_NON3D, SFXPRIORITY_HIGHEST );

		// Stop allowing other objects to collide with us.
		StopBlocking( );

		// Play our death animation.
		SetAnimation( "Death", -1, ANIMF_DONTBLEND );
	}

	MainLoop
	{
	}
}
