///////////////////////////////////////////////////////////////////////////////
//
// File   : AVP_MovesMelee.h
// Author : Chris Wallace
// Date   : 23-Jan-2008
//
// Copyright (C) 2008 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
	#pragma once
#endif   // ifdef ASURA_USE_PRAGMA_ONCE

#ifndef __AVP_MOVES_MELEE_H__
#define __AVP_MOVES_MELEE_H__

////////////////////////////////////////////////////////////////////////////////
// Include files...
////////////////////////////////////////////////////////////////////////////////

#include "Blueprint/Asura_Blueprint.h"
#include "Core/Asura_HashedList.h"

#include "Core/AVP_Settings.h"
#include "Moves/AVP_Moves.h"


////////////////////////////////////////////////////////////////////////////////
// Forward class declarations...
////////////////////////////////////////////////////////////////////////////////

class Asura_Message; 
class AVP_ClientEntity_Actor;
class AVP_ClientEntity_PhysicalObject;

////////////////////////////////////////////////////////////////////////////////
// Class declaration...
////////////////////////////////////////////////////////////////////////////////

const u_int uAVP_MOVE_MELEE_MAX_VARIATIONS = 8;

////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_Move_Melee
// Author       : Chris Wallace
// Date         : 02-May-2007
////////////////////////////////////////////////////////////////////////////////

class AVP_Move_Melee : public AVP_Move
{
public:
	// Public functions...
	AVP_Move_Melee(Asura_Movement_System& xParentSystem, const Asura_Hash_ID uHash );
	virtual ~AVP_Move_Melee();

	bool HasBeenCountered() const { return m_bHasBeenCountered; }
	void SetHasBeenCountered(bool bCountered) { m_bHasBeenCountered = bCountered; }

	bool HasDoneDamage() const { return m_bHasDoneDamage; }
	void SetHasDoneDamage(bool bDone) { m_bHasDoneDamage = bDone; }

	u_int GetVariation( void ) const { return m_uVariation; }

	u_int GetPendingVariation() const { return m_uPendingVariation; }
	u_int GetPendingAttackType() const { return m_uPendingAttackType; }

	void SetFirstPersonAnimHashesForVariations(const Asura_Hash_ID* puHashes, u_int uNumVariations);
	void SetThirdPersonAnimHashesForVariations(const Asura_Hash_ID* puHashes, u_int uNumVariations);

	Asura_Guid GetHitEntity() const { return m_uHitEntity; }
	Asura_Hash_ID GetPendingGrappleBlueprint() const { return m_uPendingGrappleBlueprint; }

	virtual Asura_Guid GetTargetGuid() const { return m_uTargetGuid; }

	virtual u_int GetNumVariations() const { return Asura_Maths::Max(m_uNumFirstPersonVariations, m_uNumThirdPersonVariations); }

protected:
	// Protected functions...

	// Overridden functions...
	virtual	bool ShouldStart() const { return false; }
	virtual bool Start(const Asura_Msg_Move* pxStartMsg);
	virtual bool HandleMessage( const Asura_Message* pxMessage );
	virtual void Abort();
	virtual void Finish();

	virtual void SendStartMsg(); 

	virtual void UpdateStates(const float fTimeStep);
	
	void SetVariation(u_int uVariation);

	void SetupAnimHashesFromBlueprint(const Asura_Blueprint* pxFirstPersonBlueprint, const Asura_Blueprint* pxThirdPersonBlueprint, const char* szParameterName);
	void SetupAnimHashesFromBlueprint(const Asura_Blueprint* pxFirstPersonBlueprint, const Asura_Blueprint* pxThirdPersonBlueprint, const Asura_Hash_ID uParameterHash);

	Asura_Message* CreateStartMsg(); 

	// Protected variables...
	Asura_Guid m_uTargetGuid;

	Asura_Hash_ID m_auFirstPersonAnimHashes[uAVP_MOVE_MELEE_MAX_VARIATIONS];
	Asura_Hash_ID m_auThirdPersonAnimHashes[uAVP_MOVE_MELEE_MAX_VARIATIONS];
	u_int m_uNumFirstPersonVariations;
	u_int m_uNumThirdPersonVariations;

	u_int m_uVariation;

	Asura_Guid m_uHitEntity; // Set by the melee attack hit message, and queried by the follow-up moves (only when that message has set the appropriate flag to true, so this will always be valid when checked).
	Asura_Hash_ID m_uPendingGrappleBlueprint; // Can be set by the melee attack hit message, or set in advance (although the don't clear flag below will also need setting in the latter case). If not ASURA_HASH_ID_UNSET and the hit entity is not unregistered, the AVP_Move_Melee_Grapple_Start::ShouldStart function will return true if called.

	// Details that may be handy for follow-on moves.
	u_int m_uPendingVariation; // May want to be different to the current variation in some rare cases.
	u_int m_uPendingAttackType; // Simple way to enable branching grapple selection making consistent choices across the network.

	union
	{
		u_int m_uMeleeFlags;
		struct
		{
			u_int	m_bHasDoneDamage					: 1,
					m_bHasBeenCountered					: 1,
					m_bLookAtEnemyByAnimFlag			: 1,
					m_eAimDirectionUsageBackup			: 2,	// The aim direction usage to return to should the move end or the anim flag turn off.
					m_bDontClearPendingGrappleBlueprint	: 1,	// By default we'll set the pending grapple back to ASURA_HASH_ID_UNSET on reset. If this move always goes to a grapple on a hit and we can permanently store the blueprint name, set this flag to true.
														: 0;
		};
	};

private:
	// Private typedef...
	typedef AVP_Move PARENT;

