//=============================================================================
//
//	geizer2.txt
//
//	This is the script for the second encounter with Geizer, the E1L1 boss.
//	In this encounter, he has 3 attacks: sweeping the room with a laser-
//	like attack (you must stand on the top step to avoid it), a four
//	following missile attack (must be jumped over), and an attack in which
//	he fires a bunch of missiles while turning (must be crouched under). He
//	is the game's first boss.
//
//	On hardcore/bullshit, he has a 4th attack: the firing of wave missiles.
//	They must be dodged by crouching on the bottom step.
//
//	For documentation on scripting, please consult the Wrack Wiki at:
//	http://wrack.wikia.com/
//
//=============================================================================

#include "commondefines.h"

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

#define	THRUST_HORIZONTAL	20
#define	THRUST_VERTICAL		30

//== 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	BeginAttack1;
state	Attack1;
state	EndAttack1;
state	BeginAttack2;
state	Attack2;
state	EndAttack2;
state	BeginAttack3;
state	Attack3;
state	EndAttack3;
state	BeginAttack4;
state	Attack4;
state	EndAttack4;
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 ));
}

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

state Spawn
{
	OnEnter
	{

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

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

		// Randomly determine our "last" attack.
		if ( GetDifficulty( ) == DIFFICULTY_HARD )
			g_iLastAttack = rand( 1, 4 );
		else
			g_iLastAttack = rand( 1, 3 );
	}

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

//-----------------------------------------------------------------------------
state IntroSequence
{
	event( "animation over" )
	{
		// Play the idle sound, and have it play the entire time Geizer
		// is alive.
		PlaySound( "geizer2_idle.wav", 100, SFXF_LOOP, SFXPRIORITY_MEDIUM );

		changestate( Main );
	}

	OnEnter
	{
	}

	MainLoop
	{
	}
}

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

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

	MainLoop
	{
		// 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.
		if ( GetDifficulty( ) == DIFFICULTY_HARD )
			iAttack = rand( 1, 4 );
		else
			iAttack = rand( 1, 3 );

		// Make sure we don't do the same attack twice in a row.
		while ( iAttack == g_iLastAttack )
		{
			if ( GetDifficulty( ) == DIFFICULTY_HARD )
				iAttack = rand( 1, 4 );
			else
				iAttack = rand( 1, 3 );
		}

		// Save the attack.
		g_iLastAttack = iAttack;

		switch ( iAttack )
		{
		case 1:

			changestate( BeginAttack1 );
			break;
		case 2:

			changestate( BeginAttack2 );
			break;
		case 3:

			changestate( BeginAttack3 );
			break;
		case 4:

			changestate( BeginAttack4 );
			break;
		}
	}
}
//-----------------------------------------------------------------------------
state BeginAttack1
{
	int	iXDistance;
	int	iYDistance;

	OnEnter
	{
		// Play the warmup sound.
		PlaySound( "geizer2_attack_start.wav", 100, SFXF_LOOP, SFXPRIORITY_HIGHEST );

		// Play the warmup animation.
		SetAnimation( "Attack_Start", 24, 0 );

		iXDistance = 0;
		iYDistance = 0;
	}

	MainLoop
	{
		if ( iXDistance == -192 )
		{
			if ( GetSkillSettingFlags( ) & SKILL_VERYAGGRESSIVE )
				delay( FPS / 4 );
			else if ( GetSkillSettingFlags( ) & SKILL_AGGRESSIVE )
				delay( FPS / 2 );
			else
				delay( FPS );

			changestate( Attack1 );
		}

		if ( iXDistance <= -128 )
			iYDistance += 1;

		iXDistance -= 8;
		MoveLinearFromOrigin( iXDistance, iYDistance, 0 );
		Turn( ANGLE_YAW, ANGLE_1, false );
	}
}

//-----------------------------------------------------------------------------
state Attack1
{
	int	iXDistance;

	OnEnter
	{
		// Play the attack sound.
		PlaySound( "geizer2_attack.wav", 100, SFXF_LOOP, SFXPRIORITY_HIGHEST );

		// Play the attack animation.
		SetAnimation( "Attack_Loop", -1, ANIMF_LOOP );

		iXDistance = -192;
	}

	MainLoop
	{
		if ( iXDistance == 192 )
		{
			if ( GetSkillSettingFlags( ) & SKILL_VERYAGGRESSIVE )
				delay( FPS / 4 );
			else if ( GetSkillSettingFlags( ) & SKILL_AGGRESSIVE )
				delay( FPS / 2 );
			else
				delay( FPS );

			changestate( EndAttack1 );
		}

		iXDistance += 8;
		MoveLinearFromOrigin( iXDistance, 16, 0 );

		// This should eventually be a laser attack!
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Missile_Geizer" );
		FireProjectile( "Missile_Geizer1", 1, 0, 0 );
		Turn( ANGLE_YAW, ANGLE_1 * -1, false );
	}
}

