/*************************************************************************
Crytek Source File.
Copyright (C), Crytek Studios, 2001-2004.
-------------------------------------------------------------------------
$Id$
$DateTime$

-------------------------------------------------------------------------
History:
- 30:8:2005   12:30 : Created by Márcio Martins

*************************************************************************/
#include "StdAfx.h"
#include "Item.h"

#include <ICryAnimation.h>
#include <ISound.h>
#include <CryPath.h>
#include "Actor.h"


//------------------------------------------------------------------------
void CItem::PreCache()
{
	FUNCTION_PROFILER(GetISystem(), PROFILE_GAME);

	IEntitySoundProxy *pSoundProxy = GetSoundProxy(true);
	if (!pSoundProxy || !m_pGameFramework->GetISystem()->GetISoundSystem())
		return;

	for (TActionMap::iterator it = m_actions.begin(); it != m_actions.end(); ++it)
	{
		string name = it->second.sound.name;
		FixResourceName(name, 0, "left", 0, 0, ITEM_FIRST_PERSON_TOKEN);
		m_pGameFramework->GetISystem()->GetISoundSystem()->Precache(name, 0, true);

		name = it->second.sound.name;
		FixResourceName(name, 0, "right", 0, 0, ITEM_THIRD_PERSON_TOKEN);
		m_pGameFramework->GetISystem()->GetISoundSystem()->Precache(name, 0, true);
	}
}

//------------------------------------------------------------------------
bool CItem::CreateCharacterAttachment(int slot, const char *name, int type, const char *bone)
{
	ICharacterInstance *pCharacter = GetEntity()->GetCharacter(slot);
	if (!pCharacter)
		return false;

	IAttachmentManager *pAttachmentManager = pCharacter->GetIAttachmentManager();
	IAttachment *pAttachment = pAttachmentManager->GetInterfaceByName(name);

	if (pAttachment)
	{
//		GameWarning("Item '%s' trying to create attachment '%s' which already exists!", GetEntity()->GetName(), name);
		return false;
	}

	pAttachment = pAttachmentManager->CreateAttachment(name, type, bone);

	if (!pAttachment)
	{
		if (type == CA_BONE)
			GameWarning("Item '%s' failed to create attachment '%s' on bone '%s'!", GetEntity()->GetName(), name, bone);
		return false;
	}

	return true;
}

//------------------------------------------------------------------------
void CItem::DestroyCharacterAttachment(int slot, const char *name)
{
	ICharacterInstance *pCharacter = GetEntity()->GetCharacter(slot);
	if (!pCharacter)
		return;

	IAttachmentManager *pAttachmentManager = pCharacter->GetIAttachmentManager();
	pAttachmentManager->RemoveAttachmentByName(name);
}

//------------------------------------------------------------------------
void CItem::ResetCharacterAttachment(int slot, const char *name)
{
	ICharacterInstance *pCharacter = GetEntity()->GetCharacter(slot);
	if (!pCharacter)
		return;

	IAttachmentManager *pAttachmentManager = pCharacter->GetIAttachmentManager();
	IAttachment *pAttachment = pAttachmentManager->GetInterfaceByName(name);

	if (!pAttachment)
	{
		GameWarning("Item '%s' trying to reset attachment '%s' which does not exist!", GetEntity()->GetName(), name);
		return;
	}

	pAttachment->ClearBinding();
}

//------------------------------------------------------------------------
const char *CItem::GetCharacterAttachmentBone(int slot, const char *name)
{
	ICharacterInstance *pCharacter = GetEntity()->GetCharacter(slot);
	if (!pCharacter)
		return 0;

	IAttachmentManager *pAttachmentManager = pCharacter->GetIAttachmentManager();
	IAttachment *pAttachment = pAttachmentManager->GetInterfaceByName(name);

	if (!pAttachment)
	{
		GameWarning("Item '%' trying to get attachment bone on '%s' which does not exist!", GetEntity()->GetName(), name);
		return 0;
	}

	return pCharacter->GetISkeleton()->GetJNameByID(pAttachment->GetBoneID());
}

