/*************************************************************************
  Crytek Source File.
  Copyright (C), Crytek Studios, 2001-2004.
 -------------------------------------------------------------------------
  $Id$
  $DateTime$
  
 -------------------------------------------------------------------------
  History:
  - 27:10:2004   11:26 : Created by Márcio Martins

*************************************************************************/
#include "StdAfx.h"
#include "Item.h"
#include "Game.h"
#include "GameActions.h"
#include "IGameObject.h"
#include "ISerialize.h"
#include <IEntitySystem.h>

#include "Actor.h"
#include "Player.h"
#include "IActorSystem.h"
#include "IItemSystem.h"
#include "ActionMapManager.h"
#include "ScriptBind_Item.h"
#include "GameRules.h"

#pragma warning(disable: 4355)	// ´this´ used in base member initializer list

ICVar* CItem::i_staticfiresounds = 0;
ICVar* CItem::i_offset_front = 0;
ICVar* CItem::i_offset_up = 0;
ICVar* CItem::i_offset_right = 0;
ICVar* CItem::i_unlimitedammo = 0;
ICVar* CItem::i_lighteffects = 0;
ICVar* CItem::i_particleeffects = 0;

//------------------------------------------------------------------------
CItem::CItem()
: m_scheduler(this),	// just to store the pointer.
	m_dualWieldMasterId(0),
	m_dualWieldSlaveId(0),
	m_requireUpdate(false),
	m_ownerId(0),
	m_parentId(0),
	m_effectGenId(0),
  m_hostId(0),
	m_pEntityScript(0),
	m_pEntitySystem(0),
	m_pItemSystem(0),
	m_pGameFramework(0),
	m_bModifying(false),
	m_bTransitioning(false),
	m_dummyOffset(0,0,0),
	m_frozen(false)
{
	memset(m_animationTime, 0, sizeof(m_animationTime));
	memset(m_animationEnd, 0, sizeof(m_animationTime));
	memset(m_animationSpeed, 0, sizeof(m_animationSpeed));

	if (!i_staticfiresounds)
		i_staticfiresounds = GetISystem()->GetIConsole()->GetCVar("i_staticfiresounds", false);
	if (!i_offset_front)
		i_offset_front = GetISystem()->GetIConsole()->GetCVar("i_offset_front", false);
	if (!i_offset_up)
		i_offset_up = GetISystem()->GetIConsole()->GetCVar("i_offset_up", false);
	if (!i_offset_right)
		i_offset_right = GetISystem()->GetIConsole()->GetCVar("i_offset_right", false);
	if (!i_unlimitedammo)
		i_unlimitedammo = GetISystem()->GetIConsole()->GetCVar("i_unlimitedammo", false);
	if (!i_lighteffects)
		i_lighteffects = GetISystem()->GetIConsole()->GetCVar("i_lighteffects", false);
	if (!i_particleeffects)
		i_particleeffects = GetISystem()->GetIConsole()->GetCVar("i_particleeffects", false);
}

//------------------------------------------------------------------------
CItem::~CItem()
{
	GetGameObject()->ReleasePhysics(this);

	for (TAccessoryMap::iterator it=m_accessories.begin(); it!=m_accessories.end(); ++it)
		GetISystem()->GetIEntitySystem()->RemoveEntity(it->second);

	AttachArms(false);
	
	if(m_pItemSystem)
		m_pItemSystem->RemoveItem(GetEntityId());
}

//------------------------------------------------------------------------
bool CItem::Init( IGameObject *pGameObject )
{
	SetGameObject(pGameObject);
	
	if (!GetGameObject()->CapturePhysics(this))
		return false;

	m_pEntityScript = GetEntity()->GetScriptTable();
	m_pEntitySystem = GetISystem()->GetIEntitySystem();
	m_pGameFramework= GetISystem()->GetIGame()->GetIGameFramework();
	m_pItemSystem = m_pGameFramework->GetIItemSystem();

	// register with item system
	m_pItemSystem->AddItem(GetEntityId(), this);

	// read params
	const IItemParamsNode *root = m_pItemSystem->GetItemParams(GetEntity()->GetClass()->GetName());
	ReadItemParams(root);

	m_stateTable[0] = GetEntity()->GetScriptTable();
	if (!!m_stateTable[0])
	{
		m_stateTable[0]->GetValue("Server", m_stateTable[1]);
		m_stateTable[0]->GetValue("Client", m_stateTable[2]);
	} 

	g_pGame->GetItemScriptBind()->AttachTo(this);
	
	PreCache();

	//compute item volume
	AABB bounds;
	GetEntity()->GetLocalBounds(bounds);
	Vec3 delta(bounds.max - bounds.min);
	m_fVolume = fabs(delta.x * delta.y * delta.z);

	if (0 == (GetEntity()->GetFlags() & (ENTITY_FLAG_CLIENT_ONLY | ENTITY_FLAG_SERVER_ONLY)))
		if (!GetGameObject()->BindToNetwork())
			return false;

	return true;
}