	// Private variables...
#ifdef ASURA_DEBUG_VARIABLE_SYSTEM
	static u_int s_uConsolevarCount;
#endif //#ifdef ASURA_DEBUG_VARIABLE_SYSTEM
};   // End of class 'AVP_Move_Melee'.


////////////////////////////////////////////////////////////////////////////////
// Generic melee attack sequence (start -> hit/miss/countered).
// Since so many attacks will follow this pattern we can share a lot of the code.
////////////////////////////////////////////////////////////////////////////////

class AVP_Move_Melee_GenericAttack_Start : public AVP_Move_Melee
{
public:
	// Public functions...
	AVP_Move_Melee_GenericAttack_Start(Asura_Movement_System& xParentSystem, const Asura_Hash_ID uHash,
										const Asura_Hash_ID uBlueprintType, const Asura_Hash_ID uFirstPersonBlueprintHash, const Asura_Hash_ID uThirdPersonBlueprintHash, const char* szBaseParameterName,
										const Asura_Hash_ID uHitReturnMove, const Asura_Hash_ID uCounteredReturnMove, const Asura_Hash_ID uMissReturnMove);
	// Second constructor for when we know we only have one animation set
	AVP_Move_Melee_GenericAttack_Start(Asura_Movement_System& xParentSystem, const Asura_Hash_ID uHash,
										const Asura_Hash_ID uBlueprintType, const Asura_Hash_ID uFirstPersonBlueprintHash, const Asura_Hash_ID uThirdPersonBlueprintHash, const Asura_Hash_ID uParameterHash,
										const Asura_Hash_ID uHitReturnMove, const Asura_Hash_ID uCounteredReturnMove, const Asura_Hash_ID uMissReturnMove);
	// Third constructor for when subclasses want to do something more involved to sort out the animations.
	AVP_Move_Melee_GenericAttack_Start(Asura_Movement_System& xParentSystem, const Asura_Hash_ID uHash,
										const Asura_Hash_ID uHitReturnMove, const Asura_Hash_ID uCounteredReturnMove, const Asura_Hash_ID uMissReturnMove);
	virtual ~AVP_Move_Melee_GenericAttack_Start();

	static float GetMinSuckDistance() { return s_fMinSuckDistance; }

protected:
	// Overridden functions...
	virtual bool Start(const Asura_Msg_Move* pxStartMsg);
	virtual void UpdateStates(const float fTimeStep);
	virtual void Finish();
	virtual void Abort();

	Asura_MoveData_PositionInterpolation m_xPositionInterpolation;
	bool m_bTargetChaseActive;
	bool m_bAllowSuckToEnemy;

private:
	// Private typedef...
	typedef AVP_Move_Melee PARENT;

	static float s_fMinSuckDistance;
	static float s_fSuckTargetDistance;

#ifdef ASURA_DEBUG_VARIABLE_SYSTEM
	static u_int s_uDVSVarCount;
#endif //#ifdef ASURA_DEBUG_VARIABLE_SYSTEM
};   // End of class 'AVP_Move_Melee_GenericAttack_Start'.


class AVP_Move_Melee_GenericAttack_Return_Hit : public AVP_Move_Melee
{
public:
	// Public functions...
	AVP_Move_Melee_GenericAttack_Return_Hit(Asura_Movement_System& xParentSystem, const Asura_Hash_ID uHash,
											const Asura_Hash_ID uBlueprintType, const Asura_Hash_ID uFirstPersonBlueprintHash, const Asura_Hash_ID uThirdPersonBlueprintHash, const char* szBaseParameterName);
	// Second constructor for when we know we only have one animation set
	AVP_Move_Melee_GenericAttack_Return_Hit(Asura_Movement_System& xParentSystem, const Asura_Hash_ID uHash,
											const Asura_Hash_ID uBlueprintType, const Asura_Hash_ID uFirstPersonBlueprintHash, const Asura_Hash_ID uThirdPersonBlueprintHash, const Asura_Hash_ID uParameterHash);
	// Third constructor for when subclasses want to do something more involved to sort out the animations.
	AVP_Move_Melee_GenericAttack_Return_Hit(Asura_Movement_System& xParentSystem, const Asura_Hash_ID uHash);
	//	virtual ~AVP_Move_Melee_GenericAttack_Return_Hit();

protected:
	// Overridden functions...
	virtual	bool ShouldStart() const;
	virtual bool Start(const Asura_Msg_Move* pxStartMsg);

private:
	// Private typedef...
	typedef AVP_Move_Melee PARENT;
};   // End of class 'AVP_Move_Melee_GenericAttack_Return_Hit'.