//-----------------------------------------------------------------------------
state EndAttack1
{
	int	iXDistance;
	int	iYDistance;

	OnEnter
	{
		// Stop the looping attack sound, and restart our idle sound.
		PlaySound( "geizer2_idle.wav", 100, SFXF_LOOP | SFXF_STOPEXISTING_ALL, SFXPRIORITY_MEDIUM );

		// Play the cooldown sound.
		PlaySound( "geizer2_attack_end.wav", 100, 0, SFXPRIORITY_HIGHEST );

		// Play the cooldown animation.
		SetAnimation( "Attack_End", 32, 0 );

		iXDistance = 192;
		iYDistance = 16;
	}

	MainLoop
	{
		if ( iXDistance == 0 )
			changestate( Main );

		if ( iXDistance > 128 )
			iYDistance -= 1;

		iXDistance -= 4;
		MoveLinearFromOrigin( iXDistance, iYDistance, 0 );
		Turn( ANGLE_YAW, ANGLE_1 / 2, false );
	}
}

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

	OnEnter
	{
		// Play the warmup sound.
		PlaySound( "geizer2_attack_start.wav", 100, 0, SFXPRIORITY_HIGHEST );

		// Play the warmup animation.
		SetAnimation( "Attack_Start", -1, 0 );
	}

	MainLoop
	{
	}
}

