//=============================================================================
//
//	giggordo1.txt
//
//	This is the script for the E1L6' boss, Giggordo. For his intro sequence, he
//	drops down from his chute, plays an animation, and starts a cutscene. Once
//	the battle starts, he randomly choose one of four attacks. Attack #1 has him
//	fire a pair of spinning spike balls that eventually slam into a wall. Attack
//	#2 has wall cannons fire all across the room, and the player must use
//	Giggordo as a shield. Attack #3 has him jump into the air, landing causing a
//	quake attack, and firing a spread shot which must be crouched under. Attack
//	#4 has him firing a spread attack as he spins around.
//
//	For documentation on scripting, please consult the Wrack Wiki at:
//	http://wrack.wikia.com/
//
//=============================================================================

#include "commondefines.h"


#define	THRUST_HORIZONTAL		8
#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	Idle;
state	StartAttack1;
state	Attack1;
state	StartAttack2;
state	Attack2;
state	StartAttack3;
state	Attack3;
state	StartAttack4;
state	Attack4;
state	Damaged;
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( );
}

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

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

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

state Spawn
{
	OnEnter
	{
		
		if ( QuakeAttack( 0, 8 * MAPUNIT_MULTIPLIER, 512 * MAPUNIT_MULTIPLIER, 0 ))
			DoScreenShake( SST_FADEOUT, 65536, ANGLE_1, 60 );
		g_iLastAttack = -1;
	}

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

//-----------------------------------------------------------------------------
state IntroSequence
{
	event( "animation over" )
	{
		changestate( Main );
	}

	OnEnter
	{
		// Play our intro animation.
		SetAnimation( "Intro", -1, 0 );

		// Play his intro sound.
		PlaySound( "giggordo1_intro.wav", 100, SFXF_NON3D, SFXPRIORITY_HIGHEST );
	}

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

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

	OnEnter
	{
		// Play our idle animation and sound.
		SetAnimation( "Idle", -1, ANIMF_LOOP );
		PlaySound( "giggordo1_idle.wav", 100, SFXF_STOPEXISTING_ALL | SFXF_LOOP, SFXPRIORITY_HIGHEST );
	}

	MainLoop
	{
		Delay (50);
		// 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, 4 );

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

		// Save the attack.
		g_iLastAttack = iAttack;

		switch ( iAttack )
		{
		case 1:

			changestate( StartAttack1 );
			break;
		case 2:

			changestate( StartAttack2 );
			break;
		case 3:

			changestate( StartAttack3 );
			break;
		case 4:

			changestate( StartAttack4 );
			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 );
	}

	MainLoop
	{
	}
}

//-----------------------------------------------------------------------------
state StartAttack1
{
	MainLoop
	{
		// Face the northern wall.
		SetTarget( SETTARGET_TAG, 12, false );
		FaceTarget( true, 60 );
		SetLookDeltaAnimation( "Delta", 4, 8, ANGLE_1 * 15, 15 );
		SetAnimation( "Turn", 60, 0 );
		PlaySound( "giggordo1_turn.wav", 100, SFXF_STOPEXISTING_ALL, SFXPRIORITY_HIGHEST );
		delay( 60 );
		SetTarget( SETTARGET_PLAYER, -1, false );

		// Begin the attack.
		changestate( Attack1 );
	}
}

//-----------------------------------------------------------------------------
state Attack1
{
	event( "animation almost over" )
	{
		// All done!
		changestate( Main );
	}

	event( "spawn spikeballs" )
	{
		// Fire our outward-spiraling spike balls (must be dodged in the corner).
		SetSpawnPosition( SPAWNPOSITION_FROMCENTER, 0, false, "" );
		SpawnItem( "SpikeBall_Moving_Giggordo_L1" );
		delay( 1 );
		SpawnItem( "SpikeBall_Moving_Giggordo_R1" );
	}

	OnEnter
	{
		// Set the attack animation and sound.
		SetAnimation( "Attack1", -1, 0 );
		PlaySound( "giggordo1_attack1.wav", 100, SFXF_STOPEXISTING_ALL, SFXPRIORITY_HIGHEST );
	}

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

//-----------------------------------------------------------------------------
state StartAttack2
{
	MainLoop
	{
		// Face the southern wall.
		SetTarget( SETTARGET_TAG, 253, false );
		FaceTarget( true, 60 );
		SetAnimation( "Turn", 60, 0 );
		SetLookDeltaAnimation( "Delta", 4, 8, ANGLE_1 * 15, 15 );
		PlaySound( "giggordo1_turn.wav", 100, SFXF_STOPEXISTING_ALL, SFXPRIORITY_HIGHEST );
		delay( 60 );
		SetTarget( SETTARGET_PLAYER, -1, false );

		// Begin the attack.
		changestate( Attack2 );
	}
}

//-----------------------------------------------------------------------------
state Attack2
{
	event( "missile shooters" )
	{
		// Run the script which handles the attack.
		ExecuteMapScript( "GiggordoMissileShooterAttack", 0, 0, 0, 0 );

	}

	event_instant( "self damaged" )
		changestate( Damaged );
	
	MainLoop
	{
		// Set the attack animation and sound.
		SetAnimation( "Attack2", -1, 0 );
		PlaySound( "giggordo1_attack2.wav", 100, SFXF_STOPEXISTING_ALL, SFXPRIORITY_HIGHEST );

		// Wait a few seconds while the turrets do their thing.
		delay( 300 );

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

//-----------------------------------------------------------------------------
state StartAttack3
{
	MainLoop
	{
		// Face the eastern wall.
		SetTarget( SETTARGET_TAG, 254, false );
		FaceTarget( true, 60 );
		SetAnimation( "Turn", 60, 0 );
		SetLookDeltaAnimation( "Delta", 4, 8, ANGLE_1 * 15, 15 );
		PlaySound( "giggordo1_turn.wav", 100, SFXF_STOPEXISTING_ALL, SFXPRIORITY_HIGHEST );
		delay( 60 );
		SetTarget( SETTARGET_PLAYER, -1, false );

		// Begin the attack.
		changestate( Attack3 );
	}
}

//-----------------------------------------------------------------------------
state Attack3
{
	event( "animation almost over" )
	{
		// Loop the idle animation for the rest of the attack.
		SetAnimation( "Idle", -1, ANIMF_LOOP );
	}

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

		// Wait a bit, then face our target.
		delay( 60 );

		// Face our target.
		FaceTarget( true, -1 );
		delay( 15 );
		
		// Fire a spread of seeking projectiles.
		SetSpawnPositionAtBone( "gunggordo", true, "Missile_Seeking" );
		FireProjectileAtTarget( "Missile_Seeking", 3, ANGLE_1 * 30, 0 );

		// Wait a bit, and then go back to the main state.
		if ( GetSkillSettingFlags( ) & SKILL_VERYAGGRESSIVE )
			delay( 60 );
		else if ( GetSkillSettingFlags( ) & SKILL_AGGRESSIVE )
			delay( 90 );
		else
			delay( 120 );

		changestate( Main );
	}

	OnEnter
	{
		// Set the attack animation and sound.
		SetAnimation( "Attack3", -1, 0 );
		PlaySound( "giggordo1_attack3.wav", 100, SFXF_STOPEXISTING_ALL, SFXPRIORITY_HIGHEST );
	}

	MainLoop
	{
	}
}

//-----------------------------------------------------------------------------
state StartAttack4
{
	MainLoop
	{
		// Face the player.
		SetTarget( SETTARGET_PLAYER, -1, false );
		FaceTarget( true, 60 );
		SetAnimation( "Turn", 60, 0 );
		SetLookDeltaAnimation( "Delta", 4, 8, ANGLE_1 * 15, 15 );
		PlaySound( "giggordo1_turn.wav", 100, SFXF_STOPEXISTING_ALL, SFXPRIORITY_HIGHEST );
		delay( 60 );

		// Begin the attack.
		changestate( Attack4 );
	}
}

//-----------------------------------------------------------------------------
state Attack4
{
	event( "shoot" )
	{
		// Fire our gun in the direction we're currently facing.
		SetSpawnPositionAtBone( "gunggordo", true, "Missile_Giggordo" );
		FireProjectileAtTarget( "Missile_Giggordo1", 5, ANGLE_15, FPF_DONTANGLE );
	}

	event( "animation almost over" )
	{
		// All done!
		changestate( Main );
	}

	OnEnter
	{
		// Set the attack animation and sound.
		SetAnimation( "Attack4", -1, 0 );
		PlaySound( "giggordo1_attack4.wav", 100, SFXF_STOPEXISTING_ALL, SFXPRIORITY_HIGHEST );
	}

	MainLoop
	{
		// Continuously face our target.
		FaceTarget( false, -1 );
	}
}

//-----------------------------------------------------------------------------
state Damaged
{
	event( "animation almost over" )
	{
		// All done!
		changestate( Main );
	}

	OnEnter
	{
		// Play the damaged animation and sound.
		SetAnimation( "Damage", -1, 0 );
		PlaySound( "giggordo1_damage.wav", 100, SFXF_STOPEXISTING_ALL, SFXPRIORITY_HIGHEST );
	}

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

//-----------------------------------------------------------------------------
state DeathSequence
{
	event( "player died" )
{
}

	event( "fade to white" )
	{
		// Fade to and from white.
		delay( 60 );
		StopSounds( true );
	StopSounds( false );

	// Play our gib sound.
	PlaySound( "gib_blood.wav", 100, SFXF_STOPEXISTING_ALL, SFXPRIORITY_HIGH );

	// Spawn a bloody explosion particle.
	SetSpawnPosition( SPAWNPOSITION_FROMCENTER, GetIntProperty( "projectileheight" ), false, "" );
	SpawnParticles( "BloodExplosionParticle", 1, true, 0, ANGLE_90 * -1 );

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

	// Toss some gibs.
	SetSpawnPosition( SPAWNPOSITION_FROMCENTER, GetIntProperty( "height" ), false, "" );
		TossGib( "Arcturan_OrganGib1", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), false );
		TossGib( "Arcturan_SmallChunkGib1", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), false );
		TossGib( "Arcturan_LargeChunkGib1", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), false );
TossGib( "Arcturan_OrganGib1", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), false );
		TossGib( "Arcturan_SmallChunkGib1", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), false );
		TossGib( "Arcturan_LargeChunkGib1", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), false );
TossGib( "Arcturan_OrganGib1", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), false );
		TossGib( "Arcturan_SmallChunkGib1", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), false );
		TossGib( "Arcturan_LargeChunkGib1", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), false );
TossGib( "Arcturan_OrganGib1", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), false );
		TossGib( "Arcturan_SmallChunkGib1", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), false );
		TossGib( "Arcturan_LargeChunkGib1", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), false );
TossGib( "Arcturan_OrganGib1", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), false );
		TossGib( "Arcturan_SmallChunkGib1", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), false );
		TossGib( "Arcturan_LargeChunkGib1", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), false );		
TossGib( "Arcturan_LargeChunkGib1", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), false );
TossGib( "Arcturan_OrganGib1", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), false );
		TossGib( "Arcturan_SmallChunkGib1", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), false );
		TossGib( "Arcturan_LargeChunkGib1", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), false );

	AddFlag( FLAG_NOCOLLISIONAGAINST );
	AddFlag( FLAG_NOTHINGCOLLISION );
	AddFlag( FLAG_IMMUNETODAMAGE );
		FadeFromColor( 255, 255, 255, 60 );
	}

	event( "animation over" )
	{
	}

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

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

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

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

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