//=============================================================================
//
//	galactron.txt
//
//	This is the script for the final boss of episode 1, Galactron. For his
//	first attack, he lifts both arms and pounds the ground to his left/right
//	side. For his second attack, he punches the EW walls, then punches the NS
//	walls. This causes spikes to drop from the ceiling. For his third attack, he
//	sticks his arms out at the ground level and spins around. This hits you if
//	you're out in the open. For his fourth attack, he holds him arms up to the
//	side and fires a couple bouncing seeking projectiles. His final attack is a
//	charged railgun attack. He must be stunned (shotgun) to stop the attack.
//
//	For documentation on scripting, please consult the Wrack Wiki at:
//	http://wrack.wikia.com/
//
//=============================================================================

#include "commondefines.h"


#define	THRUST_HORIZONTAL	10
#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;

// Is our shield up? This impacts which attacks we can do.
int	g_iShieldUp;
int	g_iTyderiumCutscenePlayed;
int	g_Start;
int     g_last;

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

state	Spawn;
state	IntroSequence;
state	IntroShield;
state	Main;
state	Idle;
state	Shield;
state	Stagger;
state	Attack1;
state	Attack2;
state	Attack3;
state	Attack4;
state	Attack5;
state	Attack6;
state	Attack7;
state	DeathSequence;
state	DeathSequence2;

//== 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( );
}

event_instant( "Last one" )
{
		ClearFlag( FLAG_IMMUNETODEATH );
		ClearFlag( FLAG_HIDELIFEBAR );
		g_last = 1;
}

//-----------------------------------------------------------------------------
event( "player died" )
	ChangeState( Idle );

//-----------------------------------------------------------------------------
event( "tyderium impact" )
{
	if ( g_iShieldUp != 0 )
	{
		// The shield is now down.
		g_iShieldUp = 0;
		ClearFlag( FLAG_IMMUNETODAMAGE );

		// Make the shield invisible.
		SetMaterialVisibility( "muzz_galactron_shield.png", false );

		// Surprised face!
		SetMaterialTexture( "galactron_face_bsod.png", "galactron_face_surprise.png" );
		if (g_start)
			changestate( Shield );
		ChangeState( Stagger );
	}
}

event_instant( "Start" )
{
g_start=0;
if ( g_iShieldUp != 0 )
	{
		// The shield is now down.
		g_iShieldUp = 0;
		ClearFlag( FLAG_IMMUNETODAMAGE );

		// Make the shield invisible.
		SetMaterialVisibility( "muzz_galactron_shield.png", false );
	}

		// Surprised face!
		SetMaterialTexture( "galactron_face_bsod.png", "galactron_face_surprise.png" );
		ChangeState( Stagger );
}

//== 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 TossMachineGib( int iGib )
{
	switch ( iGib )
	{
	case 1:

		TossGib( "MachineGib_Bolt", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), false );
		break;
	case 2:

		TossGib( "MachineGib_LargeCog", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), false );
		break;
	case 3:

		TossGib( "MachineGib_SmallCog", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), false );
		break;
	case 4:

		TossGib( "MachineGib_Misc", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), false );
		break;
	case 5:

		TossGib( "MachineGib_CircuitBoard", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), false );
		break;
	}
}

void SetRandomFace( void )
{
	switch ( rand( 1, 7 ))
	{
	case 1:

		// Angry face!
		SetMaterialTexture( "galactron_face_bsod.png", "galactron_face_angry.png" );
		break;
	case 2:

		// Crying face!
		SetMaterialTexture( "galactron_face_bsod.png", "galactron_face_crying.png" );
		break;
	case 3:

		// Happy face!
		SetMaterialTexture( "galactron_face_bsod.png", "galactron_face_happy.png" );
		break;
	case 4:

		// Sad face!
		SetMaterialTexture( "galactron_face_bsod.png", "galactron_face_sad.png" );
		break;
	case 5:

		// Skull face!
		SetMaterialTexture( "galactron_face_bsod.png", "galactron_face_skull.png" );
		break;
	case 6:

		// Surprise face!
		SetMaterialTexture( "galactron_face_bsod.png", "galactron_face_surprise.png" );
		break;
	case 7:

		// Very sad face!
		SetMaterialTexture( "galactron_face_bsod.png", "galactron_face_verysad.png" );
		break;
	}
}

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