//------------------------------------------------------------------------
void CItem::SetCharacterAttachment(int slot, const char *name, IEntity *pEntity, int flags)
{
	ICharacterInstance *pCharacter = GetEntity()->GetCharacter(slot);
	if (!pCharacter)
		return;

	IAttachmentManager *pAttachmentManager = pCharacter->GetIAttachmentManager();
	IAttachment *pAttachment = pAttachmentManager->GetInterfaceByName(name);

	if (!pAttachment)
	{
		GameWarning("Item '%' trying to attach entity on '%s' which does not exist!", GetEntity()->GetName(), name);
		return;
	}

	CEntityAttachment *pEntityAttachment = new CEntityAttachment();
	pEntityAttachment->SetEntityId(pEntity->GetId());

	pAttachment->AddBinding(pEntityAttachment);
	pAttachment->HideAttachment(0);
}

//------------------------------------------------------------------------
void CItem::SetCharacterAttachment(int slot, const char *name, IStatObj *pObj, int flags)
{
	ICharacterInstance *pCharacter = GetEntity()->GetCharacter(slot);
	if (!pCharacter)
		return;

	IAttachmentManager *pAttachmentManager = pCharacter->GetIAttachmentManager();
	IAttachment *pAttachment = pAttachmentManager->GetInterfaceByName(name);

	if (!pAttachment)
	{
		GameWarning("Item '%' trying to attach static object on '%s' which does not exist!", GetEntity()->GetName(), name);
		return;
	}

	CCGFAttachment *pStatAttachment = new CCGFAttachment();
	pStatAttachment->pObj  = pObj;

	pAttachment->AddBinding(pStatAttachment);
}

//------------------------------------------------------------------------
void CItem::SetCharacterAttachment(int slot, const char *name, ICharacterInstance *pAttachedCharacter, int flags)
{
	ICharacterInstance *pCharacter = GetEntity()->GetCharacter(slot);
	if (!pCharacter)
		return;

	IAttachmentManager *pAttachmentManager = pCharacter->GetIAttachmentManager();
	IAttachment *pAttachment = pAttachmentManager->GetInterfaceByName(name);

	if (!pAttachment)
	{
		GameWarning("Item '%' trying to attach character on '%s' which does not exist!", GetEntity()->GetName(), name);
		return;
	}

	CCHRAttachment *pCharacterAttachment = new CCHRAttachment();
	pCharacterAttachment->m_pCharInstance  = pAttachedCharacter;

	// sub skin ?
	if (pAttachment->GetType() == CA_SKIN)
	{
		pAttachment->RegisterSubSkin(pCharacterAttachment, pCharacter);
	}
	else
	{
		pAttachment->AddBinding(pCharacterAttachment);
	}
}

//------------------------------------------------------------------------
void CItem::SetCharacterAttachment(int slot, const char *name, CDLight &light, int flags)
{
	ICharacterInstance *pCharacter = GetEntity()->GetCharacter(slot);
	if (!pCharacter)
		return;

	IAttachmentManager *pAttachmentManager = pCharacter->GetIAttachmentManager();
	IAttachment *pAttachment = pAttachmentManager->GetInterfaceByName(name);

	if (!pAttachment)
	{
		GameWarning("Item '%' trying to attach light on '%s' which does not exist!", GetEntity()->GetName(), name);
		return;
	}

	CLightAttachment *pLightAttachment = new CLightAttachment();
	pLightAttachment->LoadLight(light);

	pAttachment->AddBinding(pLightAttachment);
	pAttachment->HideAttachment(0);
}

//------------------------------------------------------------------------
void CItem::SetCharacterAttachment(int slot, const char *name, IEntity *pEntity, int objSlot, int flags)
{
	SEntitySlotInfo info;
	if (!pEntity->GetSlotInfo(objSlot, info))
		return;

	if (info.pCharacter)
		SetCharacterAttachment(slot, name, info.pCharacter, flags);
	else if (info.pStatObj)
		SetCharacterAttachment(slot, name, info.pStatObj, flags);
}

//------------------------------------------------------------------------
void CItem::SetCharacterAttachmentLocalTM(int slot, const char *name, const Matrix34 &tm)
{
	ICharacterInstance *pCharacter = GetEntity()->GetCharacter(slot);
	if (!pCharacter)
		return;

	IAttachmentManager *pAttachmentManager = pCharacter->GetIAttachmentManager();
	IAttachment *pAttachment = pAttachmentManager->GetInterfaceByName(name);

	if (!pAttachment)
	{
		GameWarning("Item '%' trying to set local TM on attachment '%s' which does not exist!", GetEntity()->GetName(), name);
		return;
	}

	pAttachment->SetRelativeMat(tm);
}