//------------------------------------------------------------------------
void CItem::PostInit( IGameObject * pGameObject )
{
	OnReset();

	InitialSetup();
}

//------------------------------------------------------------------------
void CItem::Release()
{
	delete this;
}

//------------------------------------------------------------------------
void CItem::Update( SEntityUpdateContext& ctx, int slot )
{
	FUNCTION_PROFILER(GetISystem(), PROFILE_GAME);
	if (m_frozen)
		return;

	switch (slot)
	{
	case eIUS_Scheduler:
		m_scheduler.Update(ctx.fFrameTime);
		break;
	}

	// drop the item if too heavy
	/*if (IsSelected())		//current design: just slow down the player movement
	{
		CActor *pActor = GetOwnerActor();

		if(pActor)
		{
			bool zeroG = false;
			if(pActor->IsPlayer())
			{
				CPlayer *pPlayer = (CPlayer*)pActor;
				zeroG = pPlayer->IsZeroG();
			}

			if (!zeroG && !pActor->CanPickUpObject(m_params.mass, m_fVolume))
			{
				const char *str="You need more strength to hold this item!";
				SGameObjectEvent evt("HUD_TextMessage",eGOEF_ToAll, IGameObjectSystem::InvalidExtensionID, (void*)str);
				m_pGameFramework->GetIGameObjectSystem()->BroadcastEvent(evt);

				pActor->DropItem(GetEntityId());
			}
		}
	}*/

	// update mounted
	UpdateMounted(ctx.fFrameTime);
}

//------------------------------------------------------------------------
bool CItem::SetProfile( uint8 profile )
{
	//CryLogAlways("%s::SetProfile(%d: %s)", GetEntity()->GetName(), profile, profile==eIPhys_Physicalized?"Physicalized":"NotPhysicalized");

	switch (profile)
	{
	case eIPhys_Physicalized:
		{
			SEntityPhysicalizeParams params;
			params.type = PE_RIGID;
			params.nSlot = eIGS_ThirdPerson;
			params.mass = m_params.mass;

			pe_params_buoyancy buoyancy;
			buoyancy.waterDamping = 1.5;
			buoyancy.waterResistance = 1000;
			buoyancy.waterDensity = 0;
			params.pBuoyancy = &buoyancy;

			GetEntity()->Physicalize(params);

			IPhysicalEntity *pPhysics = GetEntity()->GetPhysics();
			if (pPhysics)
			{
				pe_action_awake action;
				action.bAwake = 1;
				pPhysics->Action(&action);
			}
		}
		return true;
	case eIPhys_NotPhysicalized:
		{
			IEntityPhysicalProxy *pPhysicsProxy = GetPhysicalProxy();
			if (pPhysicsProxy)
			{
				SEntityPhysicalizeParams params;
				params.type = PE_NONE;
				params.nSlot = eIGS_ThirdPerson;
				pPhysicsProxy->Physicalize(params);
			}
		}
		return true;
	default:
		assert(!"Unknown physicalization profile!");
		return false;
	}
}

bool CItem::SerializeProfile( TSerialize ser, uint8 profile )
{
	pe_type type = PE_NONE;
	switch (profile)
	{
	case eIPhys_Physicalized:
		type = PE_RIGID;
		break;
	case eIPhys_NotPhysicalized:
		type = PE_NONE;
		break;
	default:
		return false;
	}

	if (type == PE_NONE)
		return true;

	IEntityPhysicalProxy * pEPP = (IEntityPhysicalProxy *) GetEntity()->GetProxy(ENTITY_PROXY_PHYSICS);
	if (!pEPP)
		return false;

	pEPP->SerializeTyped( ser, type );
	return true;
}