state Spawn
{
	OnEnter
	{
		g_last = 0;
		g_start = 1;
		AddFlag( FLAG_HIDELIFEBAR );
		AddFlag( FLAG_IMMUNETODEATH );
		// Initially make the shield invisible.
		SetMaterialVisibility( "muzz_galactron_shield.png", false );

		// Happy face!
		SetMaterialTexture( "galactron_face_bsod.png", "galactron_face_happy.png" );

		g_iLastAttack = 0;
		g_iShieldUp = 0;
		g_iTyderiumCutscenePlayed = 0;
	}

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

//-----------------------------------------------------------------------------
state IntroSequence
{
	event( "animation almost over" )
	{
		// Begin by arming our shield.
		changestate( IntroShield );
	}

	OnEnter
	{
		// Play the intro animation and sound.
		StopMusic( );
		FreezeAction( FA_NOTOBJECTS | FA_NOTFACEACTIONS | FA_NOTBOSS | FA_NOTPLAYERMOVEMENT | FA_NOTPLAYERANIMATION );
		SetAnimation( "Intro", 192, 0 );
		PlaySound( "galactron_intro.wav", 100, SFXF_NON3D, SFXPRIORITY_HIGHEST );
	}

	MainLoop
	{
	}
}

//-----------------------------------------------------------------------------
state IntroShield
{
	event( "animation almost over" )
	{
		ExecuteMapScript( "GalactronSpecialCutscene", 0, 0, 0, 0 );

		// Wait for the cutscene to be over.
		while ( IsCutsceneActive( ))
			delay( 1 );

		PlayBossMusic( );
		FreezeAction( FA_NONE );
		// Begin by arming our shield.
		changestate( Main );
	}

	event( "shield up" )
	{
		// Make the shield material visible.
		SetMaterialVisibility( "muzz_galactron_shield.png", true );

		// We're invulnerable while our shield is up.
		g_iShieldUp = 2;
		AddFlag( FLAG_IMMUNETODAMAGE );
	}

	OnEnter
	{
		// Play the shield animation and sound.
		SetAnimation( "Shield", -1, 0 );
		PlaySound( "galactron_shield.wav", 100, 0, SFXPRIORITY_HIGHEST );
	}

	MainLoop
	{
		// Just wait for the animation to finish.
	}
}

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

	OnEnter
	{
		// Play our idle animation.
		SetAnimation( "Idle", -1, ANIMF_LOOP );
		if (g_start)
			SetMaterialTexture( "galactron_face_bsod.png", "galactron_face_happy.png" );
		else if (g_last == 0)
			// Sad face!
			SetMaterialTexture( "galactron_face_bsod.png", "galactron_face_sad.png" );
		else
			SetMaterialTexture( "galactron_face_bsod.png", "galactron_face_verysad.png" );
	}

	MainLoop
	{
		// Face our target.
		FaceTarget8Way( true, false );

		// 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 (g_last == 0)
			Delay (50);
		if (g_start)
			delay (450);
		if ( GetSkillSettingFlags( ) & SKILL_VERYAGGRESSIVE )
{
			if (g_last == 0)
			delay( rand( 1, 4 ) * 15 );
}
		else if ( GetSkillSettingFlags( ) & SKILL_AGGRESSIVE )
{
			if (g_last == 0)
			delay( rand( 2, 8 ) * 15 );
}
		else
{
			if (g_last == 0)
			delay( rand( 4, 12 ) * 15 );
}

		// Randomly pick our attack.
			iAttack = rand( 0, 7 );
		// Make sure we don't do the same attack twice in a row.
		while ( iAttack == g_iLastAttack )
		{
				iAttack = rand( 0, 7 );
		}

		// Save the attack.
		g_iLastAttack = iAttack;
		switch ( iAttack )
		{
		case 0:

			if ( g_iShieldUp > 0 )
			changestate( Attack2 );
			else
			changestate( Shield );
			break;
		case 1:

			changestate( Attack1 );
			break;
		case 2:

			changestate( Attack2 );
			break;
		case 3:

			changestate( Attack3 );
			break;
		case 4:

			changestate( Attack4 );
			break;
		case 5:
			if (g_start)
			changestate( Attack4 );
			else
			changestate( Attack5 );
			break;
		case 6:
			if (g_last)
{
				changestate (Attack6);
				break;
			}
			if ( g_iShieldUp > 0 )
			changestate( Attack1 );
			else
			changestate( Shield );
			break;
		case 7:
			if (g_last)
{
				changestate (Attack7);
				break;
			}
			if ( g_iShieldUp > 0 )
			changestate( Attack3 );
			else
			changestate( Shield );
			break;
		}
	}
}

