/*!
	@project Rune
	@file RuFusion_Mime.h

	Copyright (c) 2004-2005 All rights reserved

	@author John Tang
	@date 2005/07/22
*/

#ifndef _RUFUSION_MIME_H_
#define _RUFUSION_MIME_H_

#include "../Scene/Base/RuSceneBase.h"
#include "../Scene/Controller/RuController_Bone.h"

#pragma unmanaged

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

enum CRuFusion_Mime_Action
{
	ruFUSION_MIME_NONE								= 0,				//!< No motion

	ruFUSION_MIME_IDLE_STAND						= 11,				//!< Temporary idle motion
	ruFUSION_MIME_IDLE_COMBAT_1H					= 12,
	ruFUSION_MIME_IDLE_COMBAT_2H					= 13,
	ruFUSION_MIME_IDLE_COMBAT_BOW					= 14,
	ruFUSION_MIME_IDLE_COMBAT_GUN					= 15,
	ruFUSION_MIME_IDLE_COMBAT_POLEARM				= 16,
	ruFUSION_MIME_IDLE_COMBAT_UNARMED				= 17,

	ruFUSION_MIME_ATTACK_1H							= 21,				//!< Standard 1H attack
	ruFUSION_MIME_ATTACK_2H							= 22,				//!< Standard 2H attack
	ruFUSION_MIME_ATTACK_BOW_BEGIN					= 23,
	ruFUSION_MIME_ATTACK_BOW_LOOP					= 24,
	ruFUSION_MIME_ATTACK_BOW_END					= 25,
	ruFUSION_MIME_ATTACK_GUN_BEGIN					= 26,
	ruFUSION_MIME_ATTACK_GUN_LOOP					= 27,
	ruFUSION_MIME_ATTACK_GUN_END					= 28,
	ruFUSION_MIME_ATTACK_OH							= 29,
	ruFUSION_MIME_ATTACK_OH_PIERCE					= 30,
	ruFUSION_MIME_ATTACK_POLEARM					= 31,				//!< Standard unarmed attack
	ruFUSION_MIME_ATTACK_UNARMED					= 32,				//!< Standard unarmed attack

	ruFUSION_MIME_BUFF_BEGIN						= 51,
	ruFUSION_MIME_BUFF_LOOP							= 52,
	ruFUSION_MIME_BUFF_END							= 53,
	ruFUSION_MIME_BUFF_INSTANT						= 54,

	ruFUSION_MIME_CAST_BEGIN						= 55,
	ruFUSION_MIME_CAST_LOOP							= 56,
	ruFUSION_MIME_CAST_END							= 57,
	ruFUSION_MIME_CAST_INSTANT						= 58,

	ruFUSION_MIME_CHANNEL_BEGIN						= 59,
	ruFUSION_MIME_CHANNEL_LOOP						= 60,
	ruFUSION_MIME_CHANNEL_END						= 61,
	ruFUSION_MIME_CHANNEL_INSTANT					= 62,

	ruFUSION_MIME_RUN_FORWARD						= 101,				//!<
	ruFUSION_MIME_RUN_BACKWARD						= 102,				//!<
	ruFUSION_MIME_WALK_FORWARD						= 103,				//!<

	ruFUSION_MIME_SWIM_FORWARD						= 104,				//!<
	ruFUSION_MIME_SWIM_BACKWARD						= 105,				//!<
	ruFUSION_MIME_SWIM_LEFT							= 106,				//!<
	ruFUSION_MIME_SWIM_RIGHT						= 107,				//!<
	ruFUSION_MIME_SWIM_IDLE							= 108,				//!< Temporary idle motion

	ruFUSION_MINE_HOLSTER							= 111,
	ruFUSION_MIME_UNHOLSTER							= 112,

	ruFUSION_MINE_HOLSTER_2H						= 113,
	ruFUSION_MIME_UNHOLSTER_2H						= 114,

	// States
	ruFUSION_MIME_JUMP_DOWN							= 121,
	ruFUSION_MIME_JUMP_LOOP							= 122,
	ruFUSION_MIME_JUMP_UP							= 123,

	ruFUSION_MIME_SLEEP_DOWN						= 124,
	ruFUSION_MIME_SLEEP_LOOP						= 125,
	ruFUSION_MIME_SLEEP_UP							= 126,

	ruFUSION_MIME_SIT_DOWN							= 127,
	ruFUSION_MIME_SIT_LOOP							= 128,
	ruFUSION_MIME_SIT_UP							= 129,