//------------------------------------------------------------------------
void CItem::SetCharacterAttachmentWorldTM(int slot, const char *name, const Matrix34 &tm)
{
	ICharacterInstance *pCharacter = GetEntity()->GetCharacter(slot);
	if (!pCharacter)
		return;

	IAttachmentManager *pAttachmentManager = pCharacter->GetIAttachmentManager();
	IAttachment *pAttachment = pAttachmentManager->GetInterfaceByName(name);

	if (!pAttachment)
	{
		GameWarning("Item '%' trying to set world TM on attachment '%s' which does not exist!", GetEntity()->GetName(), name);
		return;
	}

	Matrix34 boneWorldMatrix = GetEntity()->GetSlotWorldTM(slot)*
		pCharacter->GetISkeleton()->GetAbsJMatrixByID(pAttachment->GetBoneID());
	Matrix34 localAttachmentMatrix = (boneWorldMatrix.GetInverted()*tm);
	pAttachment->SetRelativeMat(localAttachmentMatrix);
}

//------------------------------------------------------------------------
Matrix34 CItem::GetCharacterAttachmentLocalTM(int slot, const char *name)
{
	ICharacterInstance *pCharacter = GetEntity()->GetCharacter(slot);
	if (!pCharacter)
		return Matrix34::CreateIdentity();;

	IAttachmentManager *pAttachmentManager = pCharacter->GetIAttachmentManager();
	IAttachment *pAttachment = pAttachmentManager->GetInterfaceByName(name);

	if (!pAttachment)
	{
		GameWarning("Item '%' trying to get local TM on attachment '%s' which does not exist!", GetEntity()->GetName(), name);
		return Matrix34::CreateIdentity();
	}

	return pAttachment->GetRelativeMat();
}

//------------------------------------------------------------------------
Matrix34 CItem::GetCharacterAttachmentWorldTM(int slot, const char *name)
{
	ICharacterInstance *pCharacter = GetEntity()->GetCharacter(slot);
	if (!pCharacter)
		return Matrix34::CreateIdentity();

	IAttachmentManager *pAttachmentManager = pCharacter->GetIAttachmentManager();
	IAttachment *pAttachment = pAttachmentManager->GetInterfaceByName(name);

	if (!pAttachment)
	{
		GameWarning("Item '%' trying to get local TM on attachment '%s' which does not exist!", GetEntity()->GetName(), name);
		return Matrix34::CreateIdentity();
	}

	return pAttachment->GetWMatrix();
}

//------------------------------------------------------------------------
void CItem::HideCharacterAttachment(int slot, const char *name, bool hide)
{
	ICharacterInstance *pCharacter = GetEntity()->GetCharacter(slot);
	if (!pCharacter)
		return;

	IAttachmentManager *pAttachmentManager = pCharacter->GetIAttachmentManager();
	IAttachment *pAttachment = pAttachmentManager->GetInterfaceByName(name);

	if (!pAttachment)
	{
		GameWarning("Item '%' trying to hide attachment '%s' which does not exist!", GetEntity()->GetName(), name);
		return;
	}

	pAttachment->HideAttachment(hide?1:0);
}

//------------------------------------------------------------------------
void CItem::HideCharacterAttachmentMaster(int slot, const char *name, bool hide)
{
	ICharacterInstance *pCharacter = GetEntity()->GetCharacter(slot);
	if (!pCharacter)
		return;

	pCharacter->HideMaster(hide?1:0);
}

//------------------------------------------------------------------------
void CItem::CreateAttachmentHelpers(int slot)
{
	for (THelperVector::iterator it = m_helpers.begin(); it != m_helpers.end(); it++)
	{
		if (it->slot != slot)
			continue;

		CreateCharacterAttachment(slot, it->name.c_str(), CA_BONE, it->bone.c_str());
	}

	if (slot == eIGS_FirstPerson)
		CreateCharacterAttachment(slot, ITEM_ARMS_ATTACHMENT_NAME, CA_SKIN, 0);
}

//------------------------------------------------------------------------
void CItem::DestroyAttachmentHelpers(int slot)
{
	for (THelperVector::iterator it = m_helpers.begin(); it != m_helpers.end(); it++)
	{
		if (it->slot != slot)
			continue;

		DestroyCharacterAttachment(slot, it->name.c_str());
	}
}