//------------------------------------------------------------------------
void CItem::ProcessEvent(SEntityEvent &event)
{
	switch (event.event)
	{
	case ENTITY_EVENT_TIMER:
		{
			switch (event.nParam[0])
			{
			case eIT_Flying:
				m_stats.flying = false;
				break;
			}
      break;
		}
  case ENTITY_EVENT_RESET:
    OnReset();
    break;
	}
}

//------------------------------------------------------------------------
void CItem::Serialize( TSerialize ser, unsigned aspects )
{
	if (ser.GetSerializationTarget() != eST_Network)
	{
		ser.Value("ownerId", m_ownerId);
		ser.Value("parentId", m_parentId);
	}
	else if (aspects & eEA_GameServerDynamic)
	{
		/*CryLogAlways("%s::Serialize(ownerId: %s, parentId: %s)", GetEntity()->GetName(),
			GetActor(NetGetOwnerId())?GetActor(NetGetOwnerId())->GetEntity()->GetName():"",
			m_parentId?GetActor(m_parentId)->GetEntity()->GetName():"");
		*/
		ser.Value("ownerId", this, &CItem::NetGetOwnerId, &CItem::NetSetOwnerId, NSerPolicy::AC_EntityId());
		ser.Value("parentId", m_parentId, NSerPolicy::AC_EntityId());
	}
}

//------------------------------------------------------------------------
void CItem::SetOwnerId(EntityId ownerId)
{
	m_ownerId = ownerId;

	GetGameObject()->ChangedNetworkState(eEA_GameServerDynamic);
}

//------------------------------------------------------------------------
EntityId CItem::GetOwnerId() const
{
	return m_ownerId;
}

//------------------------------------------------------------------------
void CItem::SetParentId(EntityId parentId)
{
	m_parentId = parentId;

	GetGameObject()->ChangedNetworkState(eEA_GameServerDynamic);
}

//------------------------------------------------------------------------
EntityId CItem::GetParentId() const
{
	return m_parentId;
}

//------------------------------------------------------------------------
void CItem::SetHand(int hand)
{
	m_stats.hand = hand;

	int idx = 0;
	if (hand == eIH_Right)
		idx = 1;
	else if (hand == eIH_Left)
		idx = 2;

	if (m_fpgeometry[idx].name.empty())
		idx = 0;

	SGeometry &geometry = m_fpgeometry[idx];
	SetGeometry(eIGS_FirstPerson, geometry.name.c_str(), geometry.position, geometry.angles, geometry.scale);

	if (idx == 0)
	{
		ICharacterInstance *pCharacter = GetEntity()->GetCharacter(eIGS_FirstPerson);
		if (!pCharacter)
			return;
		
		if (hand == eIH_Left)
			pCharacter->SetScale(Vec3(-1,1,1));
		else
			pCharacter->SetScale(Vec3(1,1,1));
	}
}

//------------------------------------------------------------------------
void CItem::Use(EntityId userId)
{
	if (m_params.usable && m_stats.mounted)
	{
		if (!m_ownerId)
			StartUse(userId);
		else if (m_ownerId == userId)
			StopUse(userId);
	}
}

//------------------------------------------------------------------------
void CItem::Select(bool select)
{
	//CryLogAlways("%s::Select(%s)", GetEntity()->GetName(), select?"true":"false");

	CheckViewChange();

	if (select)
	{
		GetEntity()->Hide(false);

		if (!m_stats.mounted && GetOwner())
		  GetEntity()->SetWorldTM(GetOwner()->GetWorldTM());	// move somewhere near the owner so the sound can play

		SetBusy(true);
		PlayAction("select", 0, false, eIPAF_Default|eIPAF_NoBlend);
		ForceSkinning(true);

		struct SelectAction: public ISchedulerAction
		{
			void execute(CItem *_item)
			{
				_item->SetBusy(false);
			}
		};	
		GetScheduler()->TimerAction(MAX(250, GetCurrentAnimationTime(eIGS_FirstPerson))-250, new SelectAction(), false);
	}
	else
	{
		if (!m_stats.mounted)
		{
			SetViewMode(0);
			GetEntity()->Hide(true);
		}

		// set no-weapon pose on actor
		CActor *pOwner = GetOwnerActor();
		if (pOwner)
			pOwner->PlayAction("idle", ITEM_DESELECT_POSE);

		EnableUpdate(false);

		ReleaseStaticSounds();
	}

	if (IItem *pSlave=GetDualWieldSlave())
		pSlave->Select(select);
}

