/*
	Lan Wars.
	Copyright (c) 2009, 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.
*/

#ifndef GAME_CHARACTER_H
#define GAME_CHARACTER_H

//=====================================================================================================================
//=====================================================================================================================

#include "GameObjects\PositionalObject.h"
#include "Game\GameSpriteBank.h"

//=====================================================================================================================
//=====================================================================================================================

namespace Game
{
	//=================================================================================================================
	//=================================================================================================================
	
	class DoomLevel;
	class SpriteAnimation;

	//=================================================================================================================
	/// @brief		This is the base class for any character (player or enemy) in the game.
	//=================================================================================================================

	class GameCharacter : public PositionalObject
	{
		public:
		
			//=========================================================================================================
			// Constants
			//=========================================================================================================
			
				/// This is the amount of downwards gravity velocity per second to apply to the player
				
				static const float GRAVITY;

		
			//=========================================================================================================
			// Structs
			//=========================================================================================================
				
				/// Stores a predicted move on the client side and it's result
				
				struct PredictedMove
				{
					/// This is id of the move: it is incremented on each move made
					
					unsigned m_move_id;
					
					/// Right/left move speed from -1 to 1
					
					float m_x_mov;
					
					/// Forward/back move speed from -1 to 1
					
					float m_z_mov;
					
					/// The amount of x rotation done
					
					float m_x_rot;
					
					/// The amount of y rotation done
					
					float m_y_rot;
					
					/// This is the result of the predicted move: x rotation
					
					float m_result_x_rot;
					
					/// This is the result of the predicted move: y rotation
					
					float m_result_y_rot;
					
					/// This is the result of the predicted move: position
					
					Vec3f m_result_position;
					
					/// If true then we are to fire
					
					bool m_fire;

					/// If true then we have sent this move off to the server. False otherwise.

					bool m_sent_to_server;
					
					/// Creates a default move that does nothing:
					
					PredictedMove()
					{ 
						m_move_id			= 0; 
						m_x_mov				= 0;
						m_z_mov				= 0;
						m_x_rot				= 0;
						m_y_rot				= 0;
						m_result_position	= Vec3f::Zero();
						m_sent_to_server	= false;
						m_fire				= false;
					}
					
					/// Tells if no move has been performed:
					
					bool IsEmptyMove()
					{
						if ( m_x_mov == 0 && m_z_mov == 0 )
						{
							if ( m_x_rot == 0 && m_y_rot == 0 )
							{
								// Empty move
								
								return true;
							}							
						}
						
						// Not an empty move
						
						return false;		
					}					
				};

			//=========================================================================================================
			// Functions
			//=========================================================================================================
			
				/// Constructor. Creates the character 
				
				GameCharacter
				( 
					const Vec3f & position							,
					unsigned owner_net_id							,
					float width										, 
					float height									, 
					GameSpriteBank::Sprite sprite					,
					unsigned net_id = NetObject::NET_ID_INVALID 		
				);	
				
				/// Destructor.
				
				~GameCharacter();
				
				/// Gets the x rotation of the character (pitch)
				
				inline float GetRotationX() const { return m_x_rot; }
				
				/// Gets the y rotation of the character (yaw)
				
				inline float GetRotationY() const { return m_y_rot; }
				
				/// Sets the x rotation of the character (pitch)
				
				inline void SetRotationX( float rot ){ m_x_rot = rot; }
				
				/// Sets the y rotation of the character (yaw)
				
				inline void SetRotationY( float rot ){ m_y_rot = rot; }
				
				/// Returns the width of the character
				
				inline float GetWidth(){ return m_width; }
				
				/// Returns the height of the character
				
				inline float GetHeight(){ return m_height; }
				
				/// Draws the character
				
				virtual void OnDraw( Camera3D * c );
				
				/// Returns the flattened (on the y axis) forward vector for the character
				
				Vec3f GetFlatForward() const;
				
				/// Returns the flattened (on the y axis) right vector for the character
				
				Vec3f GetFlatRight() const;

				/// Returns the forward vector for the character

				Vec3f GetForward() const;

				/// Returns the up vector for the character

				Vec3f GetUp() const;

				/// Tells if the given predicted move with the given id is in the list of predicted moves we made

				bool HavePredictedMove( unsigned id ) const;

				/// Gets the predicted move with the given id

				PredictedMove GetPredictedMove( unsigned id ) const;

				/// Removes all predicted moves, including and up to moves with the given id

				void CleanPredictedMoveList( unsigned id );
				
				/// Server only: Apply a force to the player
				
				void ApplyForce( Vec3f force );
				
				/// Corrects spawn orientation for the object both on the client and server:
				
				void CorrectSpawnOrientation();
				
		protected:	
		
			//=========================================================================================================
			// Variables
			//=========================================================================================================
			
				/// Variable used on the client only. Id of the next move to make.
				
				unsigned m_next_move_id;
				
				/// This is our animated sprite
				
				SpriteAnimation * m_sprite;
								
		protected:					

			//=========================================================================================================
			// Variables
			//=========================================================================================================
		
				/// These are the predicted moves carried out by the client and the result of these moves. Most recent moves are put to the back of the list.
				
				std::list<PredictedMove> m_predicted_moves;
				
				/// The rotation about the x axis for the character (pitch)
				
				float m_x_rot;
				
				/// The rotation about the z axis for the chacter (yaw)
				
				float m_y_rot;

				/// The width of the character. This is half width. This is for the sprite only.
				
				float m_width;
				
				/// The height of the character. This is half height. This is for the sprite only.
				
				float m_height;
				
				/// This is the velocity force currently applied to the character. This is created from impulsive forces and gravity.
				
				Vec3f m_velocity_force;
	};
};

#endif 