//------------------------------------------------------------------------
bool CItem::SetGeometry(int slot, const char *name, const Vec3 &poffset, const Vec3 &aoffset, float scale, bool forceReload)
{
	switch(slot)
	{
	case eIGS_Arms:
		{
			if (!name || forceReload)
				GetEntity()->FreeSlot(slot);

			ResetCharacterAttachment(eIGS_FirstPerson, ITEM_ARMS_ATTACHMENT_NAME);

			ICharacterInstance *pCharacter=0;

			if (name && name[0])
			{
				GetEntity()->LoadCharacter(slot, name);
				DrawSlot(eIGS_Arms, false);

				pCharacter = GetEntity()->GetCharacter(eIGS_Arms);
			}
			else
			{
				pCharacter = GetOwnerActor()?GetOwnerActor()->GetFPArms():0;
			}

			if (pCharacter)
			{
				pCharacter->SetFlags(pCharacter->GetFlags()&(~CS_FLAG_UPDATE));
				SetCharacterAttachment(eIGS_FirstPerson, ITEM_ARMS_ATTACHMENT_NAME, pCharacter, 0);
			}
		}
		break;
	case eIGS_FirstPerson:
	case eIGS_ThirdPerson:
	default:
		{
			if (!name || forceReload)
				GetEntity()->FreeSlot(slot);

			DestroyAttachmentHelpers(slot);

			if (name && name[0])
			{
				string ext = PathUtil::GetExt(name);
				if ((ext == "chr") || (ext == "cdf") || (ext == "cga"))
					GetEntity()->LoadCharacter(slot, name, 0);
				else
					GetEntity()->LoadGeometry(slot, name, 0, 0);
			}

			CreateAttachmentHelpers(slot);

			SetDefaultIdleAnimation(slot, "idle");
			PlayAction(m_idleAnimation[eIGS_FirstPerson].c_str(), 0, true);
			ForceSkinning(true);

			if (slot == eIGS_FirstPerson)
			{
				ICharacterInstance *pCharacter = GetEntity()->GetCharacter(eIGS_FirstPerson);
				if (pCharacter)
					pCharacter->SetFlags(pCharacter->GetFlags()&(~CS_FLAG_UPDATE));
			}
		}
		break;
	}

	Matrix34 slotTM;
	slotTM = Matrix34::CreateRotationXYZ(aoffset);
	slotTM.Scale(Vec3(scale, scale, scale));
	slotTM.SetTranslation(poffset);
	GetEntity()->SetSlotLocalTM(slot, slotTM);

	if (slot == eIGS_FirstPerson && !m_mountparams.pivot.empty())
	{
		Matrix34 tm=GetEntity()->GetSlotLocalTM(eIGS_FirstPerson, false);
		Vec3 pivot = GetSlotHelperPos(eIGS_FirstPerson, m_mountparams.pivot.c_str(), false);
		tm.AddTranslation(pivot);

		GetEntity()->SetSlotLocalTM(eIGS_FirstPerson, tm);
		GetEntity()->SetWorldTM(GetEntity()->GetWorldTM());

		PlayAction(m_idleAnimation[eIGS_FirstPerson].c_str(), 0, true);
		ForceSkinning(true);
	}

	ReAttachAccessories();

	return true;
}

//------------------------------------------------------------------------
void CItem::SetDefaultIdleAnimation(int slot, const char *actionName)
{
	TActionMap::iterator it = m_actions.find(actionName);
	if (it == m_actions.end())
	{
//		GameWarning("Action '%s' not found on item '%s'!", actionName, GetEntity()->GetName());
		return;
	}

	SAction &action = it->second;

	ICharacterInstance *pCharacter = GetEntity()->GetCharacter(slot);
	if (pCharacter)
	{
		string name = action.animation[slot].name;
		FixResourceName(name, 0);
		//changed by ivo!
		//pCharacter->SetDefaultIdleAnimation(0, name.c_str());
	}
	m_idleAnimation[slot] = actionName;
}

//------------------------------------------------------------------------
void CItem::ForceSkinning(bool always)
{
	for (int slot=0; slot<eIGS_Last; slot++)
	{
		ICharacterInstance *pCharacter = GetEntity()->GetCharacter(slot);
		if (pCharacter)
		{
			pCharacter->Update(GetEntity()->GetSlotWorldTM(slot), GetISystem()->GetViewCamera());
			pCharacter->ForceUpdate(GetEntity()->GetSlotWorldTM(slot), 1);
		}
	}
}

