
enum eRocketAnims
{
	anim_Rocket_Load   = anim_weaponAttack1,
	anim_Rocket_Fire   = anim_weaponFireCharged,
	anim_Rocket_Rotate = anim_weaponAttack2
}

final class TurokRocketLauncher : TurokWeapon
{
	int loaded;
	bool bRockets;

	TurokRocketLauncher( kWeapon@ a )
	{
		super( a );
		BobDamping = 0.975f;
	}

	void AnimProperties( int&out first, int&out last, float&out rate, bool&out bLoop )
	{
		rate = 60; bLoop = false;
		switch ( PlayingID() )
		{
			case anim_weaponSwapIn:  first =   0; last =  35; break;
			case anim_weaponSwapOut: first = 452; last = 475; break;
			case anim_Rocket_Load:   switch ( loaded ) {
			                 case 0: first =  63; last =  91; break;
			                 case 1: first = 108; last = 136; break;
			                 case 2: first = 187; last = 215; break;
			                 case 3: first = 270; last = 298; break;
			                 case 4: first = 476; last = 504; break;
			                 case 5: first = 521; last = 549; break; } break;
			case anim_Rocket_Fire:   switch ( loaded ) {
			                 case 0: first =      last =  63; break; // done firing, next anim not yet started
			                 case 1: first =  36; last =  63; break; // (^ only happens 1 tick when out of ammo)
			                 case 2: first = 136; last = 169; break;
			                 case 3: first = 215; last = 248; break;
			                 case 4: first = 298; last = 335; break;
			                 case 5: first = 354; last = 397; break;
			                 case 6: first = 398; last = 451; break; } break;
			case anim_Rocket_Rotate: switch ( loaded ) {
			                 case 1: first =  91; last = 108; break;
			                 case 2: first = 170; last = 187; break;
			                 case 3: first = 249; last = 270; break;
			                 case 4: first = 336; last = 353; break;
			                 case 5: first = 504; last = 521; break; } break;
			default: /* idle */      first =      last =  35; bLoop = true; break;
		}
	}

	void AnimEnd()
	{
		switch ( PlayingID() )
		{
			case anim_Rocket_Load:
				++loaded;
				if ( loaded == 1 && !bFire )
					PlayAnim( anim_weaponIdle );
				else
					Rotate();
				return;
			case anim_Rocket_Fire:
				loaded = 0;
				if ( !HasAmmo() )
					break; // stop and return to idle
				// else fall through and load
			case anim_Rocket_Rotate:
				PlayAnim( anim_Rocket_Load );
				PlayWeaponSound( "U1/sounds/Eightball/Load.ksnd" );
				return;
		}
		TurokWeapon::AnimEnd();
	}

	void OnTick()
	{
		TurokWeapon::OnTick();
		AmmoLED();

		switch ( PlayingID() )
		{
			// do this here instead of OnFire() so AnimEnd() has a chance to return to idle after reloading
			// if fire is not pressed, instead of firing again
			// also lets us update custom input vars first
			case anim_Rocket_Load: case anim_Rocket_Rotate:
				// figure out fire mode for next sequence while reloading first rocket
				if ( loaded < 1 )
					CheckFireMode();
				else if ( (bRockets && !bFire1) || (!bRockets && !bFire2) )
					ShootLoad();
				break;
			case anim_Rocket_Fire:
				Recoil();
		}
	}

	void Recoil()
	{
		float L = (loaded-1) / 5.0f;
		float f = 0.5f;//0.4f + 0.1f * L;

		if ( PlayTime() > f ) return;
		f = 1 - PlayTime() / f;

		float g = f*f;
		OwnerP().RecoilPitch() = Math::Sin( Math::pi * g );
		if ( g > 0.5f ) OwnerP().RecoilPitch() = Math::Sqrt( OwnerP().RecoilPitch() );
		else            OwnerP().RecoilPitch() *= OwnerP().RecoilPitch();
		OwnerP().RecoilPitch() *= -0.03f - 0.02f * L;

		g *= f*f;
		if ( bRockets )
		{
			OwnerP().Roll() = Math::Sin( Math::pi * g );
			if ( g > 0.5f ) OwnerP().Roll() = Math::Sqrt( OwnerP().Roll() );
			else            OwnerP().Roll() = float( OwnerP().Roll() ) * OwnerP().Roll();
		}
		else
			OwnerP().Roll() = Math::Sin( 2 * Math::pi * g ) * g * -1.5f;
		OwnerP().Roll() = OwnerP().Roll() * (-0.02f - 0.01f * L);
	}