class AVP_Move_Melee_GenericAttack_Return_Countered : public AVP_Move_Melee
{
public:
	// Public functions...
	AVP_Move_Melee_GenericAttack_Return_Countered(Asura_Movement_System& xParentSystem, const Asura_Hash_ID uHash,
													const Asura_Hash_ID uBlueprintType, const Asura_Hash_ID uFirstPersonBlueprintHash, const Asura_Hash_ID uThirdPersonBlueprintHash, const char* szBaseParameterName);
	// Second constructor for when we know we only have one animation set
	AVP_Move_Melee_GenericAttack_Return_Countered(Asura_Movement_System& xParentSystem, const Asura_Hash_ID uHash,
													const Asura_Hash_ID uBlueprintType, const Asura_Hash_ID uFirstPersonBlueprintHash, const Asura_Hash_ID uThirdPersonBlueprintHash, const Asura_Hash_ID uParameterHash);
	// Third constructor for when subclasses want to do something more involved to sort out the animations.
	AVP_Move_Melee_GenericAttack_Return_Countered(Asura_Movement_System& xParentSystem, const Asura_Hash_ID uHash);
	//	virtual ~AVP_Move_Melee_GenericAttack_Return_Countered();

protected:
	// Overridden functions...
	virtual	bool ShouldStart() const;
	virtual bool Start(const Asura_Msg_Move* pxStartMsg);

private:
	// Private typedef...
	typedef AVP_Move_Melee PARENT;
};   // End of class 'AVP_Move_Melee_GenericAttack_Return_Countered'.


class AVP_Move_Melee_GenericAttack_Return_Miss : public AVP_Move_Melee
{
public:
	// Public functions...
	AVP_Move_Melee_GenericAttack_Return_Miss(Asura_Movement_System& xParentSystem, const Asura_Hash_ID uHash,
												const Asura_Hash_ID uBlueprintType, const Asura_Hash_ID uFirstPersonBlueprintHash, const Asura_Hash_ID uThirdPersonBlueprintHash, const char* szBaseParameterName);
	// Second constructor for when we know we only have one animation set
	AVP_Move_Melee_GenericAttack_Return_Miss(Asura_Movement_System& xParentSystem, const Asura_Hash_ID uHash,
												const Asura_Hash_ID uBlueprintType, const Asura_Hash_ID uFirstPersonBlueprintHash, const Asura_Hash_ID uThirdPersonBlueprintHash, const Asura_Hash_ID uParameterHash);
	// Third constructor for when subclasses want to do something more involved to sort out the animations.
	AVP_Move_Melee_GenericAttack_Return_Miss(Asura_Movement_System& xParentSystem, const Asura_Hash_ID uHash);
	//	virtual ~AVP_Move_Melee_GenericAttack_Return_Miss();

protected:
	// Overridden functions...
	virtual	bool ShouldStart() const;
	virtual bool Start(const Asura_Msg_Move* pxStartMsg);

private:
	// Private typedef...
	typedef AVP_Move_Melee PARENT;
};   // End of class 'AVP_Move_Melee_GenericAttack_Return_Miss'.


// Full default sequence and counter, with interchangable animations, so we can blueprint the default melee attack fully with most, if not all, weapons.

////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_Move_Melee_DefaultAttack_Start
// Author       : Anthony Gregson
// Date         : 24/04/08
////////////////////////////////////////////////////////////////////////////////

class AVP_Move_Melee_DefaultAttack_Start : public AVP_Move_Melee_GenericAttack_Start
{
public:
	// Public functions...
	AVP_Move_Melee_DefaultAttack_Start(Asura_Movement_System& xParentSystem);
//	virtual ~AVP_Move_Melee_DefaultAttack_Start();

	// Accessor functions...
	static Asura_Hash_ID GetStaticHash() { return(0x24C4D017); } // Asura_GetHashID("AVP_Move_Melee_DefaultAttack_Start")); }

protected:
	virtual bool Start(const Asura_Msg_Move* pxStartMsg);

	Asura_Hash_ID m_uCurrentFirstPersonMeleeBlueprint;
	Asura_Hash_ID m_uCurrentThirdPersonMeleeBlueprint;

private:
	// Private typedef...
	typedef AVP_Move_Melee_GenericAttack_Start PARENT;
};   // End of class 'AVP_Move_Melee_DefaultAttack_Start'.

////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_Move_Melee_DefaultAttack_Return_Hit
// Author       : Anthony Gregson
// Date         : 24/04/08
////////////////////////////////////////////////////////////////////////////////

class AVP_Move_Melee_DefaultAttack_Return_Hit : public AVP_Move_Melee_GenericAttack_Return_Hit
{
public:
	// Public functions...
	AVP_Move_Melee_DefaultAttack_Return_Hit(Asura_Movement_System& xParentSystem);
	//	virtual ~AVP_Move_Melee_DefaultAttack_Return_Hit();

	// Accessor functions...
	static Asura_Hash_ID GetStaticHash() { return(0xFFEAE56F); } // Asura_GetHashID("AVP_Move_Melee_DefaultAttack_Return_Hit")); }

protected:
	virtual bool Start(const Asura_Msg_Move* pxStartMsg);

	Asura_Hash_ID m_uCurrentFirstPersonMeleeBlueprint;
	Asura_Hash_ID m_uCurrentThirdPersonMeleeBlueprint;

private:
	// Private typedef...
	typedef AVP_Move_Melee_GenericAttack_Return_Hit PARENT;
};   // End of class 'AVP_Move_Melee_DefaultAttack_Return_Hit'.


////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_Move_Melee_DefaultAttack_Return_Countered
// Author       : Anthony Gregson
// Date         : 24/04/08
////////////////////////////////////////////////////////////////////////////////

class AVP_Move_Melee_DefaultAttack_Return_Countered : public AVP_Move_Melee_GenericAttack_Return_Countered
{
public:
	// Public functions...
	AVP_Move_Melee_DefaultAttack_Return_Countered(Asura_Movement_System& xParentSystem);
	//	virtual ~AVP_Move_Melee_DefaultAttack_Return_Countered();