//------------------------------------------------------------------------
void CItem::Drop()
{
	//CryLogAlways("%s::Drop()", GetEntity()->GetName());
	CActor *pOwner = GetOwnerActor();
	if (pOwner)
	{
		IInventory *pInventory = GetActorInventory(pOwner);
		if (pInventory && pInventory->GetCurrentItem() == GetEntity()->GetId())
			pInventory->SetCurrentItem(0);
	}

	if (IsDualWieldSlave())
		GetDualWieldMaster()->ResetDualWield();
	ResetDualWield();

	Select(false);
	SetViewMode(eIVM_ThirdPerson);
	AttachToHand(false);

	Hide(false);

	Physicalize(true);

	if (pOwner)
	{
		if (IMovementController * pMC = pOwner->GetMovementController())
		{
			SMovementState moveState;
			pMC->GetMovementState(moveState);

			Vec3 dir = moveState.eyeDirection;
			Vec3 pos = moveState.eyePosition+moveState.eyeDirection;

			Matrix34 tm = Matrix34(Matrix33::CreateRotationVDir(dir)*Matrix33::CreateRotationXYZ(DEG2RAD(m_params.drop_angles)));
			tm.SetTranslation(pos-Vec3(0.0f,0.0f,0.15f));
			GetEntity()->SetWorldTM(tm);

			IEntityPhysicalProxy *pPhysics = GetPhysicalProxy();
			if (pPhysics)
				pPhysics->AddImpulse(-1, m_params.drop_impulse_pos, dir*m_params.drop_impulse, true, 1.0f);
		}

		// remove from inventory
		GetActorInventory(GetOwnerActor())->RemoveItem(GetEntity()->GetId());
		SetOwnerId(0);
	}

	Pickalize(true, true);

	if (IsServer())
		g_pGame->GetGameRules()->OnItemDropped(GetEntityId(), pOwner?pOwner->GetEntityId():0);
}


//------------------------------------------------------------------------
void CItem::PickUp(EntityId pickerId, bool sound, bool select, bool keepHistory)
{
	//CryLogAlways("%s::PickUp(%08x:%s)", GetEntity()->GetName(), pickerId, GetActor(pickerId)?GetActor(pickerId)->GetEntity()->GetName():"null");

	Physicalize(false);

	bool soundEnabled = IsSoundEnabled();
	EnableSound(sound);

	SetViewMode(0);		
	SetOwnerId(pickerId);

	CopyRenderFlags(GetOwner());

	GetEntity()->Hide(true);
	m_stats.dropped = false;

	// move the entity to picker position
	IEntity *pOwner = GetOwner();
	if (pOwner)
	{
		Matrix34 tm(pOwner->GetWorldTM());
		tm.AddTranslation(Vec3(0,0,2));
		GetEntity()->SetWorldTM(tm);
	}

	// dual wielding stuff goes here
	PlayAction("pickedup");

	bool slave = false;
	IInventory *pInventory = GetActorInventory(m_pGameFramework->GetIActorSystem()->GetActor(pickerId));
	if (!pInventory)
	{
		GameWarning("Actor '%s' has no inventory, when trying to pickup '%s'!",
			GetActor(pickerId)?GetActor(pickerId)->GetEntity()->GetName():"null",
			GetEntity()->GetName());
		return;
	}

	int n = pInventory->GetCount();
	for (int i=0; i<n; i++)
	{
		EntityId itemId = pInventory->GetItem(i);
		IItem *pItem = m_pItemSystem->GetItem(itemId);
		if (!pItem)
			continue;

		if ((pItem != this) && !pItem->IsDualWield() && pItem->SupportsDualWield(GetEntity()->GetClass()->GetName()))
		{
			EnableUpdate(true);
			SetDualWieldMaster(pItem->GetEntity()->GetId());
			pItem->SetDualWieldSlave(GetEntity()->GetId());

			slave = true;
			if (pItem->GetEntity()->GetId() == pInventory->GetCurrentItem())
				pItem->Select(true);
			break;
		}
	}

	// add to inventory
	pInventory->AddItem(GetEntity()->GetId());

	if (!slave && CanSelect() && select)
		m_pItemSystem->SetActorItem(GetOwnerActor(), GetEntity()->GetId(), keepHistory);

	EnableSound(soundEnabled);

	if (IsServer())
		g_pGame->GetGameRules()->OnItemPickedUp(GetEntityId(), pickerId);
}