//------------------------------------------------------------------------
void CItem::EnableHiddenSkinning(bool enable)
{
	/*
	for (int slot=0; slot<eIGS_Last; slot++)
	{
		ICharacterInstance *pCharacter = GetEntity()->GetCharacter(slot);
		if (pCharacter)
		{
			if (enable)
				pCharacter->SetFlags(pCharacter->GetFlags()|CS_FLAG_UPDATE_ALWAYS);
			else
				pCharacter->SetFlags(pCharacter->GetFlags()&(~CS_FLAG_UPDATE_ALWAYS));
		}
	}
	*/
}

//------------------------------------------------------------------------
void CItem::FixResourceName(string &name, int flags, const char *hand, const char *suffix, const char *pose, const char *pov, const char *env)
{
	if (!hand)
	{
		if (m_stats.hand == eIH_Left)
			hand = "left";
		else
			hand = "right";
	}
	name.replace("%hand%", hand);

	if (!suffix)
	{
		if (IsDualWield())
			suffix = m_params.dual_wield_suffix.c_str();
		else
			suffix = "";
	}
	name.replace("%suffix%", suffix);

	if (!pose)
	{
		if (!m_params.pose.empty())
			pose = m_params.pose.c_str();
		else
			pose = "";
	}
	name.replace("%pose%", "");

	if (!pov)
	{
		if ((m_stats.fp || flags&eIPAF_ForceFirstPerson) && !(flags&eIPAF_ForceThirdPerson))
			pov = ITEM_FIRST_PERSON_TOKEN;
		else
			pov = ITEM_THIRD_PERSON_TOKEN;
	}
	name.replace("%pov%", pov);

	if (!env)
	{
		IEntitySoundProxy *pProxy = GetSoundProxy(false);
		if (pProxy)
			env=pProxy->GetTailName();
		if (!env)
			return;

		string envname("_");
		if (!stricmp("indoor", env) || !env[0])
			envname.resize(0);
		else if (env[0])
			envname.append(env);

		name.replace("%env%", envname.c_str());
	}
}

//------------------------------------------------------------------------
tSoundID CItem::PlayAction(const char *actionName, int layer, bool loop, uint flags)
{
	TActionMap::iterator it = m_actions.find(actionName);
	if (it == m_actions.end())
	{
//		GameWarning("Action '%s' not found on item '%s'!", actionName, GetEntity()->GetName());
		return 0;
	}

	bool fp = m_stats.fp;
	if (flags&eIPAF_ForceFirstPerson)
		fp = true;
	if (flags&eIPAF_ForceThirdPerson)
		fp = false;

	SAction &action = it->second;
	
	tSoundID result = INVALID_SOUNDID;
	if ((flags&eIPAF_Sound) && !action.sound.name.empty() && IsSoundEnabled())
	{
		int nSoundFlags = (flags&eIPAF_SoundStartPaused?FLAG_SOUND_START_PAUSED:0) | (flags&eIPAF_SoundLooped?FLAG_SOUND_LOOP:0);
		IEntitySoundProxy *pSoundProxy = GetSoundProxy(true);
		EntityId pSkipEnts[3];
		int nSkipEnts = 0;

		// TODO for Marcio :)
		// check code changes

		// Skip the Item
		pSkipEnts[nSkipEnts] = GetEntity()->GetId();
		++nSkipEnts;

		// Skip the Owner
		if (GetOwner())
		{
			pSkipEnts[nSkipEnts] = GetOwner()->GetId();
			++nSkipEnts;
		}

		if (pSoundProxy)
		{
			string name = action.sound.name;
			FixResourceName(name, flags);
			nSoundFlags = nSoundFlags | (fp?FLAG_SOUND_2D:FLAG_SOUND_DEFAULT_3D);
			//nSoundFlags = nSoundFlags | (fp?FLAG_SOUND_DEFAULT_3D|FLAG_SOUND_RELATIVE:FLAG_SOUND_DEFAULT_3D);
			Vec3 vOffset(0,0,0);
			if (fp)
				vOffset.x = 0.3f; // offset for first person weapon to the front

			if (!i_staticfiresounds->GetIVal())
			{
				result = pSoundProxy->PlaySoundEx(name, vOffset, FORWARD_DIRECTION, 
					nSoundFlags, 255, 1, 255, pSkipEnts, nSkipEnts);
			}
			else
			{
				if ((action.sound.id != INVALID_SOUNDID) && (action.sound.static_name != name))
					ReleaseStaticSound(&action.sound);

				if (action.sound.id == INVALID_SOUNDID)
					result = pSoundProxy->PlaySoundEx(name, vOffset, FORWARD_DIRECTION,
						nSoundFlags, 255, 1, 255, pSkipEnts, nSkipEnts);

				if (action.sound.isstatic)
				{
					if (action.sound.id == INVALID_SOUNDID)
					{
						action.sound.id = result;
						action.sound.static_name = name;
						pSoundProxy->SetStaticSound(result, true);
					}
					else
					{
						ISound *pSound = pSoundProxy->GetSound(action.sound.id);
						if (pSound)
							pSound->Play(1.0, true, true, pSoundProxy);
					}
				}
			}
			
			if (action.sound.airadius > 0.0f)
			{
				IEntity *pOwner = GetOwner();
				GetISystem()->GetAISystem()->SoundEvent(GetEntity()->GetWorldPos(), action.sound.airadius, 0, 1,
					pOwner?pOwner->GetAI():0);
			}
		}
	}

	if (flags&eIPAF_Animation)
	{
		for (int i=0; i<eIGS_Last; i++)
		{
			if (!(flags&1<<i))
				continue;

			if (action.animation[i].name.empty())
				continue;

			string name = action.animation[i].name;

			FixResourceName(name, flags);

			if (i == eIGS_Owner)
			{
				if (!action.animation[eIGS_Owner].name.empty())
				{
					CActor *pOwner = GetOwnerActor();
					if (pOwner)
						pOwner->PlayAction(name.c_str(), m_params.pose.c_str());
				}
				continue;
			}

			ICharacterInstance *pCharacter = GetEntity()->GetCharacter(i);
			if (pCharacter && !action.animation[i].name.empty())
			{
				float blend = action.animation[i].blend;
				if (flags&eIPAF_NoBlend)
					blend = 0.0f;

				PlayAnimationEx(name.c_str(), i, layer, loop, blend, action.animation[i].speed, flags);
			}
		}
	}

	return result;
}