	// Accessor functions...
	static Asura_Hash_ID GetStaticHash() { return(0x4C5D5077); } // Asura_GetHashID("AVP_Move_Melee_DefaultAttack_Return_Countered")); }

protected:
	virtual bool Start(const Asura_Msg_Move* pxStartMsg);

	Asura_Hash_ID m_uCurrentFirstPersonMeleeBlueprint;
	Asura_Hash_ID m_uCurrentThirdPersonMeleeBlueprint;

private:
	// Private typedef...
	typedef AVP_Move_Melee_GenericAttack_Return_Countered PARENT;
};   // End of class 'AVP_Move_Melee_DefaultAttack_Return_Countered'.


////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_Move_Melee_DefaultAttack_Return_Miss
// Author       : Anthony Gregson
// Date         : 24/04/08
////////////////////////////////////////////////////////////////////////////////

class AVP_Move_Melee_DefaultAttack_Return_Miss : public AVP_Move_Melee_GenericAttack_Return_Miss
{
public:
	// Public functions...
	AVP_Move_Melee_DefaultAttack_Return_Miss(Asura_Movement_System& xParentSystem);
	//	virtual ~AVP_Move_Melee_DefaultAttack_Return_Miss();

	// Accessor functions...
	static Asura_Hash_ID GetStaticHash() { return(0xFD740EA0); } // Asura_GetHashID("AVP_Move_Melee_DefaultAttack_Return_Miss")); }

protected:
	virtual bool Start(const Asura_Msg_Move* pxStartMsg);

	Asura_Hash_ID m_uCurrentFirstPersonMeleeBlueprint;
	Asura_Hash_ID m_uCurrentThirdPersonMeleeBlueprint;

private:
	// Private typedef...
	typedef AVP_Move_Melee_GenericAttack_Return_Miss PARENT;
};   // End of class 'AVP_Move_Melee_DefaultAttack_Return_Miss'.


////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_Move_Melee_DefaultCounter
// Author       : Anthony Gregson
// Date         : 24/04/08
////////////////////////////////////////////////////////////////////////////////

class AVP_Move_Melee_DefaultCounter : public AVP_Move_Melee
{
public:
	// Public functions...
	AVP_Move_Melee_DefaultCounter(Asura_Movement_System& xParentSystem);
	//	virtual ~AVP_Move_Melee_DefaultCounter ();

	// Accessor functions...
	static Asura_Hash_ID GetStaticHash() { return(0x13593210); } // Asura_GetHashID("AVP_Move_Melee_DefaultCounter")); }

protected:
	virtual bool Start(const Asura_Msg_Move* pxStartMsg);

	Asura_Hash_ID m_uCurrentFirstPersonMeleeBlueprint;
	Asura_Hash_ID m_uCurrentThirdPersonMeleeBlueprint;

private:
	// Private typedef...
	typedef AVP_Move_Melee PARENT;
};   // End of class 'AVP_Move_Melee_DefaultCounter'.


// Blocking moves don't actually inherit from AVP_Move_Melee, but they're pretty integral to the melee system so they can go here.
class AVP_Move_BlockStart : public AVP_Move
{
public:
	// Public functions...
	AVP_Move_BlockStart(Asura_Movement_System& xParentSystem);
	//	virtual ~AVP_Move_BlockStart();

	static Asura_Hash_ID GetStaticHash() { return 0x41F8C7BF; } //Asura_GetHashID("AVP_Move_BlockStart");

protected:
	// Overridden functions...
	virtual bool Start(const Asura_Msg_Move* pxStartMsg);

private:
	// Private typedef...
	typedef AVP_Move PARENT;
};   // End of class 'AVP_Move_BlockStart'.

class AVP_Move_BlockLoop : public AVP_Move
{
public:
	// Public functions...
	AVP_Move_BlockLoop(Asura_Movement_System& xParentSystem);
	//	virtual ~AVP_Move_BlockLoop();

	virtual bool HasFinished() const;

	static Asura_Hash_ID GetStaticHash() { return 0x6D7863A7; } //Asura_GetHashID("AVP_Move_BlockLoop");

protected:
	// Overridden functions...
	virtual bool ShouldStart() const;
	virtual bool Start(const Asura_Msg_Move* pxStartMsg);
	virtual void Finish();

	virtual void UpdateStates(const float fTimeStep);

	// Need a flag for when block becomes in active which gets updated in UpdateStates.
	// If we don't, and just check the state directly in HasFinished, Asura_Move::Update breaks because it uses HasFinished both before and after UpdateStates is called to work out whether it ended this frame.
	bool m_bFinished;

private:
	// Private typedef...
	typedef AVP_Move PARENT;
};   // End of class 'AVP_Move_BlockLoop'.

class AVP_Move_BlockEnd : public AVP_Move
{
public:
	// Public functions...
	AVP_Move_BlockEnd(Asura_Movement_System& xParentSystem);
	//	virtual ~AVP_Move_BlockEnd();

	static Asura_Hash_ID GetStaticHash() { return 0x6EE2BF78; } //Asura_GetHashID("AVP_Move_BlockEnd");

protected:
	// Overridden functions...
	virtual bool ShouldStart() const;
	virtual bool Start(const Asura_Msg_Move* pxStartMsg);

private:
	// Private typedef...
	typedef AVP_Move PARENT;
};   // End of class 'AVP_Move_BlockEnd'.

