/***************************************************************************
 * player.h  -  header for the corresponding cpp file
 *
 * Copyright (C) 2003 - 2009 Florian Richter
 ***************************************************************************/
/*
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.
   
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef SMC_PLAYER_H
#define SMC_PLAYER_H

#include "../core/globals.h"
#include "../objects/ball.h"
#include "../objects/animated_sprite.h"

namespace SMC
{

/* *** *** *** *** *** *** *** *** Maryo states *** *** *** *** *** *** *** *** *** */

enum Maryo_type
{
	// normal
	MARYO_DEAD = 0,
	MARYO_SMALL = 1,
	MARYO_BIG = 2,
	MARYO_FIRE = 3,
	MARYO_ICE = 4,
	MARYO_CAPE = 5,
	MARYO_GHOST = 6,
	MARYO_DOG_SMALL = 21 // todo
};

/* *** *** *** *** *** *** *** *** Maryo image array positions *** *** *** *** *** *** *** *** *** */

enum Maryo_imgpos
{
	MARYO_IMG_STAND = 0,
	MARYO_IMG_WALK = 0, // walking also uses the stay image
	MARYO_IMG_RUN = 8,
	MARYO_IMG_FALL = 12,
	MARYO_IMG_JUMP = 14,
	MARYO_IMG_DEAD = 16,
	MARYO_IMG_DUCK = 18,
	MARYO_IMG_CLIMB = 20,
	MARYO_IMG_THROW = 22,
	MARYO_IMG_FLY = 26,
	MARYO_IMG_SPECIAL_1 = 34
};

/* *** *** *** *** *** *** *** How to move the camera *** *** *** *** *** *** *** *** */
enum Camera_movement
{
	CAMERA_MOVE_NONE = 0,	// No movement is used when changing level files
	CAMERA_MOVE_FLY = 1,	// Move the camera visibly
	CAMERA_MOVE_BLINK = 2,	// Fade out and back in at the destination position
	CAMERA_MOVE_ALONG_PATH = 3, // Move the camera along a given path
	CAMERA_MOVE_ALONG_PATH_BACKWARDS = 4 // Move the camera along a given path backwards
};

/* *** *** *** *** *** *** *** Player class *** *** *** *** *** *** *** *** *** *** */

class cPlayer : public cAnimated_Sprite
{
public:
	// constructor
	cPlayer( float x = m_default_pos_x, float y = m_default_pos_y );
	// destructor
	virtual ~cPlayer( void );

	// copy
	virtual cPlayer *Copy( void );

	// Init
	virtual void Init( void );
	// lets the Player hold in
	void Hold( void );

	/* Set the direction
	 * if new_start_direction is set also set the start/editor direction
	*/
	virtual void Set_Direction( const ObjectDirection dir, bool new_start_direction = 0 );

	// Set the ground object
	virtual bool Set_On_Ground( cSprite *obj, bool set_on_top = 1 );

	/* downgrade state ( if small maryo : dies )
	 * force : dies or a complete downgrade
	*/
	virtual void DownGrade( bool force = 0 );
	/* downgrade state ( if small maryo : dies )
	 * if delayed is set the downgrade is handled on the next game update
	 * force : dies or a complete downgrade
	*/
	void DownGrade_Player( bool delayed = 1, bool force = 0 );

	// moves in the current direction
	void Move_Player( float velocity, float vel_wrongway );
	// generate foot clouds
	void Generate_Feet_Clouds( cParticle_Emitter *anim = NULL );
	// Update the walking
	void Update_Walking( void );
	// Update the running
	void Update_Running( void );
	// Update the staying
	void Update_Staying( void );
	// Update the flying
	void Update_Flying( void );
	/* Stop flying
	 * parachute : if set fall slow with parachute
	*/
	void Stop_Flying( bool nparachute = 1 );
	// Start falling
	void Start_Falling( void );
	// Update falling
	void Update_Falling();
	// Start ducking
	void Start_Ducking( void );
	// Stop ducking
	void Stop_Ducking( void );
	// Update ducking
	void Update_Ducking( void );
	// Start climbing
	void Start_Climbing( void );
	// Update the climbing
	void Update_Climbing( void );
	// Test if colliding with climbable
	bool Is_On_Climbable( float move_y = 0.0f );
	// Set up the UpKeytime for better jumping detection
	void Start_Jump_Keytime( void );
	// Update the UpKeytime and start a jump if possible
	void Update_Jump_Keytime( void );
	// Start a jump with the given de-acceleration
	void Start_Jump( float deaccel = 0.08f );
	// Update jump
	void Update_Jump( void );

	// Update the active item
	void Update_Item( void );

	/* Release the Active Item
	 * if set_position is set the active item will be set in front of the player
	 * if no_action is set the item will just be released
	*/
	void Release_Item( bool set_position = 1, bool no_action = 0 );

	/* Set the Type
	 * animate : show type change animation
	 * sound : if set the upgrade sound is played
	 * temp_power : set the temp power item
	*/
	void Set_Type( Maryo_type new_type, bool animation = 1, bool sound = 1, bool temp_power = 0 );
	void Set_Type( SpriteType item_type, bool animation = 1, bool sound = 1, bool temp_power = 0 );
	// set the moving state
	void Set_Moving_State( Moving_state new_state );

	// default update
	virtual void Update( void );