//------------------------------------------------------------------------
void CItem::PlayAnimation(const char *animationName, int layer, bool loop, uint flags)
{
	for (int i=0; i<eIGS_Last; i++)
	{
		if (!(flags&1<<i))
			continue;

		PlayAnimationEx(animationName, i, layer, loop, 0.175f, 1.0f, flags);
	}
}

//------------------------------------------------------------------------
void CItem::PlayAnimationEx(const char *animationName, int slot, int layer, bool loop, float blend, float speed, uint flags)
{
	ICharacterInstance *pCharacter = GetEntity()->GetCharacter(slot);
	if (pCharacter && animationName)
	{
		ISkeleton *pSkeleton = pCharacter->GetISkeleton();

		if (flags&eIPAF_CleanBlending)
		{
			while(pSkeleton->GetNumAnimsInFIFO(layer)>1)
			{
				if (!pSkeleton->RemoveAnimFromFIFO(layer, pSkeleton->GetNumAnimsInFIFO(layer)-1))
					break;
			}
		}

		if (flags&eIPAF_NoBlend)
			blend = 0.0f;

		CryCharAnimationParams params;
		params.fTransTime = blend;
		params.nLayerID = layer;
		params.nFlags = CA_RECURSIVE|(loop?CA_LOOP_ANIMATION:0)|(flags&eIPAF_RestartAnimation?CA_ALLOW_ANIM_RESTART:0)|(flags&eIPAF_RepeatLastFrame?CA_REPEAT_LAST_KEY:0);
		pSkeleton->StartAnimation(animationName, 0, params);
		pSkeleton->SetAnimationSpeedLayer(layer, speed);
		
		//pCharacter->GetISkeleton()->SetDebugging( true );

		float duration=0.0f;
		int animationId = pCharacter->GetIAnimationSet()->GetIDByName(animationName);
		if (animationId>=0)
			duration = pCharacter->GetIAnimationSet()->GetDuration_sec(animationId);
		
		m_animationTime[slot] = (uint)(duration*1000.0f/speed);
		m_animationEnd[slot] = (uint)(m_pGameFramework->GetISystem()->GetITimer()->GetCurrTime()*1000.0f)+m_animationTime[slot];
		m_animationSpeed[slot] = speed;
	}
}