class AVP_Move_BlockFlinch : public AVP_Move
{
public:
	// Public functions...
	AVP_Move_BlockFlinch(Asura_Movement_System& xParentSystem);
	//	virtual ~AVP_Move_BlockFlinch();

	static Asura_Hash_ID GetStaticHash() { return 0xE6840653; } //Asura_GetHashID("AVP_Move_BlockFlinch");

protected:
	// Overridden functions...
	virtual bool Start(const Asura_Msg_Move* pxStartMsg);

private:
	// Private typedef...
	typedef AVP_Move PARENT;
};   // End of class 'AVP_Move_BlockFlinch'.


// Generic puppeteer attack, allowing greater code sharing similar to the generic standard attack.

////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_Move_Melee_GenericPuppeteer_Start
// Author       : Anthony Gregson
// Date         : 01/04/08
////////////////////////////////////////////////////////////////////////////////

class AVP_Move_Melee_GenericPuppeteer_Start : public AVP_Move_Puppeteer
{
public:
	// Public functions...
	// First constructor, designed for use with branching puppeteer moves.
	AVP_Move_Melee_GenericPuppeteer_Start(Asura_Movement_System& xParentSystem, const Asura_Hash_ID uMoveHash,
										  const AVP_Settings::Species ePuppeteerSpecies, const AVP_Settings::Species eVictimSpecies, const Asura_Hash_ID uBlueprintNameHash,
										  const Asura_Hash_ID uSuccessMove, const Asura_Hash_ID uCounteredMove);
	// Second constructor, designed for use with one-stage puppeteer moves.
	AVP_Move_Melee_GenericPuppeteer_Start(Asura_Movement_System& xParentSystem, const Asura_Hash_ID uMoveHash,
										  const AVP_Settings::Species ePuppeteerSpecies, const AVP_Settings::Species eVictimSpecies, const Asura_Hash_ID uBlueprintNameHash);
	// Third constructor, designed for anything that needs to do something different to the above. Obviously, the subclass has to set up most details if using this.
	AVP_Move_Melee_GenericPuppeteer_Start(Asura_Movement_System& xParentSystem, const Asura_Hash_ID uMoveHash);
	//	virtual ~AVP_Move_Melee_GenericPuppeteer_Start();

	virtual bool HandleMessage(const Asura_Message* pxMessage);

	u_int GetFinalAttackType() const { return m_uFinalAttackType; }
	bool GetCountered() const { return m_bCountered; }

protected:
	virtual bool ShouldStart() const;
	virtual bool Start(const Asura_Msg_Move* pxStartMsg);
	virtual void Reset();
	virtual void Abort();

	virtual void SendStartMsg();

	// Store the IDs we need to send to the puppet move.
	Asura_Hash_ID m_uFirstPersonVictimAnimID;
	Asura_Hash_ID m_uThirdPersonVictimAnimID;
	AVP_Settings::Species m_eVictimSpecies; // Used by ShouldStart to ensure the entity classification matches. Species used instead of classification as there's multiple classifications associated with the HUMAN species.

	// PFX effects, only for use if there is no chained success move (as that should play the effects otherwise).
	Asura_Hash_ID m_uPuppeteerPFXEffect;
	Asura_Hash_ID m_uPuppeteerPFXMarker;
	Asura_Hash_ID m_uPuppetPFXEffect;
	Asura_Hash_ID m_uPuppetPFXMarker;

	// Also store the initial offset.
	float m_fInitialVictimForwardOffset;

	// Data for what move to start next.
	u_int m_uFinalAttackType;
	bool m_bCountered;
	bool m_bAlwaysFatal; // If this is true, we can know not to tween out the puppet animation. Only valid if there's no follow-up moves.
	bool m_bNoBranching;

private:
	Asura_Hash_ID GetBlueprintType(AVP_Settings::Species ePuppeteerSpecies) const;
	Asura_Hash_ID GetPuppeteerFirstPersonParam(AVP_Settings::Species ePuppeteerSpecies, bool bHasNextMove) const;
	Asura_Hash_ID GetPuppeteerThirdPersonParam(AVP_Settings::Species ePuppeteerSpecies, bool bHasNextMove) const;
	Asura_Hash_ID GetVictimFirstPersonParam(AVP_Settings::Species eVictimSpecies, bool bHasNextMove) const;
	Asura_Hash_ID GetVictimThirdPersonParam(AVP_Settings::Species eVictimSpecies, bool bHasNextMove) const;

	// Private typedef...
	typedef AVP_Move_Puppeteer PARENT;
};   // End of class 'AVP_Move_Melee_GenericPuppeteer_Start'.

////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_Move_Melee_GenericPuppeteer_Success
// Author       : Anthony Gregson
// Date         : 01/04/08
////////////////////////////////////////////////////////////////////////////////

class AVP_Move_Melee_GenericPuppeteer_Success : public AVP_Move_Puppeteer
{
public:
	// Public functions...
	AVP_Move_Melee_GenericPuppeteer_Success(Asura_Movement_System& xParentSystem, const Asura_Hash_ID uMoveHash,
											const AVP_Settings::Species ePuppeteerSpecies, const AVP_Settings::Species eVictimSpecies, const Asura_Hash_ID uBlueprintNameHash);
	//	virtual ~AVP_Move_Melee_GenericPuppeteer_Success();

protected:
	virtual bool ShouldStart() const;
	virtual bool Start(const Asura_Msg_Move* pxStartMsg);
	virtual void Reset();
	virtual void Abort();