//-----------------------------------------------------------------------------
state Idle
{
	OnEnter
	{
		// Just face the dead player.
		SetTarget( SETTARGET_PLAYER, -1, false );
		FaceTarget( true, -1 );

		// Play our idle animation.
		SetAnimation( "Idle", -1, ANIMF_LOOP );

		// Overlay an animation to face our target.
//		SetLookDeltaAnimation( "Delta", 4, 8, ANGLE_1 * 100 );
	}

	MainLoop
	{
	}
}

//-----------------------------------------------------------------------------
state Shield
{
	event( "animation almost over" )
		changestate( Main );

	event( "shield up" )
	{
		// Make the shield material visible.
		SetMaterialVisibility( "muzz_galactron_shield.png", true );

		// We're invulnerable while our shield is up.
		g_iShieldUp = 1;
		AddFlag( FLAG_IMMUNETODAMAGE );
	}

	OnEnter
	{
		// Play the shield animation and sound.
		SetAnimation( "Shield", -1, 0 );
		PlaySound( "galactron_shield.wav", 100, 0, SFXPRIORITY_HIGHEST );
	}

	MainLoop
	{
		// Just wait for the animation to finish.
	}
}

//-----------------------------------------------------------------------------
state Stagger
{
	event( "animation almost over" )
	{

		changestate( Main );
	}

	OnEnter
	{
		// Play the stagger animation and sound.
		SetAnimation( "Stagger", -1, 0 );
		PlaySound( "galactron_stagger.wav", 100, 0, SFXPRIORITY_HIGHEST );
	}

	MainLoop
	{
		// Wait for the animation to finish.
	}
}

//-----------------------------------------------------------------------------
state Attack1
{
	event( "animation almost over" )
		changestate( Main );

	event( "ground slam" )
	{
		// Perform a quake attack.
		MoveLinearFromOrigin( 0, 64, 0 );
		QuakeAttack( GetIntProperty( "damage" ), GetIntProperty( "knockback" ), 1500 * MAPUNIT_MULTIPLIER, 0 );
		DoScreenShake( SST_FADEOUT, 262144, ANGLE_1 * 3, 60 );
		MoveLinearFromOrigin( 0, 0, 0 );
	}

	OnEnter
	{
/*
		// Face the northern wall before slamming the ground.
		SetTarget( SETTARGET_TAG, 101, false );
		FaceTarget( true, 15 );
		delay( 15 );
		SetTarget( SETTARGET_PLAYER, -1, false );
*/
		// Face our target.
		FaceTarget8Way( true, false );

		// Play the attack animation and sound.
		SetAnimation( "Attack1", -1, 0 );
		PlaySound( "galactron_attack1.wav", 100, SFXF_STOPEXISTING_ALL, SFXPRIORITY_HIGHEST );

		// Angry face!
		SetMaterialTexture( "galactron_face_bsod.png", "galactron_face_angry.png" );
	}

	MainLoop
	{
		// Wait for the animation to finish.
	}

	OnExit
	{
		// Just in case we stagger while targetting the northern wall.
		SetTarget( SETTARGET_PLAYER, -1, false );
	}
}

//-----------------------------------------------------------------------------
state Attack2
{
	event( "animation almost over" )
		changestate( Main );

	event( "pound" )
		ExecuteMapScript( "DropTheBalls", 0, 0, 0, 0 );

	OnEnter
	{
		// Face the southern wall before pounding the side wall.
		SetTarget( SETTARGET_TAG, 101, false );
		FaceTarget( true, 15 );
		delay( 15 );
		SetTarget( SETTARGET_PLAYER, -1, false );

		// Play the attack animation and sound.
		SetAnimation( "Attack2", -1, 0 );
		PlaySound( "galactron_attack2.wav", 100, SFXF_STOPEXISTING_ALL, SFXPRIORITY_HIGHEST );

		// Angry face!
		SetMaterialTexture( "galactron_face_bsod.png", "galactron_face_angry.png" );
	}

	MainLoop
	{
		// Wait for the animation to finish.
	}

	OnExit
	{
		// Just in case we stagger while targetting the southern wall.
		SetTarget( SETTARGET_PLAYER, -1, false );
	}
}