	void OnBeginFire()
	{
		// if we're coming from idle, we only have 1 loaded
		// which we need to ensure is set in case we were put down after ammo ran out
		loaded = 1;
		CheckFireMode();
		Rotate();
	}

	void ShootLoad()
	{
		PlayAnim( anim_Rocket_Fire );
		StopWeaponSound(); // stop load/rotate sound

		bool bCluster;
		array<kStr> proj = { "UT/fx/Rocket/", "" };
		kVec3 origin( 10, 25, -5 );

		if ( bRockets )
		{
			bCluster = bFire2;
			self.PlaySound( "U1/sounds/Eightball/Fire_Rocket.ksnd");
			proj[0] += "Rocket";
		}
		else // grenades
		{
			bCluster = true;
			self.PlaySound( "U1/sounds/Eightball/Fire_Grenade.ksnd");
			proj[0] += "Grenade";
			// compensate for bOffsetFromFloor
			origin -= kVec3( 0, 0, 10 ) * kQuat( OwnerP().Pitch(), 1,0,0 );
		}
		proj[1] = proj[0] + "_Even";
		if ( UDamage() )
		{
			proj[0] += "_Amp";
			proj[1] += "_Amp";
		}
		proj[0] += ".kfx";
		proj[1] += ".kfx";

		kVec3 offset( (bCluster && loaded > 1) ? -8.75f : -5, 0, 0 );
		kQuat offsetInc( Math::Deg2Rad(-360/6), 0,1,0 );

		//      m
		//     l r x x
		//    l m r x x
		//   l l r r x
		//  l l m r r
		// l l l r r r
		int minAngle = 1 - loaded;
		int maxAngle = loaded - 1;
		int angle = minAngle;
		int angleInc = 4;
//		Sys.Print ( "shoot load" );
		for ( int i=0; i<loaded; ++i )
		{
			kVec3 v = origin + offset;
			float rand;
			if ( loaded > 1 )
			{
				rand = Math::RandFloat();
				v.y += rand * 20;
			}
			else
				rand = 0.5f;

			if ( bRockets )
			{
				kQuat q = OwnerP().Rotation();
				if ( !bCluster )
				{
					q = q * kQuat( Math::Deg2Rad( 1.43f * angle ), 0,0,1 );
					angle += angleInc;
					if ( angle > maxAngle )
					{
						angle -= 2 + 4 * (loaded % 2);
						angleInc = -angleInc;
					}
				}
				SpawnProj( proj[ i % 2 ], v, q, kVec3( 0, 900 + rand*100, 0 ) * q * GAME_DELTA_TIME );
			}
			else // grenades
			{
				kVec3 dir = kVec3( 0,1,0 ) * OwnerP().Rotation();
				if ( loaded > 1 ) dir.Randomize( 0.05f );
				float speed = 600;
				kVec3 vel = dir * (speed + 100*rand);
				vel.z += speed * 0.2f;
				SpawnProj( proj[ i % 2 ], v, dir, vel * GAME_DELTA_TIME );
			}

			offset = offset * offsetInc;
		}

		self.Owner().Actor().LoudNoiseAlert();
		self.Owner().ConsumeAmmo( loaded );
	}

	void Rotate()
	{
		if ( loaded >= 6 || loaded >= GetAmmo() )
			ShootLoad();
		else
		{
			PlayAnim( anim_Rocket_Rotate );
			PlayWeaponSound( "U1/sounds/Eightball/Rotate.ksnd" );
		}
	}

	void CheckFireMode()
	{
		bRockets = bFire1;
	}
}