	ruFUSION_MIME_DEATH_DOWN						= 130,
	ruFUSION_MIME_DEATH_LOOP						= 131,
	ruFUSION_MIME_DEATH_UP							= 132,

	// Emotes
	ruFUSION_MIME_EMOTE_ANGRY						= 201,
	ruFUSION_MIME_EMOTE_APPLAUSE					= 202,
	ruFUSION_MIME_EMOTE_APPROVAL					= 203,
	ruFUSION_MIME_EMOTE_BEG							= 204,
	ruFUSION_MIME_EMOTE_CRY							= 205,
	ruFUSION_MIME_EMOTE_HEAD_NOD					= 206,
	ruFUSION_MIME_EMOTE_HEAD_SHAKE					= 207,
	ruFUSION_MIME_EMOTE_LAUGH						= 208,
	ruFUSION_MIME_EMOTE_POINT						= 209,
	ruFUSION_MIME_EMOTE_PROVOKE						= 210,
	ruFUSION_MIME_EMOTE_SALUTE						= 211,
	ruFUSION_MIME_EMOTE_SPEAK						= 212,
	ruFUSION_MIME_EMOTE_SURRENDER					= 213,
	ruFUSION_MIME_EMOTE_THREATEN					= 214,
	ruFUSION_MIME_EMOTE_VICTORY						= 215,
	ruFUSION_MIME_EMOTE_WAVE						= 216,

	ruFUSION_MIME_ACTION_COUNT						= 217,
	ruFUSION_MIME_FORCE_DWORD						= 0x7FFFFFFF
};

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

enum CRuFusion_Mime_ActionType
{
	ruFUSION_MIME_ACTIONTYPE_LOW					= 0,
	ruFUSION_MIME_ACTIONTYPE_NORMAL					= 1,
	ruFUSION_MIME_ACTIONTYPE_HIGH					= 2,

	ruFUSION_MIME_ACTIONTYPE_FORCE_DWORD			= 0x7FFFFFFF
};

enum CRuFusion_Mime_MotionType
{
	ruFUSION_MIME_MOTIONTYPE_NORMAL					= 0,
	ruFUSION_MIME_MOTIONTYPE_NORMAL_OVERRIDE		= 1,
	ruFUSION_MIME_MOTIONTYPE_EXCLUSIVE				= 2,
	ruFUSION_MIME_MOTIONTYPE_EXCLUSIVE_OVERRIDE		= 3,

	ruFUSION_MIME_MOTIONTYPE_FORCE_DWORD			= 0x7FFFFFFF
};

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

class CRuFusion_Mime_Template : public IRuObject
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

protected:
	// Action descriptor
	struct CRuFusion_Mime_ActionDescriptor
	{
		INT32										m_actionPriority;							//!< Action priority
		CRuFusion_Mime_ActionType					m_actionType;								//!< Action type
		CRuArrayList<const char *>					m_motionNames;								//!< Array of motion names
		CRuArrayList<REAL>							m_motionProbabilities;						//!< Array of motion probabilities

										CRuFusion_Mime_ActionDescriptor();
										~CRuFusion_Mime_ActionDescriptor();

		void							SetActionType(CRuFusion_Mime_ActionType actionType);
		INT32							AddMotion(const char *motionName, REAL motionProbability = 1.0f);

		INT32							GetNumMotions() const;
		const char*						GetMotion(INT32 motionIndex) const;
		REAL							GetMotionProbability(INT32 motionIndex) const;
	};

	// Rotational bone descriptor
	struct CRuFusion_Mime_Bone_R
	{
		INT32							m_boneID;									//!< ID of bone
		REAL							m_weight;									//!< Weight

										CRuFusion_Mime_Bone_R(INT32 boneID = 0, REAL weight = 1.0f)
										:	m_boneID(boneID),
											m_weight(weight)
										{
										}
	};

	// Members
	CRuMTRandom							m_randGen;									//!< Build-in random number generator
	CRuFusion_Mime_ActionDescriptor*	m_actionDescriptors;						//!< List of action descriptors
	CRuArrayList<CRuFusion_Mime_Bone_R>	m_bodyBones;								//!< List of main body bones, used for body rotation
	CRuArrayList<CRuFusion_Mime_Bone_R>	m_torsoBones;								//!< List of torso bones, used for torso twisting