	virtual void SendStartMsg();

	Asura_Hash_ID GetBlueprintType(AVP_Settings::Species ePuppeteerSpecies) const;

	// Store the IDs we need to send to the puppet move.
	Asura_Hash_ID m_uFirstPersonVictimAnimID;
	Asura_Hash_ID m_uThirdPersonVictimAnimID;

	// PFX for things like blood. Very temporary.
	Asura_Hash_ID m_uPuppeteerPFXEffect;
	Asura_Hash_ID m_uPuppeteerPFXMarker;
	Asura_Hash_ID m_uPuppetPFXEffect;
	Asura_Hash_ID m_uPuppetPFXMarker;

	bool m_bAlwaysFatal; // If this is true, we can know not to tween out the puppet animation.

private:
	Asura_Hash_ID GetPuppeteerFirstPersonParam(AVP_Settings::Species ePuppeteerSpecies) const;
	Asura_Hash_ID GetPuppeteerThirdPersonParam(AVP_Settings::Species ePuppeteerSpecies) const;
	Asura_Hash_ID GetVictimFirstPersonParam(AVP_Settings::Species eVictimSpecies) const;
	Asura_Hash_ID GetVictimThirdPersonParam(AVP_Settings::Species eVictimSpecies) const;

	// Private typedef...
	typedef AVP_Move_Puppeteer PARENT;
};   // End of class 'AVP_Move_Melee_GenericPuppeteer_Success'.

////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_Move_Melee_GenericPuppeteer_Countered
// Author       : Anthony Gregson
// Date         : 01/04/08
////////////////////////////////////////////////////////////////////////////////

class AVP_Move_Melee_GenericPuppeteer_Countered : public AVP_Move_Puppeteer
{
public:
	// Public functions...
	AVP_Move_Melee_GenericPuppeteer_Countered(Asura_Movement_System& xParentSystem, const Asura_Hash_ID uMoveHash,
											  const AVP_Settings::Species ePuppeteerSpecies, const AVP_Settings::Species eVictimSpecies, const Asura_Hash_ID uBlueprintNameHash);
	//	virtual ~AVP_Move_Melee_GenericPuppeteer_Countered();

protected:
	virtual bool ShouldStart() const;
	virtual bool Start(const Asura_Msg_Move* pxStartMsg);
	virtual void Reset();

	virtual void SendStartMsg();

	// Store the IDs we need to send to the puppet move.
	Asura_Hash_ID m_uFirstPersonVictimAnimID;
	Asura_Hash_ID m_uThirdPersonVictimAnimID;

private:
	Asura_Hash_ID GetBlueprintType(AVP_Settings::Species ePuppeteerSpecies) const;
	Asura_Hash_ID GetPuppeteerFirstPersonParam(AVP_Settings::Species ePuppeteerSpecies) const;
	Asura_Hash_ID GetPuppeteerThirdPersonParam(AVP_Settings::Species ePuppeteerSpecies) const;
	Asura_Hash_ID GetVictimFirstPersonParam(AVP_Settings::Species eVictimSpecies) const;
	Asura_Hash_ID GetVictimThirdPersonParam(AVP_Settings::Species eVictimSpecies) const;

	// Private typedef...
	typedef AVP_Move_Puppeteer PARENT;
};   // End of class 'AVP_Move_Melee_GenericPuppeteer_Countered'.

// TODO - may need a generic puppeteer drop too.


////////////////////////////////////////////////////////////////////////////////
// Pounce attack without grabbing enemy, now common to both predator and alien
////////////////////////////////////////////////////////////////////////////////

class AVP_Move_Melee_Pounce_Attack_Start : public AVP_Move_Melee_GenericAttack_Start
{
public:
	AVP_Move_Melee_Pounce_Attack_Start(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash);
	virtual ~AVP_Move_Melee_Pounce_Attack_Start();

	void AddAlienGrapple(AVP_Move_Puppeteer* pxMove);
	void AddHumanGrapple(AVP_Move_Puppeteer* pxMove);
	void AddPredatorGrapple(AVP_Move_Puppeteer* pxMove);

	bool GetHasAlienGrapple() const { return m_bHasAlienGrapple; }
	bool GetHasHumanGrapple() const { return m_bHasHumanGrapple; }
	bool GetHasPredatorGrapple() const { return m_bHasPredatorGrapple; }
	bool GetIsGrapplePounce() const { return m_bIsGrapplePounce; }

	static Asura_Hash_ID GetStaticHash() { return 0x9592FC3B; } // Asura_GetHashID("AVP_Move_Melee_Pounce_Attack_Start")); }

protected:
	virtual void Reset();

	virtual bool Start(const Asura_Msg_Move* pxStartMsg);

	virtual void UpdateStates(const float fTimeStep);

	virtual bool CalculateVelocity(const float fTimeStep, Asura_AVector3_OutParam xVelocity) const;

	Asura_MoveData_OrientationInterpolation m_xOrientationInterpolationData;
	Asura_MoveData_PositionInterpolation m_xPositionInterpolationData;
	Asura_AVector3 m_xCurrentVelocity;
	float m_fEnemyPositionForwardOffset;
	float m_fTrackingMaxAcceleration;