//-----------------------------------------------------------------------------
state Attack3
{
	event( "animation almost over" )
		changestate( Main );

	event( "smack" )
	{
		// Melee attack the target.
		MoveLinearFromOrigin( 0, 64, 0 );
		MeleeAttackTarget( GetIntProperty( "damage" ), GetIntProperty( "knockback" ), 0 );
		MoveLinearFromOrigin( 0, 0, 0 );
	}

	OnEnter
	{
		// Face our target.
		FaceTarget8Way( true, false );
		delay( 5 );

		// Play the attack animation and sound.
		SetAnimation( "Attack3", -1, 0 );
		PlaySound( "galactron_attack3.wav", 100, SFXF_STOPEXISTING_ALL, SFXPRIORITY_HIGHEST );

		// Angry face!
		SetMaterialTexture( "galactron_face_bsod.png", "galactron_face_angry.png" );
	}

	MainLoop
	{
		// Face our target the entire time during this attack.
		FaceTarget( false, -1 );
	}
}

//-----------------------------------------------------------------------------
state Attack4
{
	event( "animation almost over" )
		changestate( Main );

	event( "pew pew left" )
	{
		// Fire bouncing projectiles at our target that must be stood under.
		SetSpawnPositionAtBone( "finger_l_index_2", true, "Missile_Seeking_Bounce" );
		FireProjectileAtTarget( "Missile_Seeking_Bounce1", 1, 0, FPF_DONTPITCH );
	}

	event( "pew pew right" )
	{
		// Fire bouncing projectiles at our target that must be stood under.
		SetSpawnPositionAtBone( "finger_r_index_2", true, "Missile_Seeking_Bounce" );
		FireProjectileAtTarget( "Missile_Seeking_Bounce1", 1, 0, FPF_DONTPITCH );
	}

	OnEnter
	{
		// Face our target.
		FaceTarget8Way( true, false );
		delay( 5 );

		// Play the attack animation and sound.
		SetAnimation( "Attack4", -1, 0 );
		PlaySound( "galactron_attack4.wav", 100, SFXF_STOPEXISTING_ALL, SFXPRIORITY_HIGHEST );

		// Angry face!
		SetMaterialTexture( "galactron_face_bsod.png", "galactron_face_angry.png" );
	}

	MainLoop
	{
		// Face our target the entire time during this attack.
		FaceTarget( false, -1 );
	}
}
//-----------------------------------------------------------------------------
state Attack6
{
	event( "animation almost over" )
		changestate( Main );

	event( "pew pew left" )
	{
		// Fire bouncing projectiles at our target that must be stood under.
		SetSpawnPositionAtBone( "finger_l_index_2", true, "Rocket_Mechron_Seeking1" );
		FireProjectileAtTarget( "Rocket_Mechron_Seeking1", 1, 0, 0 );
	}

	event( "pew pew right" )
	{
		// Fire bouncing projectiles at our target that must be stood under.
		SetSpawnPositionAtBone( "finger_r_index_2", true, "Rocket_Mechron_Seeking1" );
		FireProjectileAtTarget( "Rocket_Mechron_Seeking1", 1, 0, 0 );
	}

	OnEnter
	{
		// Face our target.
		FaceTarget8Way( true, false );
		delay( 5 );

		// Play the attack animation and sound.
		SetAnimation( "Attack4", -1, 0 );
		PlaySound( "galactron_attack4.wav", 100, SFXF_STOPEXISTING_ALL, SFXPRIORITY_HIGHEST );

		// Angry face!
		SetMaterialTexture( "galactron_face_bsod.png", "galactron_face_angry.png" );
	}

	MainLoop
	{
		// Face our target the entire time during this attack.
		FaceTarget( false, -1 );
	}
}