public:
										CRuFusion_Mime_Template();
	virtual								~CRuFusion_Mime_Template();

	BOOL								LoadSettings(IRuStream *settingsStream);
	BOOL								SaveSettings(IRuStream *settingsStream);

	INT32								GetActionPriority(CRuFusion_Mime_Action action);
	CRuFusion_Mime_ActionType			GetActionType(CRuFusion_Mime_Action action);
	const char*							GetMotion(CRuFusion_Mime_Action action);

	INT32								GetNumBodyBones() const;
	INT32								GetBodyBoneID(INT32 index) const;
	REAL								GetBodyBoneWeight(INT32 index) const;

	INT32								GetNumTorsoBones() const;
	INT32								GetTorsoBoneID(INT32 index) const;
	REAL								GetTorsoBoneWeight(INT32 index) const;
};

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

class CRuFusion_Mime : public IRuObject
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

protected:
	// Mime definition
	CRuFusion_Mime_Template*			m_mimeTemplate;
	UINT32								m_defaultChannel;
	UINT32								m_auxiliaryChannel;
	UINT32								m_backgroundChannel;
	UINT32								m_foregroundChannel;
	UINT32								m_userChannel;
	REAL								m_blendDelay;

	// Target and its status
	CRuEntity*							m_targetEntity;								//!< Target entity
	BOOL								m_targetEntitySupportsChannels;				//!< Does the target entity support channels?
	UINT32								m_backgroundActive;

	CRuFusion_Mime_Action				m_backgroundAction;							//!< Current mime background action
	CRuFusion_Mime_Action				m_scheduledBackgroundAction;				//!< Next scheduled background action
	CRuFusion_Mime_MotionType			m_backgroundMotionType;
	CRuFusion_Mime_MotionType			m_scheduledBackgroundMotionType;

	CRuFusion_Mime_Action				m_foregroundAction;							//!< Current mime foreground action
	CRuFusion_Mime_Action				m_scheduledForegroundAction;				//!< Next scheduled foreground action
	CRuFusion_Mime_MotionType			m_foregroundMotionType;
	CRuFusion_Mime_MotionType			m_scheduledForegroundMotionType;

	// Skeletal rotation
	REAL								m_body_YawOffset;
	REAL								m_body_HeadingOffset;
	CRuController_Bone*					m_body_BoneController;

	REAL								m_torso_HeadingOffset;
	CRuController_Bone*					m_torso_BoneController;						//!< Bone controller that acts on this bone group

	// Skeletal scaling

	// Run-time active motion names
	const char*							m_backgroundMotion;							//!< Active background motion name
	const char*							m_foregroundMotion;							//!< Active foreground motion name

	REAL								m_expectedMotionScale;

	REAL								m_defaultForwardSpeed;
	REAL								m_forwardSpeed;

	REAL								m_defaultBackwardSpeed;
	REAL								m_backwardSpeed;

public:
										CRuFusion_Mime();
	virtual								~CRuFusion_Mime();

	CRuEntity*							GetTarget() const;
	BOOL								SetTarget(CRuEntity *targetEntity);

	BOOL								SetMimeTemplate(CRuFusion_Mime_Template *mimeTemplate);

	CRuFusion_Mime_Action				GetBackgroundAction();
	BOOL								SetBackgroundAction(CRuFusion_Mime_Action action, CRuFusion_Mime_MotionType motionType = ruFUSION_MIME_MOTIONTYPE_NORMAL);
	CRuFusion_Mime_Action				GetForegroundAction();
	BOOL								SetForegroundAction(CRuFusion_Mime_Action action, CRuFusion_Mime_MotionType motionType = ruFUSION_MIME_MOTIONTYPE_NORMAL);

	BOOL								SetBodyYawOffset(REAL yawOffset);
	BOOL								SetBodyHeadingOffset(REAL headingOffset);
	BOOL								SetTorsoHeadingOffset(REAL headingOffset);

	BOOL								SetExpectedMotionScale(REAL expectedMotionScale);

	BOOL								SetDefaultForwardSpeed(REAL defaultForwardSpeed);
	BOOL								SetForwardSpeed(REAL forwardSpeed);

	BOOL								SetDefaultBackwardSpeed(REAL defaultBackwardSpeed);
	BOOL								SetBackwardSpeed(REAL backwardSpeed);

	void								Update(REAL elapsedTime);
	void								Update_WithChannel(REAL elapsedTime);
	void								Update_WithoutChannel(REAL elapsedTime);

protected:
	BOOL								IsImmediateAction(CRuFusion_Mime_Action currentAction, CRuFusion_Mime_MotionType currentMotionType, CRuFusion_Mime_Action newAction, CRuFusion_Mime_MotionType newMotionType);
};

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

#pragma managed

#endif