	bool m_bHasAlienGrapple;
	bool m_bHasHumanGrapple;
	bool m_bHasPredatorGrapple;
	bool m_bIsGrapplePounce;

private:
	void UpdateTracking(const float fTimeStep);
	void SetupTargetPosition(const AVP_ClientEntity_PhysicalObject& xTargetEnemy, const float fDuration, Asura_Matrix_3x3* pxOrientationToEnemy);

#if defined(ASURA_SUPPORT_COMMAND_CONSOLE)
	static int s_iConsoleVarsCount;
#endif	// defined(ASURA_SUPPORT_COMMAND_CONSOLE)

	typedef AVP_Move_Melee_GenericAttack_Start PARENT;
};   // End of class 'AVP_Move_Melee_Pounce_Attack_Start'.


class AVP_Move_Melee_Pounce_Attack_Return_Hit : public AVP_Move_Melee_GenericAttack_Return_Hit
{
public:
	AVP_Move_Melee_Pounce_Attack_Return_Hit(Asura_Movement_System& xParentSystem);

	static Asura_Hash_ID GetStaticHash() { return 0x3286AFCB; } // Asura_GetHashID("AVP_Move_Melee_Pounce_Attack_Return_Hit")); }

protected:
	virtual bool ShouldStart() const;
	virtual bool Start(const Asura_Msg_Move* pxStartMsg);
	virtual void Finish(void);
	virtual void Abort(void);

private:
	typedef AVP_Move_Melee_GenericAttack_Return_Hit PARENT;
};   // End of class 'AVP_Move_Melee_Pounce_Attack_Return_Hit'.

class AVP_Move_Melee_Pounce_Attack_Return_Countered : public AVP_Move_Melee_GenericAttack_Return_Countered
{
public:
	AVP_Move_Melee_Pounce_Attack_Return_Countered(Asura_Movement_System& xParentSystem);

	static Asura_Hash_ID GetStaticHash() { return 0x8C36E5D3; } // Asura_GetHashID("AVP_Move_Melee_Pounce_Attack_Return_Countered")); }

protected:
	virtual bool Start(const Asura_Msg_Move* pxStartMsg);
	virtual void Finish(void);
	virtual void Abort(void);

private:
	typedef AVP_Move_Melee_GenericAttack_Return_Countered PARENT;
};   // End of class 'AVP_Move_Melee_Pounce_Attack_Return_Countered'.

class AVP_Move_Melee_Pounce_Attack_Return_Miss : public AVP_Move_Melee_GenericAttack_Return_Miss
{
public:
	AVP_Move_Melee_Pounce_Attack_Return_Miss(Asura_Movement_System& xParentSystem);

	static Asura_Hash_ID GetStaticHash() { return 0x1E518FC4; } // Asura_GetHashID("AVP_Move_Melee_Pounce_Attack_Return_Miss")); }

protected:
	virtual bool Start(const Asura_Msg_Move* pxStartMsg);
	virtual void Finish(void);
	virtual void Abort(void);

private:
	typedef AVP_Move_Melee_GenericAttack_Return_Miss PARENT;
};   // End of class 'AVP_Move_Melee_Pounce_Attack_Return_Miss'.


////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_Move_Melee_Grapple_Start
// Author       : Anthony Gregson
// Date         : 02/04/09
//
// Second attempt at simplifying the creation of grapples, while increasing the blueprint control of them.
////////////////////////////////////////////////////////////////////////////////

class AVP_Move_Melee_Grapple_Start : public AVP_Move_Puppeteer
{
public:
	// First constructor, if anything needs to subclass this.
	AVP_Move_Melee_Grapple_Start(Asura_Movement_System& xParentSystem, const Asura_Hash_ID uMoveHash, const Asura_Hash_ID uFinishMove);

	// Second constructor, for constructing the one instance of this most grapples will be able to use.
	AVP_Move_Melee_Grapple_Start(Asura_Movement_System& xParentSystem);

	virtual ~AVP_Move_Melee_Grapple_Start() {}

	virtual bool HandleMessage(const Asura_Message* pxMessage);

	virtual bool HasFinished() const;

	Asura_Hash_ID GetGrappleDescriptionBlueprint() const { return m_uGrappleDescriptionBlueprint; }

	bool IsAttackerVictorious() const { return m_bAttackerVictorious; }
	bool IsCriticalVictory() const { return m_bCriticalVictory; }
	bool IsResultFinalised() const { return m_bResultFinalised; }
	bool IsBranching() const { return m_bBranching; }

	bool GetFinishMovePuppetStartOffset(Asura_AVector3& xPosition, Asura_Quat& xOrientation) const;

	static Asura_Hash_ID GetStaticHash() { return 0x4000715D; } // Asura_GetHashID("AVP_Move_Melee_Grapple_Start"); }

protected:
	virtual bool ShouldStart() const;
	virtual bool Start(const Asura_Msg_Move* pxStartMsg);
	virtual void Reset();
	virtual void Finish();
	virtual void Abort();

	virtual void UpdateStates(const float fTimeStep);

	virtual void SendStartMsg();

	bool CalculateFinishMovePuppetStartOffset();

	// All data for the attack goes into the grapple description blueprint, so all we need is that plus some flags so we know what move to start next (if we're going to start a next move).
	Asura_Hash_ID m_uGrappleDescriptionBlueprint;