//-----------------------------------------------------------------------------
state Attack5
{
	int	iShotFired;
	int	iDamageCount;

	event( "animation almost over" )
		changestate( Main );

	event( "tyderium impact" )
	{
		if ( g_iShieldUp != 0 )
		{
			// The shield is now down.
			g_iShieldUp = 0;
			ClearFlag( FLAG_IMMUNETODAMAGE );

			// Make the shield invisible.
			SetMaterialVisibility( "muzz_galactron_shield.png", false );
		}
	}

	event( "damaged" )
	{
		if ( iShotFired == false )
		{
			// Stagger if we've been damaged 20x during the charge.
			iDamageCount++;
			if (g_last == 0)
			{
			if ( iDamageCount == 20 )
			{
				// Crying face!
				SetMaterialTexture( "galactron_face_bsod.png", "galactron_face_crying.png" );

				changestate( Stagger );
			}
			}
			else
			{
			if ( iDamageCount == 60 )
			{
				// Crying face!
				SetMaterialTexture( "galactron_face_bsod.png", "galactron_face_crying.png" );

				changestate( Stagger );
			}
			}
		}
	}

	event( "fire" )
	{
		iShotFired = 1;

		// Fire a magnetar shot at the player.
		SetSpawnPositionAtBone( "fan", false, "" );
		MagnetarAttackTarget( GetStringProperty( "Projectile" ), "ImpactHandler_Magnetar", 100, GetIntProperty( "knockback" ), DF_ARMORPIERCING );
	}

	OnEnter
	{
		iShotFired = 0;
		iDamageCount = 0;

		// Face our target.
		FaceTarget8Way( true, false );
		delay( 5 );

		// Play the attack animation and sound.
		SetAnimation( "Attack5", -1, 0 );
		PlaySound( "galactron_attack5.wav", 100, SFXF_STOPEXISTING_ALL, SFXPRIORITY_HIGHEST );

		// Skull face!
		SetMaterialTexture( "galactron_face_bsod.png", "galactron_face_skull.png" );
	}

	MainLoop
	{
		// Face our target the entire time during this attack.
		FaceTarget( false, -1 );
	}
}

state Attack7
{
	MainLoop
	{
		ExecuteMapScript( "DisableOculusRedForceFields", 0, 0, 0, 0 );
		delay( 60 );
		ExecuteMapScript( "OculusSeekingRocketAttack", 0, 0, 0, 0 );
		delay( 120 );
		ExecuteMapScript( "EnableOculusRedForceFields", 0, 0, 0, 0 );
		delay( 60 );
		changestate( Main );
	}
}
//-----------------------------------------------------------------------------
state DeathSequence
{
	
	int	iGib1;
	int	iGib2;
	int	iGib3;
	int	iTick;
	int	Dead;

	event( "player died" )
{
}

	event_instant( "animation almost over" )
	{
		Dead = 0;

		// Wait for the cutscene to be over.
		while ( Dead == 1)
		{
			// Cycle through random faces.
			if (( iTick % 15 ) == 0 )
				SetRandomFace( );
			iTick++;

			delay( 1 );
		}

		changestate( DeathSequence2 );
	}

	OnEnter
	{
		StopBlocking( );
		DestroyChildren( );
		FreezeAction( FA_NOTOBJECTS | FA_NOTFACEACTIONS | FA_NOTBOSS | FA_NOTPLAYERMOVEMENT | FA_NOTPLAYERANIMATION );
		iTick = 0;

		// Face the player.
		FaceTarget( true, -1 );

		// Set the death animation and sound.
		SetAnimation( "Death1", -1, 0 );
		PlaySound( "galactron_death1.wav", 100, SFXF_STOPEXISTING_ALL | SFXF_NON3D, SFXPRIORITY_HIGHEST );

		// Face the boss as it blows apart.
		ExecuteMapScript( "GalactronSpecialDeath", 0, 0, 0, 0 );
		
		StopMusic( );
	}

	MainLoop
	{
		// Cycle through random faces.
		if (( iTick % 15 ) == 0 )
			iGib1 = rand( 1, 5 );
		iGib2 = rand( 1, 5 );
		while ( iGib2 == iGib1 )
			iGib2 = rand( 1, 5 );
		while (( iGib3 == iGib1 ) || ( iGib3 == iGib2 ))
			iGib3 = rand( 1, 5 );
		SetSpawnPosition( SPAWNPOSITION_FROMCENTER, GetIntProperty( "height" ) / 2, false, "" );
		TossMachineGib( iGib1 );
			SetRandomFace( );
		iTick++;
	}
}

//-----------------------------------------------------------------------------
state DeathSequence2
{
	event( "player died" )
{
}
	OnEnter
	{
		// Set the death animation and sound.
		SetAnimation( "Death2", -1, 0 );
		PlaySound( "galactron_death2.wav", 100, SFXF_STOPEXISTING_ALL | SFXF_NON3D, SFXPRIORITY_HIGHEST );

		// BSOD face!
		SetMaterialTexture( "galactron_face_bsod.png", "galactron_face_bsod.png" );

		// Fade to and from white.
		FadeToColor( 255, 255, 255, 90 );
		delay( 90 );
		FadeFromColor( 255, 255, 255, 90 );
		delay( 90 );
		Delay (150);
		FreezeAction( FA_NONE );
		AddFlag( FLAG_DONTRENDER );
	}

	MainLoop
	{
		// Wait for the animation to finish.
	}
}