//------------------------------------------------------------------------
void CItem::Physicalize(bool enable)
{
	if (IsServer())
		GetGameObject()->SetPhysicalizationProfile(enable?eIPhys_Physicalized:eIPhys_NotPhysicalized);
}

//------------------------------------------------------------------------
void CItem::Pickalize(bool enable, bool dropped)
{
	if (enable)
	{
		m_stats.flying = dropped;
		m_stats.dropped = true;
		m_stats.pickable = true;

		GetEntity()->KillTimer(eIT_Flying);
		GetEntity()->SetTimer(eIT_Flying, m_params.fly_timer);
	}
	else
	{
		m_stats.flying = false;
		m_stats.pickable = false;
	}
}

//------------------------------------------------------------------------
void CItem::AttachArms(bool attach)
{
	if (!m_params.arms)
		return;

	CActor *pOwnerActor = static_cast<CActor *>(GetOwnerActor());
	if (!pOwnerActor)
		return;

	if (attach)
		SetGeometry(eIGS_Arms, 0);
	else
		ResetCharacterAttachment(eIGS_FirstPerson, ITEM_ARMS_ATTACHMENT_NAME);
}

//------------------------------------------------------------------------
void CItem::Impulse(const Vec3 &position, const Vec3 &direction, float impulse)
{
	if (direction.len2() <= 0.001f)
		return;

	IEntityPhysicalProxy *pPhysicsProxy = GetPhysicalProxy();
	if (pPhysicsProxy)
		pPhysicsProxy->AddImpulse(-1, position, direction.GetNormalized()*impulse, true, 1);
}

//------------------------------------------------------------------------
bool CItem::CanPickUp(EntityId userId)
{
	if (m_params.pickable && m_stats.pickable && !m_stats.flying)
		return true;
	return false;
}

//------------------------------------------------------------------------
bool CItem::CanDrop()
{
	if (m_params.droppable)
		return true;

	return false;
}

//------------------------------------------------------------------------
bool CItem::CanUse(EntityId userId)
{
	return m_params.usable && IsMounted() && (!m_stats.used || (m_ownerId == userId));
}

//------------------------------------------------------------------------
bool CItem::IsMounted()
{
	return m_stats.mounted;
}

//------------------------------------------------------------------------
Vec3 CItem::GetMountedAngleLimits() const
{
	if(m_stats.mounted)
		return Vec3(m_mountparams.min_pitch, m_mountparams.max_pitch, m_mountparams.yaw_range);
	else 
		return ZERO;
}

//------------------------------------------------------------------------
bool CItem::IsUsed()
{
	return m_stats.used;
}

//------------------------------------------------------------------------
void CItem::EnableSelect(bool enable)
{
	m_stats.selectable = enable;
}

//------------------------------------------------------------------------
bool CItem::CanSelect() const
{
	return m_params.selectable && m_stats.selectable;
}

//------------------------------------------------------------------------
bool CItem::IsSelected() const
{
	IInventory *pInventory = GetActorInventory(GetOwnerActor());
	return pInventory && (pInventory->GetCurrentItem() == GetEntity()->GetId());
}

//------------------------------------------------------------------------
void CItem::EnableSound(bool enable)
{
	m_stats.sound_enabled = enable;
}

//------------------------------------------------------------------------
bool CItem::IsSoundEnabled() const
{
	return m_stats.sound_enabled;
}

//------------------------------------------------------------------------
void CItem::MountAt(const Vec3 &pos)
{
	if (!m_params.mountable)
		return;

	m_stats.mounted = true;
	m_hostId = 0;

	Matrix34 tm(GetEntity()->GetWorldTM());
	tm.SetTranslation(pos);
	GetEntity()->SetWorldTM(tm);

	m_stats.mount_dir = GetEntity()->GetWorldTM().TransformVector(FORWARD_DIRECTION);
}