//------------------------------------------------------------------------
void CItem::PlayLayer(const char *name, int flags, bool record)
{
	TLayerMap::iterator it = m_layers.find(name);
	if (it == m_layers.end())
		return;

	for (int i=0; i<eIGS_Last; i++)
	{
		if (!(flags&1<<i))
			continue;

		SLayer &layer = it->second;

		if (!layer.name[i].empty())
		{
			ICharacterInstance *pCharacter = GetEntity()->GetCharacter(i);
			if (pCharacter)
			{
				CryCharAnimationParams params;
				float blend = 0.125f;
				if (flags&eIPAF_NoBlend)
					blend = 0.0f;
				params.fTransTime = blend;
				params.nLayerID = layer.id[i];
				params.nFlags = CA_LOOP_ANIMATION;

				string name = layer.name[i];
				FixResourceName(name, flags);

				ISkeleton *pSkeleton=pCharacter->GetISkeleton();
				pSkeleton->SetRedirectToLayer0(1);
				pSkeleton->StartAnimation(name, 0, params);

				if (layer.bones.empty())
				{
					pCharacter->GetISkeleton()->SetBonesLayerStatus(layer.id[i], 1);
				}
				else
				{
					pCharacter->GetISkeleton()->SetBonesLayerStatus(layer.id[i], 0);
					for (std::vector<string>::iterator bit = layer.bones.begin(); bit != layer.bones.end(); bit++)
						pCharacter->GetISkeleton()->SetBoneLayerStatus(bit->c_str(), layer.id[i], 1);
				}
			}
		}
	}

	if (record)
	{
		TActiveLayerMap::iterator ait = m_activelayers.find(name);
		if (ait == m_activelayers.end())
			m_activelayers.insert(TActiveLayerMap::value_type(name, flags));
	}
}

//------------------------------------------------------------------------
void CItem::StopLayer(const char *name, int flags, bool record)
{
	TLayerMap::iterator it = m_layers.find(name);
	if (it == m_layers.end())
		return;

	for (int i=0; i<eIGS_Last; i++)
	{
		if (!(flags&1<<i))
			continue;

		ICharacterInstance *pCharacter = GetEntity()->GetCharacter(i);
		if (pCharacter)
			pCharacter->GetISkeleton()->StopAnimationInLayer(it->second.id[i]);
	}

	if (record)
	{
		TActiveLayerMap::iterator ait = m_activelayers.find(name);
		if (ait != m_activelayers.end())
			m_activelayers.erase(ait);
	}
}

//------------------------------------------------------------------------
void CItem::RestoreLayers()
{
	for (TActiveLayerMap::iterator it = m_activelayers.begin(); it != m_activelayers.end(); it++)
		PlayLayer(it->first, it->second, false);

	for (TLayerMap::iterator lit = m_layers.begin(); lit != m_layers.end(); lit++)
	{
		if (lit->second.isstatic)
			PlayLayer(lit->first, eIPAF_Default, false);
	}
}

//------------------------------------------------------------------------
void CItem::ResetAnimation(int layer, uint flags)
{
	for (int i=0; i<eIGS_Last; i++)
	{
		if (!(flags&1<<i))
			continue;

		if (i == eIGS_Owner)
			continue;

		ICharacterInstance *pCharacter = GetEntity()->GetCharacter(i);
		if (pCharacter)
			pCharacter->GetISkeleton()->StopAnimationsAllLayers();
	}
}

//------------------------------------------------------------------------
uint CItem::GetCurrentAnimationTime(int slot)
{
	return m_animationTime[slot];
}

//------------------------------------------------------------------------
uint CItem::GetCurrentAnimationEnd(int slot)
{
	return m_animationEnd[slot];
}

//------------------------------------------------------------------------
uint CItem::GetCurrentAnimationStart(int slot)
{
	return m_animationEnd[slot]-m_animationTime[slot];
}

//------------------------------------------------------------------------
void CItem::DrawSlot(int slot, bool draw, bool near)
{
	uint flags = GetEntity()->GetSlotFlags(slot);
	if (draw)
		flags |= ENTITY_SLOT_RENDER;
	else
		flags &= ~ENTITY_SLOT_RENDER;

	if (near)
		flags |= ENTITY_SLOT_RENDER_NEAREST;
	else
		flags &= ~ENTITY_SLOT_RENDER_NEAREST;
	
	GetEntity()->SetSlotFlags(slot, flags);
}

