/*
	Trig Wars.
	Copyright (c) 2008, Darragh Coy.
	All rights reserved.
	Original work(s), source code & author(s) details available at: http://www.darraghcoy.com

	Redistribution and use in source and binary forms, with or without modification, are permitted 
	provided that the following conditions are met:

		* 	Redistributions of source code must retain the above copyright notice, this list of 
			conditions and the following disclaimer.
		* 	Redistributions in binary form must reproduce the above copyright notice, this list of 
			conditions and the following disclaimer in the documentation.
		* 	Neither the name of the author nor the names of contributors may be used to endorse or 
			promote products derived from this software without specific prior written permission.
		* 	The use of any third party libraries, modules or data files provided with the source 
			form of the program must follow and respect the individual licensing terms of these 
			components. You do not have permission to modify or circumvent the licensing terms for 
			provided third party components unless the third party licenses specifically allow this. 
			If you do not agree to the terms of provided third party components then you do not have 
			permission to use them in your derived work(s).
		* 	The terms of this license do not apply to separate (but related) distributions if supplied 
			by the author(s), only to the contents of this source distribution, derived works, and the 
			binaries produced by either modified or unmodified versions of the source code. The terms 
			of this license do not also apply to any third party libraries or components provided with 
			the source distribution. Such third party elements are licensed under their own separate 
			agreements.

	THIS SOFTWARE IS PROVIDED BY DARRAGH COY ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
	BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
	ARE DISCLAIMED. IN NO EVENT SHALL DARRAGH COY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
	OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
	IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

//=====================================================================================================================
/// @brief		Represents one of the enemie's bullets. Does collision with the ship.
//=====================================================================================================================

#include "Precompiled.h"
#include "GameObjects\EnemyBullet.h"
#include "GameObjects\PlayerShip.h"
#include "GameObjects\ObstacleManager.h"
#include "GameObjects\AIManager.h"
#include "Game\EnemyBulletManager.h"
#include "Game\GameCore.h"
#include "Graphics\ParticleEmitter.h"

using namespace Game;

//=====================================================================================================================
/// @brief		Moves the bullet and does collision with the player. This is used instead of regular OnUpdate()
///				because the view area is given to the bullet here and is calculated beforehand.
/// @param		delta_time - time between this frame and the last one
/// @param		cam_pos - position of the camera
/// @param		view_bl	- bottom left corner of the view area in world coordinates
/// @param		view_tr	- top right corner of the view area in world coordinates
/// @remarks	The viewing area should include extra padding to account for the size of the bullet when drawn, for 
///				once the bullet gets outside of this region it is immediately marked as being dead.
/// @pre		The game must exist
/// @pre		This should not be called when the bullet is dead
/// @pre		The bullet should have a bullet manager
/// @pre		The bullet manager used by the bullet should be a EnemyBulletManager
/// @pre		The bullet manager should have a reference to an ai manager
//=====================================================================================================================

void EnemyBullet::BulletUpdate( float delta_time , const Vec2f & cam_pos , const Vec2f & view_bl , const Vec2f & view_tr )
{
	ENSURE( GameCore::GetSingleton()							, "The game must exist"														);
	ENSURE( m_is_dead == false									, "This should not be called when the bullet is dead"						);
	ENSURE( m_manager != 0										, "The bullet should have a bullet manager"									);
	ENSURE( dynamic_cast<EnemyBulletManager*>(m_manager) != 0	, "The bullet manager used by the bullet should be a EnemyBulletManager"	);
	ENSURE( ((EnemyBulletManager*)(m_manager))->GetAIManager()	, "The bullet manager should have a reference to an ai manager"				);
		
	// Move the bullet along:
	
	BulletBase::OnUpdate(delta_time);
	
	// Get our position and unwrap relative to the camera position:
	
	Vec2f pos = PositionalObject::UnwrapCoordinates( cam_pos , GetPosition() );
	
	// See if we are offscreen:
	
	if ( pos.x < view_bl.x || pos.x > view_tr.x ) 
	{
		// Bullet is now dead
		
		m_is_dead = true;
	}
	else if ( pos.y < view_bl.y || pos.y > view_tr.y )  
	{
		// Bullet is now dead
		
		m_is_dead = true;		
	}
	else
	{		
		// Bullet not offscreen: get the player

		PlayerShip * player = ((EnemyBulletManager*)(GetBulletManager()))->GetPlayerShip();
		
		// Get the particle texture for a particle burst: may need it later
		
		Texture & particle_tex = ((EnemyBulletManager*)(GetBulletManager()))->GetParticleTexture();		
		
		// See if the player ship is there:
		
		if ( player )
		{
			// Player is there: get our square distance to it:
		
			float sq_dist = SqDistanceTo(player);
			
			// Get the radius of the player's bounding sphere:
			
			float sphere_radius = Float::Max( PlayerShip::SIZE.x , PlayerShip::SIZE.y );
			
			// See if we are in range:
			
			if ( sq_dist < sphere_radius * sphere_radius )
			{
				// In range: damage the player
				
				player->Damage( GetDamage() );
				
				// Now dead
				
				m_is_dead = true;
				
				// Only if valid: make an explosion at the player
				
				if ( particle_tex.IsValid() )
				{
					// Make the burst
					
					GameCore::GetSingleton()->GetParticleEmitter()->CreateBurst
					(
						1024							,
						particle_tex					,
						player->GetPosition()			,
						0.5f							,	// live time 1
						2.0f							,	// live time 2
						2.0f							,	// size 1
						10.0f							,	// size 2
						Color(0.0f,0.35f,0.95f,0.3f)	,	// color 1
						Color(1.0f,1.00f,0.25f,0.1f)	,	// color 2
						5.0f							,	// speed 1
						1500.0f							,	// speed 2
						false								// alpha blend
					);
				}				
			}
		}
		
		// Do collisions with obstacles:
		
		{
			// Get the obstacle manager:
			
			ObstacleManager * obs_mgr = ((EnemyBulletManager*)(m_manager))->GetAIManager()->GetObstacleManager();
			
			// See if there:
			
			if ( obs_mgr )
			{
				// Get the two stacks from the game:
				
				Stack & s1 = GameCore::GetSingleton()->GetStack();
				Stack & s2 = GameCore::GetSingleton()->GetSecondaryStack();
				
				// Save the pointer of stack 1: we don't care about individual collisons - only if there is one
				
				void * stack_ptr = s1.GetPointer();
				
				// Check for collisions with obstacles
				
				unsigned num_results = obs_mgr->ObstacleCollide( GetPosition() , 1 , s1 , s2 );
				
				// Restore old stack pointer in stack where results are:
				
				s1.SetPointer(stack_ptr);
				
				// Now see if there was a collision:
				
				if ( num_results > 0 )
				{
					// Collision: now dead
					
					m_is_dead = true;
					
					// Make an explosion if our particle texture is ok
					
					if ( particle_tex.IsValid() )
					{
						// Make the burst
						
						GameCore::GetSingleton()->GetParticleEmitter()->CreateBurst
						(
							256								,
							particle_tex					,
							GetPosition()					,
							0.5f							,	// live time 1
							1.0f							,	// live time 2
							2.0f							,	// size 1
							10.0f							,	// size 2
							Color(1.0f,0.35f,0.25f,0.7f)	,	// color 1
							Color(0.3f,0.20f,0.25f,0.4f)	,	// color 2
							5.0f							,	// speed 1
							100.0f							,	// speed 2
							false								// alpha blend
						);						
					}
				}	
			}
		}
		
		// Only if valid:
		
		if ( particle_tex.IsValid() )
		{
			// Make a burst of particles
			
			GameCore::GetSingleton()->GetParticleEmitter()->CreateDirectedBurst
			(
				32										,
				particle_tex							,
				GetPosition()							,
				-GetLinearVelocity()					,
				0.1f									,
				0.03f									,	// live time 1
				0.05f									,	// live time 2
				2.5f									,	// size 1
				1.0f									,	// size 2
				GetBulletManager()->GetBulletColor()	,	// color 1
				GetBulletManager()->GetBulletColor()	,	// color 2
				200.0f									,	// speed 1
				1000.0f									,	// speed 2
				false										// alpha blend
			);
		}
	}
}

//=====================================================================================================================
/// @brief		Annouces the type name for this object.
/// @returns	Type name of this object
//=====================================================================================================================

const char * EnemyBullet::GetTypeName() const
{
	return "EnemyBullet";
}