	// Draw
	virtual void Draw( cSurface_Request *request = NULL );
	/* Draw an animation using the given new type
	 * ends with the new type set
	*/
	void Draw_Animation( Maryo_type new_mtype );
	// Returns the current image number without the direction modifier
	unsigned int Get_Image( void ) const;

	// Loads the images depending on maryo_type
	void Load_Images( void );

	/* Sets the best position to advance in size
	 * if only_check is set position is unchanged
	*/
	bool Change_Size( float x, float y, bool only_check = 0 );

	/* Player gets the given Item
	 * force : if true the player will use the item immediately
	 * and it will not be placed in the itembox
	 * base : must be given on non-item objects ( like shell )
	 */
	void Get_Item( SpriteType item_type, bool force = 0, cMovingSprite *base = NULL );
	
	// returns the current velocity modifier
	float Get_Vel_Modifier( void ) const;

	// Start a jump
	void Action_Jump( bool enemy_jump = 0 );
	// General input interact event
	void Action_Interact( input_identifier key_type );
	// Shoot if available
	void Action_Shoot( void );

	// Stop jump
	void Action_Stop_Jump( void );
	// Stop Interacting event
	void Action_Stop_Interact( input_identifier key_type );
	// Stop Shoot action
	void Action_Stop_Shoot( void );

	/* Adds a Fire/Ice-ball
	 * ball_start_angle : starting angle
	 * amount : the amount of balls to add
	 * Returns 1 if successful
	*/
	bool Ball_Add( ball_effect effect_type = FIREBALL_DEFAULT, float ball_start_angle = -1, unsigned int amount = 0 ) const;
	// Destroys all Fire/Ice-balls
	void Ball_Clear( void ) const;
	
	// Resets the complete game state
	void Reset_Save( void );
	/* Reset state and status
	 * if full is set reset item and camera state
	*/
	void Reset( bool full = 1 );
	// Reset position to start position
	void Reset_Position( void );

	// Exits the level and walks to the next Overworld waypoint
	void Goto_Next_Level( void );
	/* Enters the given level on the entry
	 * move_camera: set how to move the camera to the new position
	 * path_identifier: set the identifier of the path to move the camera along
	*/
	void Goto_Sub_Level( std::string str_level, const std::string &str_entry, Camera_movement move_camera = CAMERA_MOVE_FLY, const std::string &path_identifier = "" );
	
	// Add an enemy to the kill multiplier
	void Add_Kill_Multiplier( void );
	// Update the kill multiplier
	void Update_Kill_Multiplier( void );

	/* Validate the given collision object
	 * returns 0 if not valid
	 * returns 1 if an internal collision with this object is valid
	 * returns 2 if the given object collides with this object (blocking)
	*/
	virtual Col_Valid_Type Validate_Collision( cSprite *obj );

	// collision from an enemy
	virtual void Handle_Collision_Enemy( cObjectCollision *collision );
	// collision with massive
	virtual void Handle_Collision_Massive( cObjectCollision *collision );
	// collision with passive
	virtual void Handle_Collision_Passive( cObjectCollision *collision );
	// handle moved out of Level event
	virtual void Handle_out_of_Level( ObjectDirection dir );

	// editor activation
	virtual void Editor_Activate( void );
	// editor direction option selected event
	bool Editor_Direction_Select( const CEGUI::EventArgs &event );

	// current Maryo type
	Maryo_type maryo_type;
	//	Maryo type after the temporary powerup
	Maryo_type maryo_type_temp_power;

	// true if player godmode is active	
	bool godmode;

	// time maryo walked
	float walk_time;
	// running particle counter
	float running_particle_counter;
	// time maryo is in ghost mode
	float ghost_time;
	// ghost mode drawing modifier
	float ghost_time_mod;
	/* invincible time
	 * if 0 we are not invincible
	*/
	float invincible;
	// invincible time if maryo got a star
	float invincible_star;
	// invincible drawing modifier
	float invincible_mod;
	// invincible star counter
	float invincible_starcounter;

	// walking animation counter
	float walk_count;
	// lives left
	int lives;

	// jumping keytime
	float UpKeytime;
	// force next jump
	bool force_jump;
	// next jump with sound
	bool next_jump_sound;
	// next jump power
	float next_jump_power;
	// next jump acceleration
	float next_jump_accel;
	// Acceleration if up key is pressed
	float jump_accel_up;
	// vely De-acceleration use 0.05 - 0.08
	float jump_vel_deaccel;
	// next jump power
	float jump_power;

	// throw animation counter
	float throwing_counter;
	// if maryo is ducked
	Uint32 ducked;
	// ducked animation counter
	float ducked_animation_counter;
	// if parachute falling
	bool parachute;
	// amount of goldpieces collected
	unsigned int goldpieces;
	// collected points
	long points;
	// enemy killed in a row multiplier
	float kill_multiplier;
	// time since the last killed enemy
	float last_kill_counter;
	// time player didn't move
	float no_velx_counter, no_vely_counter;

	// fire/ice-ball shoot counter
	float shoot_counter;
	// active/holding object ( f.e. shell )
	cMovingSprite *active_object;
	// direction when ducking started ( for the anti stuck under a block test )
	ObjectDirection duck_direction;

	// default position
	static const float m_default_pos_x;
	static const float m_default_pos_y;
};

/* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */

// The Player
extern cPlayer *pPlayer;

/* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */

} // namespace SMC

#endif