//------------------------------------------------------------------------
Vec3 CItem::GetSlotHelperPos(int slot, const char *helper, bool worldSpace)
{
	Vec3 position(0,0,0);

	SEntitySlotInfo info;
	if (GetEntity()->GetSlotInfo(slot, info))
	{
		if (info.pStatObj)
		{
			IStatObj *pStatsObj = info.pStatObj;
			position = pStatsObj->GetHelperPos(helper);
			position = GetEntity()->GetSlotLocalTM(slot, false).TransformPoint(position);
		}
		else if (info.pCharacter)
		{
			ICharacterInstance *pCharacter = info.pCharacter;
			int16 id = pCharacter->GetISkeleton()->GetIDByName(helper);
			if (id > -1)
				position = pCharacter->GetISkeleton()->GetAbsJPositionByID(id);

			position = GetEntity()->GetSlotLocalTM(slot, false).TransformPoint(position);
		}
	}

	if (worldSpace)
		return GetEntity()->GetWorldTM().TransformPoint(position);

	return position;
}

//------------------------------------------------------------------------
void CItem::StopSound(tSoundID id)
{
	IEntitySoundProxy *pSoundProxy = GetSoundProxy(false);
	if (pSoundProxy)
	{
		for (TActionMap::iterator it = m_actions.begin(); it != m_actions.end(); ++it)
		{
			SAction &action = it->second;
			if (action.sound.isstatic && (action.sound.id == id))
			{
				pSoundProxy->SetStaticSound(id, false);
				action.sound.id = INVALID_SOUNDID;
			}
		}
		pSoundProxy->StopSound(id);
	}
}

//------------------------------------------------------------------------
void CItem::Quiet()
{
	IEntitySoundProxy *pSoundProxy = GetSoundProxy(false);
	if (pSoundProxy)
	{
		for (TActionMap::iterator it = m_actions.begin(); it != m_actions.end(); ++it)
		{
			SAction &action = it->second;
			if (action.sound.isstatic)
			{
				pSoundProxy->SetStaticSound(action.sound.id, false);
				action.sound.id = INVALID_SOUNDID;
			}
		}

		pSoundProxy->StopAllSounds();
	}
}

//------------------------------------------------------------------------
ISound *CItem::GetISound(tSoundID id)
{
	IEntitySoundProxy *pSoundProxy = GetSoundProxy(false);
	if (pSoundProxy)
		return pSoundProxy->GetSound(id);

	return INVALID_SOUNDID;
}

//------------------------------------------------------------------------
void CItem::ReleaseStaticSound(SAudio *sound)
{
	if (sound->isstatic && (sound->id != INVALID_SOUNDID))
	{
		IEntitySoundProxy *pSoundProxy = GetSoundProxy(false);
		if (pSoundProxy)
		{
			pSoundProxy->SetStaticSound(sound->id, false);
			pSoundProxy->StopSound(sound->id);
			sound->id = INVALID_SOUNDID;
			sound->static_name.resize(0);
		}
	}
}

//------------------------------------------------------------------------
void CItem::ReleaseStaticSounds()
{
	for (TActionMap::iterator it = m_actions.begin(); it != m_actions.end(); ++it)
		ReleaseStaticSound(&it->second.sound);
}

//------------------------------------------------------------------------
IEntitySoundProxy *CItem::GetSoundProxy(bool create)
{
	IEntitySoundProxy *pSoundProxy = (IEntitySoundProxy *)GetEntity()->GetProxy(ENTITY_PROXY_SOUND);
	if (!pSoundProxy && create)
		pSoundProxy = (IEntitySoundProxy *)GetEntity()->CreateProxy(ENTITY_PROXY_SOUND);

	return pSoundProxy;
}

//------------------------------------------------------------------------
IEntityRenderProxy *CItem::GetRenderProxy(bool create)
{
	IEntityRenderProxy *pRenderProxy = (IEntityRenderProxy *)GetEntity()->GetProxy(ENTITY_PROXY_RENDER);
	if (!pRenderProxy && create)
		pRenderProxy = (IEntityRenderProxy *)GetEntity()->CreateProxy(ENTITY_PROXY_RENDER);

	return pRenderProxy;
}

//------------------------------------------------------------------------
IEntityPhysicalProxy *CItem::GetPhysicalProxy(bool create)
{
	IEntityPhysicalProxy *pPhysicalProxy = (IEntityPhysicalProxy *)GetEntity()->GetProxy(ENTITY_PROXY_PHYSICS);
	if (!pPhysicalProxy && create)
		pPhysicalProxy = (IEntityPhysicalProxy *)GetEntity()->CreateProxy(ENTITY_PROXY_PHYSICS);

	return pPhysicalProxy;
}