//------------------------------------------------------------------------
void CItem::MountAtEntity(EntityId entityId, const Vec3 &pos, const Ang3 &angles)
{
	if (!m_params.mountable)
		return;

	IEntity *pHost = m_pEntitySystem->GetEntity(entityId);
	if (!pHost)
		return;

	m_hostId = entityId;
	m_stats.mounted = true;

	pHost->AttachChild(GetEntity(), 0);

	Matrix34 tm = Matrix33(Quat::CreateRotationXYZ(angles));
	tm.SetTranslation(pos);
	GetEntity()->SetLocalTM(tm);

	m_stats.mount_dir = GetEntity()->GetWorldTM().TransformVector(FORWARD_DIRECTION);
}


//------------------------------------------------------------------------
IEntity *CItem::GetOwner() const
{
	if (!m_ownerId)
		return 0;

	return m_pEntitySystem->GetEntity(m_ownerId);
}

//------------------------------------------------------------------------
CActor *CItem::GetOwnerActor() const
{
	return static_cast<CActor *>(m_pGameFramework->GetIActorSystem()->GetActor(m_ownerId));
}

//------------------------------------------------------------------------
CActor *CItem::GetActor(EntityId actorId) const
{
	return static_cast<CActor *>(m_pGameFramework->GetIActorSystem()->GetActor(actorId));
}

//------------------------------------------------------------------------
IInventory *CItem::GetActorInventory(IActor *pActor) const
{
	if (!pActor)
		return 0;

	return static_cast<IInventory *>(pActor->GetGameObject()->QueryExtension("Inventory"));
}

//------------------------------------------------------------------------
void CItem::OnAction(EntityId actorId, const char* actionId, int activationMode, float value)
{
	CallScriptEvent(eISET_Client, "OnAction", actorId, actionId, activationMode, value, 0, 0, 0);
}

//------------------------------------------------------------------------
void CItem::StartUse(EntityId userId)
{
	if (!m_params.usable || m_ownerId)
		return;

	ScriptHandle scriptHandle(userId);
	CallScriptEvent(eISET_All, "OnStartUse", scriptHandle, 0, 0, 0);

	// holster user item here
	SetOwnerId(userId);
	m_pItemSystem->SetActorItem(GetOwnerActor(), GetEntityId(), true);

	m_stats.used = true;

	// very dangerous
	// TODO: find a way to have these parameters in CActor
	CActor *pActor = GetOwnerActor();
	if (!pActor)
		return;

	SActorParams *pParams = pActor->GetActorParams();

	pParams->viewPivot = GetEntity()->GetWorldPos();
	pParams->viewDistance = -m_mountparams.eye_distance;
	pParams->viewHeightOffset = m_mountparams.eye_height;
	pParams->vLimitDir = m_stats.mount_dir;
	pParams->vLimitRangeH = DEG2RAD(m_mountparams.yaw_range);
	pParams->vLimitRangeV = DEG2RAD((m_mountparams.max_pitch-m_mountparams.min_pitch)*0.5f);
	pParams->speedMultiplier = 0.0f;

	RequireUpdate(true);
	EnableUpdate(true);

	// TODO: precreate this table
	SmartScriptTable locker(GetISystem()->GetIScriptSystem());
	locker->SetValue("locker", ScriptHandle(GetEntityId()));
	locker->SetValue("lockId", ScriptHandle(GetEntityId()));
	locker->SetValue("lockIdx", 1);
	pActor->GetGameObject()->SetExtensionParams("Interactor", locker);
}

//------------------------------------------------------------------------
void CItem::StopUse(EntityId userId)
{
	if (userId != m_ownerId)
			return;

	ScriptHandle scriptHandle(userId);
	CallScriptEvent(eISET_All, "OnStopUse", scriptHandle, 0, 0, 0);

	CActor *pActor = GetOwnerActor();
	if (!pActor)
		return;

	if (pActor->GetHealth()>0)
		pActor->SelectLastItem(true);

	SActorParams *pParams = pActor->GetActorParams();
	pParams->viewPivot.zero();
	pParams->viewDistance = 0.0f;
	pParams->viewHeightOffset = 0.0f;
	pParams->vLimitDir.zero();
	pParams->vLimitRangeH = 0.0f;
	pParams->vLimitRangeV = 0.0f;
	pParams->speedMultiplier = 1.0f;

	RequireUpdate(false);
	EnableUpdate(false);

	m_stats.used = false;

	SetOwnerId(0);

	// TODO: precreate this table
	SmartScriptTable locker(GetISystem()->GetIScriptSystem());
	locker->SetValue("locker", ScriptHandle(GetEntityId()));
	locker->SetValue("lockId", ScriptHandle(0));
	locker->SetValue("lockIdx", 0);
	pActor->GetGameObject()->SetExtensionParams("Interactor", locker);
}