//-----------------------------------------------------------------------------
state Attack2
{
	OnEnter
	{
		// Play the attack sound.
		PlaySound( "geizer2_attack.wav", 100, SFXF_LOOP, SFXPRIORITY_HIGHEST );

		// Play the attack animation.
		SetAnimation( "Attack_Loop", -1, ANIMF_LOOP );
	}

	MainLoop
	{
		// Fire 4 missiles 
		Turn( ANGLE_YAW, ANGLE_1 * 30, false );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Missile_Seeking_Geizer" );
		FireProjectile( "Missile_Seeking_Geizer1", 1, 0, 0 );
		Turn( ANGLE_YAW, ANGLE_1 * -30, false );
		if ( GetSkillSettingFlags( ) & SKILL_VERYAGGRESSIVE )
			delay( FPS / 4 );
		else if ( GetSkillSettingFlags( ) & SKILL_AGGRESSIVE )
			delay( FPS / 2 );
		else
			delay( FPS );

		Turn( ANGLE_YAW, ANGLE_1 * 10, false );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Missile_Seeking_Geizer" );
		FireProjectile( "Missile_Seeking_Geizer1", 1, 0, 0 );
		Turn( ANGLE_YAW, ANGLE_1 * -10, false );
		if ( GetSkillSettingFlags( ) & SKILL_VERYAGGRESSIVE )
			delay( FPS / 4 );
		else if ( GetSkillSettingFlags( ) & SKILL_AGGRESSIVE )
			delay( FPS / 2 );
		else
			delay( FPS );

		Turn( ANGLE_YAW, ANGLE_1 * -10, false );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Missile_Seeking_Geizer" );
		FireProjectile( "Missile_Seeking_Geizer1", 1, 0, 0 );
		Turn( ANGLE_YAW, ANGLE_1 * 10, false );
		if ( GetSkillSettingFlags( ) & SKILL_VERYAGGRESSIVE )
			delay( FPS / 4 );
		else if ( GetSkillSettingFlags( ) & SKILL_AGGRESSIVE )
			delay( FPS / 2 );
		else
			delay( FPS );

		Turn( ANGLE_YAW, ANGLE_1 * -30, false );
		SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Missile_Seeking_Geizer" );
		FireProjectile( "Missile_Seeking_Geizer1", 1, 0, 0 );
		Turn( ANGLE_YAW, ANGLE_1 * 30, false );
		if ( GetSkillSettingFlags( ) & SKILL_VERYAGGRESSIVE )
			delay( FPS / 2 );
		else if ( GetSkillSettingFlags( ) & SKILL_AGGRESSIVE )
			delay( FPS );
		else
			delay( FPS * 2 );

		// Tell all of the bolts to start moving.
		SendEvent( SENDEVENT_CHILDREN, "go" );

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

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

	OnEnter
	{
		// Stop the looping attack sound, and restart our idle sound.
		PlaySound( "geizer2_idle.wav", 100, SFXF_LOOP | SFXF_STOPEXISTING_ALL, SFXPRIORITY_MEDIUM );

		// Play the cooldown sound.
		PlaySound( "geizer2_attack_end.wav", 100, 0, SFXPRIORITY_HIGHEST );

		// Play the cooldown animation.
		SetAnimation( "Attack_End", -1, 0 );
	}

	MainLoop
	{
	}
}

//-----------------------------------------------------------------------------
state BeginAttack3
{
	int	iXDistance;
	int	iYDistance;

	OnEnter
	{
		// Play the warmup sound.
		PlaySound( "geizer2_attack_start.wav", 100, 0, SFXPRIORITY_HIGHEST );

		// Play the warmup animation.
		SetAnimation( "Attack_Start", 48, 0 );

		iXDistance = 0;
		iYDistance = 0;
	}

	MainLoop
	{
		if ( iXDistance == -192 )
			changestate( Attack3 );

		if ( iXDistance <= -64 )
			iYDistance += 1;

		iXDistance -= 4;
		MoveLinearFromOrigin( iXDistance, iYDistance, 0 );
	}
}

//-----------------------------------------------------------------------------
state Attack3
{
	int	iTick;
	int	iMissileTick;
	int	iYDistance;

	OnEnter
	{
		// Play the attack sound.
		PlaySound( "geizer2_attack.wav", 100, SFXF_LOOP, SFXPRIORITY_HIGHEST );

		// Play the attack animation.
		SetAnimation( "Attack_Loop", -1, ANIMF_LOOP );

		iTick = 0;
		iMissileTick = 0;
		Turn( ANGLE_YAW, ANGLE_90 * -1, false );
	}

	MainLoop
	{
		if ( iMissileTick == 0 )
		{
			SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Missile_Geizer" );
			FireProjectile( "Missile_Geizer1", 1, 0, 0 );
			iMissileTick = 2;
		}
		iMissileTick--;

		if ( GetSkillSettingFlags( ) & SKILL_VERYAGGRESSIVE )
		{
			if ( iTick == 210 )
				changestate( EndAttack3 );

			if (( iTick > 15 ) && ( iTick < 195 ))
				Turn( ANGLE_YAW, ANGLE_1 / 2, false );
		}
		else if ( GetSkillSettingFlags( ) & SKILL_AGGRESSIVE )
		{
			if ( iTick == 240 )
				changestate( EndAttack3 );

			if (( iTick > 30 ) && ( iTick < 210 ))
				Turn( ANGLE_YAW, ANGLE_1 / 2, false );
		}
		else
		{
			if ( iTick == 300 )
				changestate( EndAttack3 );

			if (( iTick > 60 ) && ( iTick < 240 ))
				Turn( ANGLE_YAW, ANGLE_1 / 2, false );
		}

		iTick++;
	}

	OnExit
	{
		MoveLinearFromOrigin( -192, 32, 0 );
	}
}

//-----------------------------------------------------------------------------
state EndAttack3
{
	int	iXDistance;
	int	iYDistance;

	OnEnter
	{
		// Stop the looping attack sound, and restart our idle sound.
		PlaySound( "geizer2_idle.wav", 100, SFXF_LOOP | SFXF_STOPEXISTING_ALL, SFXPRIORITY_MEDIUM );

		// Play the cooldown sound.
		PlaySound( "geizer2_attack_end.wav", 100, 0, SFXPRIORITY_HIGHEST );

		// Play the cooldown animation.
		SetAnimation( "Attack_End", 48, 0 );

		iXDistance = -192;
		iYDistance = 32;
	}

	MainLoop
	{
		if ( iXDistance == 0 )
			changestate( Main );

		if ( iXDistance >= -128 )
			iYDistance -= 1;

		iXDistance += 4;
		MoveLinearFromOrigin( iXDistance, iYDistance, 0 );
	}
}


//-----------------------------------------------------------------------------
state BeginAttack4
{
	int	iXDistance;
	int	iYDistance;

	OnEnter
	{
		// Play the warmup sound.
		PlaySound( "geizer2_attack_start.wav", 100, 0, SFXPRIORITY_HIGHEST );

		// Play the warmup animation.
		SetAnimation( "Attack_Start", 24, 0 );

		iXDistance = 0;
		iYDistance = 0;
	}

	MainLoop
	{
		if ( iXDistance == 192 )
		{
			if ( GetSkillSettingFlags( ) & SKILL_VERYAGGRESSIVE )
				delay( FPS / 4 );
			else if ( GetSkillSettingFlags( ) & SKILL_AGGRESSIVE )
				delay( FPS / 2 );
			else
				delay( FPS );

			changestate( Attack4 );
		}

		iXDistance += 8;
		if ( iXDistance > 64 )
			iYDistance += 4;

		MoveLinearFromOrigin( iXDistance, iYDistance, 0 );
		Turn( ANGLE_YAW, -100, false );
	}
}

//-----------------------------------------------------------------------------
state Attack4
{
	int	iXDistance;
	int	iTick;
	int	iReverse;

	OnEnter
	{
		// Play the attack sound.
		PlaySound( "geizer2_attack.wav", 100, SFXF_LOOP, SFXPRIORITY_HIGHEST );

		// Play the attack animation.
		SetAnimation( "Attack_Loop", -1, ANIMF_LOOP );

		iXDistance = 192;
		iTick = 7;

		iReverse = 0;
	}

	MainLoop
	{
		if ( iXDistance == -192 )
		{
			if ( GetSkillSettingFlags( ) & SKILL_VERYAGGRESSIVE )
				delay( FPS / 4 );
			else if ( GetSkillSettingFlags( ) & SKILL_AGGRESSIVE )
				delay( FPS / 2 );
			else
				delay( FPS );

			changestate( EndAttack4 );
		}

		iXDistance -= 2;
		MoveLinearFromOrigin( iXDistance, 64, 0 );
		Turn( ANGLE_YAW, 25, false );

		// Fire our wave projectile attack.
		if ( iTick == 0 )
		{
			if ( iReverse == 0 )
			{
				SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Missile_WaveY_Geizer" );
				FireProjectile( "Missile_WaveY_Geizer", 1, 0, 0 );
				iReverse = 1;
				iTick = 8;
			}
			else
			{
				SetSpawnPosition( SPAWNPOSITION_INFRONT, GetIntProperty( "projectileheight" ), true, "Missile_WaveY_Geizer_Reverse" );
				FireProjectile( "Missile_WaveY_Geizer_Reverse", 1, 0, 0 );
				iReverse = 0;
				iTick = 7;
			}

		}
		else
			iTick--;
	}
}

//-----------------------------------------------------------------------------
state EndAttack4
{
	int	iXDistance;
	int	iYDistance;

	OnEnter
	{
		// Stop the looping attack sound, and restart our idle sound.
		PlaySound( "geizer2_idle.wav", 100, SFXF_LOOP | SFXF_STOPEXISTING_ALL, SFXPRIORITY_MEDIUM );

		// Play the cooldown sound.
		PlaySound( "geizer2_attack_end.wav", 100, 0, SFXPRIORITY_HIGHEST );

		// Play the cooldown animation.
		SetAnimation( "Attack_End", 48, 0 );

		iXDistance = -192;
		iYDistance = 64;
	}

	MainLoop
	{
		if ( iXDistance == 0 )
			changestate( Main );

		iXDistance += 4;
		if ( iXDistance <= -64 )
			iYDistance -= 2;
		MoveLinearFromOrigin( iXDistance, iYDistance, 0 );
		Turn( ANGLE_YAW, -50, false );
	}
}

//-----------------------------------------------------------------------------
state DeathSequence
{
	int	iExplosionParticleTick;

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

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

		// Toss some gibs.
		SetSpawnPosition( SPAWNPOSITION_FROMCENTER, GetIntProperty( "height" ) / 2, false, "" );
		TossGib( "Geizer_Gib1", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), true );
		TossGib( "Geizer_Gib2", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), true );
		TossGib( "Geizer_Gib3", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), true );
		TossGib( "Geizer_Gib4", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), true );
		TossGib( "Geizer_Gib5", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), true );
		TossGib( "Geizer_Gib6", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), true );
		TossGib( "Geizer_Gib7", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), true );
		TossGib( "Geizer_Gib8", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), true );
		TossGib( "Geizer_Gib9", CalcHorizontalGibThrust( ), CalcVerticalGibThrust( ), CalcHorizontalGibThrust( ), true );

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

		// Play a shot cutscene sequence involving Exo.
	}

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

	OnEnter
	{
		// Destroy our child projectiles.
		SendEvent( SENDEVENT_CHILDREN, "explode" );

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

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

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

		// Spawn some explosion particles during the death sequence.
		iExplosionParticleTick = 1;
	}

	MainLoop
	{
		if ( iExplosionParticleTick )
		{
			iExplosionParticleTick--;
			if ( iExplosionParticleTick == 0 )
			{
				// Spawn an explosion particle.
				SetSpawnPosition( SPAWNPOSITION_FROMCENTER, GetIntProperty( "height" ) / 2, false, "" );
				SpawnParticles( "ExplosionParticle_Geizer2", 1, true, 0, ANGLE_90 * -1 );

				// Setup the timer to make another one.
				iExplosionParticleTick = rand( 6, 15 );
			}
		}
	}
}