	Asura_AVector3 m_xFinalPuppetPositionOffset;
	Asura_Quat m_xFinalPuppetOrientationOffset;

	union
	{
		u_int m_uGrappleFlags;
		struct
		{
			u_int	m_bAttackerVictorious	: 1,
					m_bCriticalVictory		: 1,	// Applies regardless of whether the attacker or the victim was victorious.
					m_bResultFinalised		: 1,
					m_bBranching			: 1,
					m_bAnimCompleteFlagHit	: 1,
					m_bGrappleCanFinish		: 1,
					m_bHasFinishMoveOffset	: 1,
											: 0;
		};
	};

private:

	typedef AVP_Move_Puppeteer PARENT;
}; 

////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_Move_Melee_Grapple_Finish
// Author       : Anthony Gregson
// Date         : 02/04/09
//
// Unlike the old generic puppeteer chains, all possible grapple results at the end of the start move can go through this one finish move (the only time this isn't used is with unbranching moves).
////////////////////////////////////////////////////////////////////////////////

class AVP_Move_Melee_Grapple_Finish : public AVP_Move_Puppeteer
{
public:
	// First constructor, if anything needs to subclass this.
	AVP_Move_Melee_Grapple_Finish(Asura_Movement_System& xParentSystem, const Asura_Hash_ID uMoveHash);

	// Second constructor, for constructing the one instance of this most grapples will be able to use.
	AVP_Move_Melee_Grapple_Finish(Asura_Movement_System& xParentSystem);

	virtual ~AVP_Move_Melee_Grapple_Finish() {}

	static Asura_Hash_ID GetStaticHash() { return 0xA9497EF8; } // Asura_GetHashID("AVP_Move_Melee_Grapple_Finish"); }

protected:
	virtual bool ShouldStart() const;
	virtual bool Start(const Asura_Msg_Move* pxStartMsg);
	virtual void Reset();
	virtual void Abort();

	virtual void SendStartMsg();

	// All data for the attack goes into the grapple description blueprint, so all we need is that plus some flags so we know whether this is a normal win or a critical win.
	Asura_Hash_ID m_uGrappleDescriptionBlueprint;

	Asura_AVector3 m_xInitialPuppetPositionOffset;
	Asura_Quat m_xInitialPuppetOrientationOffset;

	union
	{
		u_int m_uGrappleFlags;
		struct
		{
			u_int	m_bAttackerVictorious	: 1,
					m_bCriticalVictory		: 1,	// Applies regardless of whether the attacker or the victim was victorious.
											: 0;
		};
	};

private:

	typedef AVP_Move_Puppeteer PARENT;
};


////////////////////////////////////////////////////////////////////////////////
// Parameter enumerator to set up melee move variations easily.
////////////////////////////////////////////////////////////////////////////////

class AVP_Blueprint_ParameterEnumerator_MeleeVariations : public Asura_Blueprint_ParameterEnumerator
{
	typedef Asura_Blueprint_ParameterEnumerator PARENT;

public:
	AVP_Blueprint_ParameterEnumerator_MeleeVariations(AVP_Move_Melee& xMove, bool bThirdPersonSet);
	virtual ~AVP_Blueprint_ParameterEnumerator_MeleeVariations() {};

	virtual void	BeginEnumeration(void);
	virtual bool	Enumerate(const u_int uIndex, char const* const szName, const Asura_Value& xValue);
	virtual void	EndEnumeration(const bool bSuccess);

protected:
	AVP_Move_Melee& m_xMove;

	enum { MAX_MELEE_MOVE_VARIATIONS = 8, };
	Asura_Hash_ID m_auVariationHashes[MAX_MELEE_MOVE_VARIATIONS];
	u_int m_uNumVariations;

	bool m_bThirdPersonSet;
};

class AVP_Blueprint_ParameterEnumerator_MeleeVariations_MultipleParameters : public AVP_Blueprint_ParameterEnumerator_MeleeVariations
{
	typedef AVP_Blueprint_ParameterEnumerator_MeleeVariations PARENT;

public:
	AVP_Blueprint_ParameterEnumerator_MeleeVariations_MultipleParameters(AVP_Move_Melee& xMove, bool bThirdPersonSet);
	virtual ~AVP_Blueprint_ParameterEnumerator_MeleeVariations_MultipleParameters() {};

	virtual void EndEnumeration(const bool bSuccess) { m_bSuccess &= bSuccess; }

	// This has to be called from whatever is trying to enumerate the parameters, rather than everything happening automatically as is normally the case.
	void EnumeratedAllParameters();

protected:

	bool m_bSuccess;
};

class AVP_Blueprint_ParameterEnumerator_GrappleEvents : public Asura_Blueprint_ParameterEnumerator_ByHash
{
	typedef Asura_Blueprint_ParameterEnumerator_ByHash PARENT;

public:
	AVP_Blueprint_ParameterEnumerator_GrappleEvents(AVP_GrappleEvent_Entry* pxEntries, int& iNumEntries);
	virtual ~AVP_Blueprint_ParameterEnumerator_GrappleEvents() {};

	virtual void BeginEnumeration(void);
	virtual bool Enumerate(const u_int uIndex, const Asura_Value& xValue);
	virtual void EndEnumeration(const bool bSuccess);

protected:
	AVP_GrappleEvent_Entry* m_pxEntries;
	int& m_iNumEntries;
};

#endif   // ifndef __AVP_MOVES_MELEE_H__


/// End of file. ///