//------------------------------------------------------------------------
void CItem::AttachToHand(bool attach)
{
  if (m_stats.mounted)
    return;

	IEntity *pOwner = GetOwner();
	if (!pOwner)
		return;

	ICharacterInstance *pOwnerCharacter = pOwner->GetCharacter(0);
	if (!pOwnerCharacter)
		return;

	IAttachmentManager *pAttachmentManager = pOwnerCharacter->GetIAttachmentManager();
	IAttachment *pAttachment = pAttachmentManager->GetInterfaceByName(m_params.attachment.c_str());

	if (!pAttachment)
	{
		GameWarning("Item owner '%' doesn't have third-person item attachment point '%'!", pOwner->GetName(), m_params.attachment.c_str());
		return;
	}

	if (!attach)
	{
		pAttachment->ClearBinding();
	}
	else
	{
		CEntityAttachment *pEntityAttachment = new CEntityAttachment();
		pEntityAttachment->SetEntityId(GetEntityId());

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

//------------------------------------------------------------------------
void CItem::RequireUpdate(bool enable)
{
	m_requireUpdate = enable;
}

//------------------------------------------------------------------------
void CItem::EnableUpdate(bool enable)
{
	if (enable)
		GetEntity()->Activate(enable);
	else if ((!IsSelected() || !m_stats.fp) && !m_requireUpdate)
		GetEntity()->Activate(enable);
}

//------------------------------------------------------------------------
void CItem::Hide(bool hide)
{
	if (hide)
		GetEntity()->SetFlags(GetEntity()->GetFlags()|ENTITY_FLAG_UPDATE_HIDDEN);
	else
		GetEntity()->SetFlags(GetEntity()->GetFlags()&~ENTITY_FLAG_UPDATE_HIDDEN);

	GetEntity()->Hide(hide);
}

//------------------------------------------------------------------------
void CItem::HideArms(bool hide)
{
	HideCharacterAttachment(eIGS_FirstPerson, ITEM_ARMS_ATTACHMENT_NAME, hide);
}

//------------------------------------------------------------------------
void CItem::HideItem(bool hide)
{
	HideCharacterAttachmentMaster(eIGS_FirstPerson, ITEM_ARMS_ATTACHMENT_NAME, hide);

	IEntity *pOwner = GetOwner();
	if (!pOwner)
		return;

	ICharacterInstance *pOwnerCharacter = pOwner->GetCharacter(0);
	if (!pOwnerCharacter)
		return;

	IAttachmentManager *pAttachmentManager = pOwnerCharacter->GetIAttachmentManager();
	IAttachment *pAttachment = pAttachmentManager->GetInterfaceByName(m_params.attachment.c_str());
	if (pAttachment)
		pAttachment->HideAttachment(hide?1:0);
}

//------------------------------------------------------------------------
void CItem::Freeze(bool freeze)
{
	if (freeze)
	{
		m_frozen = true;
		for (int i=0; i<eIGS_Last; i++)
		{
			ICharacterInstance *pCharacter = GetEntity()->GetCharacter(i);
			if (pCharacter)
				pCharacter->SetAnimationSpeed(0);
		}

		Quiet();

		if (GetIWeapon())
			GetIWeapon()->StopFire(GetOwnerId());
	}
	else
	{
		m_frozen = false;
		for (int i=0; i<eIGS_Last; i++)
		{
			ICharacterInstance *pCharacter = GetEntity()->GetCharacter(i);
			if (pCharacter)
				pCharacter->SetAnimationSpeed(m_animationSpeed[i]);
		}
	}
}

//------------------------------------------------------------------------
// NETWORK
//------------------------------------------------------------------------
void CItem::InitClient(int channelId)
{
}

//------------------------------------------------------------------------
void CItem::PostInitClient(int channelId)
{
}

