// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010  Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.



/*
 *	Update character position notes
 *	-------------------------------
 *
 *	The update of the character position is done as followed :
 *
 *	For each character
 *		updatePreCollision
 *			updatePos
 *				PACS::move
 *
 *	The characters know where they want to be in 2d (pos().x and pos().y valid).
 *
 *	PACS::evalCollision
 *
 *	For each character
 *		updatePostCollision
 *			pacsFinalizepos
 *				PACS::getGlobalPosition
 *				If real position too far from PACS position
 *					PACS::setGlobalPosition
 *			-- Here pos().z is estimated
 *			snapToGround
 *				NL3D::visualCollisionEntities
 *				-- Here pos().z is good
 *			updateDisplay
 *			updateCluster
 *			updateHeadDirection
 *			-- Here the character is setuped in the engine
 *
 */

/////////////
// INCLUDE //
/////////////
#include "stdpch.h"
// Client.
#include "character_cl.h"
#include "pacs_client.h"
#include "net_manager.h"
#include "entity_animation_manager.h"
#include "time_client.h"
#include "ingame_database_manager.h"
#include "client_chat_manager.h"
#include "motion/user_controls.h"
#include "color_slot_manager.h"
#include "sheet_manager.h"
#include "debug_client.h"
#include "animation_misc.h"
#include "entities.h"						// \todo GUIGUI : try to remove this dependency.
#include "misc.h"
#include "string_manager_client.h"
#include "interface_v3/interface_manager.h"
#include "fx_manager.h"
#include "interface_v3/group_in_scene_user_info.h"
#include "interface_v3/group_in_scene_bubble.h"
#include "client_cfg.h"
#include "user_entity.h"
#include "projectile_manager.h"
#include "init_main_loop.h"
#include "nel/misc/cdb_branch.h"
#include "animation_fx_misc.h"
#include "attack_list.h"
#include "animation_fx_id_array.h"
#include "cursor_functions.h"
#include "interface_v3/bar_manager.h"
// sheets
#include "client_sheets/item_fx_sheet.h"
#include "client_sheets/attack_id_sheet.h"
// Misc
#include "nel/misc/geom_ext.h"
#include "nel/misc/random.h"
// 3D
#include "nel/3d/u_scene.h"
#include "nel/3d/u_camera.h"
#include "nel/3d/u_driver.h"
#include "nel/3d/u_play_list.h"
#include "nel/3d/u_particle_system_instance.h"
#include "nel/3d/u_bone.h"
#include "nel/3d/u_track.h"
#include "nel/3d/u_instance.h"
#include "nel/3d/u_instance_material.h"
// PACS
#include "nel/pacs/u_global_position.h"
// SOUND
#include "nel/sound/sound_anim_manager.h"
// Std.
#include <vector>
// Game share
#include "game_share/intensity_types.h"
#include "game_share/multi_target.h"
#include "game_share/visual_fx.h"
#include "game_share/range_weapon_type.h"
//

#ifdef DEBUG_NEW
#define new DEBUG_NEW
#endif

////////////
// DEFINE //
////////////
#define INVALID_POS		CVectorD(-1.0,-1.0,-1.0)
#define INVALID_DIST	-1.0
#define INVALID_TIME	-1.0
//#define MAX_HEAD_H_ROTATION		Pi/2.5
#define MAX_HEAD_H_ROTATION		Pi/3.0
#define MAX_HEAD_V_ROTATION		Pi/4.0
#define DEFAULT_BLEND_LENGTH	0


static const double AURA_SHUTDOWN_TIME = 1.f; // number of seconds for auras and links to shutdown

///////////
// USING //
///////////
using namespace NLMISC;
using namespace NL3D;
using namespace NLPACS;
using namespace NLSOUND;
using namespace std;
using namespace MBEHAV;
using namespace CLFECOMMON;

////////////
// EXTERN //
////////////
extern UScene					*Scene;
extern UDriver					*Driver;
extern CEntityAnimationManager	*EAM;
extern CClientChatManager		ChatMngr;
extern UTextContext				*TextContext;
extern UMaterial				GenericMat;
extern UCamera					MainCam;


///////////
// MACRO //
///////////
#if !FINAL_VERSION
	std::string LastMethod;

	#define ADD_METHOD(header) \
	header                     \
	{                          \
		LastMethod = #header;

	#define CHECK(param)                                                            \
	if((param)==false)                                                              \
	{                                                                               \
		nlwarning("entity:%d: Test '%s'", _Slot, #param);                           \
		nlwarning("entity:%d: Last Method called '%s'", _Slot, LastMethod.c_str()); \
		nlstop;                                                                     \
	}
	#define METHOD_NAME(param) LastMethod = (param);

#else
	#define ADD_METHOD(header) \
	header                     \
	{
	#define CHECK(param)
	#define METHOD_NAME(param)
#endif



////////////
// STATIC //
////////////
const std::string CCharacterCL::_EmptyString;
const uint8	 CCharacterCL::_BadHairIndex = 0xFF;

H_AUTO_DECL ( RZ_Client_Character_CL_Update_Pos_Combat_Float )
H_AUTO_DECL ( RZ_Client_Entity_CL_Update_Pos_Pacs )
H_AUTO_DECL ( RZ_Client_Entity_CL_Update_Pos_Combat_Float )
H_AUTO_DECL ( RZ_Client_Entity_CL_Update_Pos_Compute_Motion )

/////////////
// METHODS //
/////////////


//---------------------------------------------------
// dirEndAnim :
// Set the direction that should have the character at the end of the animation.
// \param vect : vector used to set the direction at the end of the animation.
//---------------------------------------------------
void CCharacterCL::dirEndAnim(const CVector &vect)
{
	setVect(_DirEndAnim, vect, true, true);
}// dirEndAnim //


//-----------------------------------------------
// CCharacterCL :
// Constructor.
//-----------------------------------------------
CCharacterCL::CCharacterCL()
: CEntityCL()
{
	Type				= NPC;

	_FirstPos			= INVALID_POS;	// Initialize the first with a bad position.
	_FirstTime			= INVALID_TIME;	// Initialize the time for the first position with a bad one.
	dist2FirstPos(INVALID_DIST);		// Initialize the distance to the first position with a bad value.
	_RunStartTimeNoPop	= INVALID_TIME;

	_DestPos			= INVALID_POS;
	_DestTime			= INVALID_TIME;
	dist2Dest(INVALID_DIST);

	_OldPos				= INVALID_POS;
	_OldPosTime			= INVALID_TIME;


	// Initialize the time for the last loop with the current time when entity created.
	_LastFrameTime = 0.0;
	// The animation should be played from the begin to the end.
	_AnimReversed.resize(animTypeCount, false);
	// Id among all the animations for each slot
	_AnimId.resize(animTypeCount, NL3D::UPlayList::empty);
	// Index in the state of the current animation for each slot.
	_AnimIndex.resize(animTypeCount, CAnimation::UnknownAnim);
	// ID of the current sound animation for each slot.
	_SoundId.resize(animTypeCount, -1);
	// ID of the current animation state for each slot.
	_AnimState.resize(animTypeCount, CAnimationStateSheet::Idle);
	// Time offest in the current animation for each slot.
	_AnimOffset.resize(animTypeCount, 0.0);
	// Subsidiary Key for the Animation State (emote).
	_SubStateKey = CAnimationStateSheet::UnknownState;
	// The character does not accept special "job animation" by default
	_AnimJobSpecialisation= 0;

	// Reset Lod.
	_LodCharacterAnimEnabled= false;
	_LodCharacterMasterAnimSlot= MOVE;

	// default POS scale to 1.
	_CharacterScalePos= 1.f;

	// No sheet pointed.
	_Sheet = 0;

	// Unknown gender at the entity creation.
	_Gender = GSGENDER::unknown;

	// The bone for the name is not known for the time
	_NameBoneId = -1;
	// No UTransform for the name needed if there is no name so not allocated for the time.
	_NameTransform = 0;
	// default Clod apparition => force compute the bone
	_NameCLodDeltaZ = NameCLodDeltaZNotComputed;

	// There is no anim set for the time.
	_CurrentAnimSet.resize(animTypeCount, 0);

	// Same as the animation at the beginning.
	_RotationFactor = 1.f;

	_CurrentState = 0;


	_RightFXActivated	= false;
	_LeftFXActivated	= false;


	dirEndAnim(CVector(0.f, 1.f, 0.f));

	// No item associated at the beginning but there is a room for them.
	_Items.resize(SLOTTYPE::NB_SLOT);
	_HeadIdx = CEntityCL::BadIndex;
	_FaceIdx = CEntityCL::BadIndex;

	// No frame remaining forthe blend at the beginning.
	_BlendRemaining = 0;

	// Scale for the skeleton according to the gabarit. Default : 1
	_CustomScalePos = 1.f;

	// Start with "unknown mode wanted by the server"
	_ModeWanted = MBEHAV::UNKNOWN_MODE; //MBEHAV::NORMAL;

	_Mount = CLFECOMMON::INVALID_SLOT;
	_Rider = CLFECOMMON::INVALID_SLOT;
	_TheoreticalMount = CLFECOMMON::INVALID_SLOT;
	_TheoreticalRider = CLFECOMMON::INVALID_SLOT;
	_OwnerPeople = MOUNT_PEOPLE::Unknown;

	// Default is : entity has no bone for the head and Neck.
	_HeadBoneId = -1;

	_IsThereAMode = false;
	_ImportantStepTime= 0.0;
	_StartDecreaseLCTImpact= 0;

	// Entity has no look and so is not displayable for the time.
	_LookRdy = false;

	// Index of the instance in the right hand (0xFFFFFFFF = no index).
	_RHandInstIdx = CEntityCL::BadIndex;
	// Index of the instance in the left hand (0xFFFFFFFF = no index).
	_LHandInstIdx = CEntityCL::BadIndex;

	_HairColor = 0;
	_EyesColor = 0;
	// No Hair Index at the beginning.
	_HairIndex = _BadHairIndex;
	_ClothesSheet = 0;

	_NbLoopAnim = 0;
	_MaxLoop = false;

	setAlive();

	_InSceneUserInterface = NULL;
	_CurrentBubble = NULL;

	// Initialize the head offset with a Null Vector.
	_HeadOffset = CVector::Null;
	_HeadOffsetComputed = false;
	// Initialize the Run Factor
	runFactor(0.0);
	// Initialize the Speed
	speed(0.0);



	_CurrentAttack = NULL;
	_CurrentAttackID.Type = CAttackIDSheet::Unknown;

	//_PelvisBoneId = -1;

	_ChestBoneId = -1;


	_HideSkin = false;


	_GuildNameId = 0;
	_GuildSymbol = 0;

	_EventFactionId = 0;
	_PvpMode = PVP_MODE::None;

	_LeagueId = 0;
	_OutpostId = 0;
	_OutpostSide = OUTPOSTENUMS::UnknownPVPSide;

	_SelectableBySpace = true;

	_LastSelectBoxComputeTime= 0;



	_CustomScale = 1.f;
}// CCharacterCL //

//-----------------------------------------------
// ~CCharacterCL:
// Default Destructor
// \warning : Do not remove sheets before the entity.
//-----------------------------------------------
CCharacterCL::~CCharacterCL()
{
	// Delete the UTransform used to compute the Bone for the Name.
	if(!_NameTransform.empty())
	{
		if(Scene)
		{
			if (!_Skeleton.empty())
				_Skeleton.detachSkeletonSon(_NameTransform);
			Scene->deleteTransform(_NameTransform);
		}
		_NameTransform = 0;
	}

	// No more sheet pointed.
	_Sheet = NULL;

	// Release items (but not their mesh, because they are managed by _Instances)
	for(uint k = 0; k < _Items.size(); ++k)
	{
		_Items[k].release();
	}

	// Delete previous interface
	releaseInSceneInterfaces();

	if (_CurrentBubble)
	{
		_CurrentBubble->unlink();
	}

}

//-----------------------------------------------
// computePrimitive :
// Create (or re-create) a primitive.
//-----------------------------------------------
void CCharacterCL::computePrimitive()
{
	// Initialize the primitive.
	if (_Sheet)
	{
		initPrimitive(_Sheet->ColRadius*getScale(), _Sheet->ColHeight*getScale(), _Sheet->ColLength, _Sheet->ColWidth, UMovePrimitive::DoNothing, UMovePrimitive::NotATrigger, MaskColNpc, MaskColNone, _Sheet->ClipRadius, _Sheet->ClipHeight);
	}
	else
	{
		initPrimitive(0.5f, 2.0f, 0.0f, 0.0f, UMovePrimitive::DoNothing, UMovePrimitive::NotATrigger, MaskColNpc, MaskColNone);
	}
	if(_Primitive)
		_Primitive->insertInWorldImage(dynamicWI);
	// Set the position.
	pacsPos(pos());
}// computePrimitive //


//-----------------------------------------------
void CCharacterCL::removeAllAttachedFX()
{
	_AttachedFXListForCurrentAnim.clear();
	_AttachedFXListToRemove.clear();
	_StaticFX = NULL;
	for(uint k = 0; k < MaxNumAura; ++k)
	{
		_AuraFX[k] = NULL;
	}
	_LinkFX = NULL;
}


//-----------------------------------------------

void CCharacterCL::releaseInSceneInterfaces()
{
	if (_InSceneUserInterface)
	{
		CWidgetManager::getInstance()->unMakeWindow(_InSceneUserInterface);
		if (_InSceneUserInterface->getParent())
		{
			_InSceneUserInterface->getParent()->delGroup(_InSceneUserInterface);
		}
		else
		{
			delete _InSceneUserInterface;
		}

		_InSceneUserInterface = NULL;
	}
}

//-----------------------------------------------
// stopAttachedFXForCurrrentAnim
// Stop all attached fxs linked  to current animation
//-----------------------------------------------
void CCharacterCL::stopAttachedFXForCurrrentAnim(bool stopLoopingFX)
{
	// shutdown fxs for current anim
	std::list<CAttachedFX::TSmartPtr>::iterator itAttachedFx = _AttachedFXListForCurrentAnim.begin();
	while(itAttachedFx != _AttachedFXListForCurrentAnim.end())
	{
		std::list<CAttachedFX::TSmartPtr>::iterator tmpItAttached = itAttachedFx;
		++itAttachedFx;
		if (!(!stopLoopingFX && (*tmpItAttached)->AniFX && (*tmpItAttached)->AniFX->Sheet->RepeatMode == CAnimationFXSheet::Loop)) // dont remove looping fx if it is requested
		{
			// test if emitters should be shutdown at the end of the anim
			if ((*tmpItAttached)->AniFX &&
				(*tmpItAttached)->AniFX->Sheet->RepeatMode != CAnimationFXSheet::Respawn &&
				(*tmpItAttached)->StickMode != CFXStickMode::SpawnPermanent
			   )
			{
				if(!(*tmpItAttached)->FX.empty())
				{
					if (!(*tmpItAttached)->FX.removeByID(NELID("STOP")) && !(*tmpItAttached)->FX.removeByID(NELID("main")))
					{
						(*tmpItAttached)->FX.activateEmitters(false);
					}
				}
			}
			_AttachedFXListToRemove.splice(_AttachedFXListToRemove.begin(), _AttachedFXListForCurrentAnim, tmpItAttached);
			_AttachedFXListToRemove.front()->TimeOutDate += TimeInSec; // compute absolute timeout date
		}
	}
	/** Removes fx that lives on more that a given count of animation
	  * Useful if framerate is low to avoid that fx overlap
	  */
	itAttachedFx = _AttachedFXListToRemove.begin();
	while(itAttachedFx != _AttachedFXListToRemove.end())
	{
		std::list<CAttachedFX::TSmartPtr>::iterator tmpItAttachedFX = itAttachedFx;
		++itAttachedFx;
		if ((*tmpItAttachedFX)->AniFX)
		{
			if ((*tmpItAttachedFX)->MaxAnimCount != 0) // if there a limit to the number of animation during which the fx can live ?
			{
				(*tmpItAttachedFX)->MaxAnimCount -= 1;
				if ((*tmpItAttachedFX)->MaxAnimCount == 0)
				{
					// remove the fx
					_AttachedFXListToRemove.erase(tmpItAttachedFX);
				}
			}
		}
	}
}


//-----------------------------------------------
// applyColorSlot :
//-----------------------------------------------
void CCharacterCL::applyColorSlot(SInstanceCL &instance, sint skin, sint userColor, sint hair, sint eyes)
{
	CColorSlotManager::TIntCouple array[4];

	// Skin
	array[0].first = (uint)0; array[0].second = (uint)skin;

	// User Color
	array[1].first = (uint)1; array[1].second = (uint)userColor;

	// Hair Color
	array[2].first = (uint)2; array[2].second = (uint)hair;

	// Eyes Color
	array[3].first = (uint)3; array[3].second = (uint)eyes;

	// Set Values.
	UInstance inst = instance.createLoadingFromCurrent();
	if (!inst.empty())
	{
		instance.setColors(skin, userColor, hair, eyes);
		ColorSlotManager.setInstanceSlot(inst, array, 4);
	}
}// applyColorSlot //


//-----------------------------------------------
// changeColors :
//-----------------------------------------------
void CCharacterCL::changeColors(sint userColor, sint hair, sint eyes, sint part)	// virtual
{
	// Color Just a part of the entity.
	if(part >= 0)
	{
		if((uint)part < _Instances.size())
			applyColorSlot(_Instances[part], skin(), userColor, hair, eyes);
	}
	// Color the whole entity.
	else
	{
		for(uint i=0; i<_Instances.size(); i++)
			applyColorSlot(_Instances[i], skin(), userColor, hair, eyes);
	}
}// changeColors //

//-----------------------------------------------
// addColoredInstance :
//-----------------------------------------------
uint32 CCharacterCL::addColoredInstance(const std::string &shapeName, const std::string &stickPoint, sint texture, uint32 instIdx, sint color)
{
	// Get the instance
	uint32 idx = addInstance(shapeName, stickPoint, texture, instIdx);
	SInstanceCL *instance = idx2Inst(idx);
	if(instance)
		applyColorSlot(*instance, skin(), color, _HairColor, _EyesColor);
	else
		nlwarning("CH::addColoredInstance: cannot create the instance for the shape '%s'.", shapeName.c_str());

	return idx;
}// addColoredInstance //


//-----------------------------------------------
// buildEquipment :
// \param slot: structure of the equipement.
// \param visualSlot: visual slot used by this item.
// \return uint32 : index of the instance or 0xFFFFFFFF.
// \todo GUIGUI : find a better choice to avoid all visualSlot checks
//-----------------------------------------------
uint32 CCharacterCL::buildEquipment(const CCharacterSheet::CEquipment &slot, SLOTTYPE::EVisualSlot visualSlot, sint color, uint32 instIdx)
{
	uint32 idx = CEntityCL::BadIndex;

	// Do something only if the slot is not empty.
	if(slot.getItem().empty())
		return idx;

	sint slotColor = slot.Color;

	// This is a reference on an item (the file is store with an UPPER case so check in UPPER CASE).
	string ext = CFile::getExtension(slot.getItem());
	if((ext == "item") || (ext == "sitem"))
	{
		// IS the item a valid one ?
		CSheetId itemId;
		if(itemId.buildSheetId(NLMISC::toLower(slot.getItem())))
		{
			// Is it stored in the database ?
			CEntitySheet *entitySheet = SheetMngr.get(itemId);
			if(entitySheet)
			{
				_Items[visualSlot].Sheet = dynamic_cast<CItemSheet *>(entitySheet);
				if(_Items[visualSlot].Sheet)
				{
					const CItemSheet &itemSheet = *(_Items[visualSlot].Sheet);

					// Compute the bind point
					string bindBone;
					switch(visualSlot)
					{
						// Right Hand
					case SLOTTYPE::RIGHT_HAND_SLOT:
						if( itemSheet.ItemType != ITEM_TYPE::MAGICIAN_STAFF )
							bindBone = "box_arme";
						break;
						// Left Hand
					case SLOTTYPE::LEFT_HAND_SLOT:
						// Shields are not stick to the same point.
						if(itemSheet.getAnimSet() == "s")
							bindBone = "Box_bouclier";
						else
							bindBone = "box_arme_gauche";
						break;
					default:
						bindBone = slot.getBindPoint();
						break;
					}

					// Choose the right colour.
					if(color==-1)
					{
						// Color in the item
						if(slotColor < 0)
						{
							// Get the item color
							slotColor = itemSheet.Color;
							// Bad item color -> set to 0
							if(slotColor < 0)
								slotColor = 0;
						}
					}
					else
						slotColor = color;

					idx = createItemInstance(itemSheet, instIdx, visualSlot, bindBone, slot.Texture, slotColor);
				}
				else
					nlwarning("CH::buildEquipment: the sheet '%s' is not an item one.", slot.getItem().c_str());
			}
			else
				nlwarning("CH::buildEquipment: the sheet '%s' is not stored in the database.", slot.getItem().c_str());
		}
		else
			nlwarning("CH::buildEquipment: item '%s' is not in the Sheet Id list.", slot.getItem().c_str());
	}
	// This is a shape.
	else
	{
		if(color==-1)
		{
			if(slotColor < 0)
				slotColor = 0;
		}
		else
			slotColor = color;

		// Get the instance
		idx = addColoredInstance(slot.getItem(), slot.getBindPoint(), slot.Texture, instIdx, slotColor);
	}

	// Return the index.
	return idx;
}// buildEquipment //

//-----------------------------------------------
// computeSomeBoneId :
// Compute the bone for the name, head...
// \warning This method do not check the bone is valid, nor there is a Scene.
//-----------------------------------------------
void CCharacterCL::computeSomeBoneId()
{
	// **** Get the Bone for the name.
	_NameBoneId = _Skeleton.getBoneIdByName("name");
	// Dummy found -> return the name position.
	if(_NameBoneId != -1)
	{
		// Just to force the bone to be compute (else not computed if not used).
		_NameTransform = Scene->createTransform();
		if(!_NameTransform.empty())
			_Skeleton.stickObject(_NameTransform, _NameBoneId);
	}
	// No Bone for the Name.
	else
	{
#if !FINAL_VERSION
		pushDebugStr("The Bone for the name is missing.");
#endif // FINAL_VERSION
	}

	// **** Get the head bone.
	_HeadBoneId = _Skeleton.getBoneIdByName("Bip01 Head");
	// Bone found
	if(_HeadBoneId == -1)
	{
#if !FINAL_VERSION
		pushDebugStr("The Bone for the Head is missing.");
#endif // FINAL_VERSION
	}
	else
	{
		_TargetAnimCtrl.EyePos = CVector::Null;
		_Skeleton.setBoneAnimCtrl(_HeadBoneId, &_TargetAnimCtrl);
	}

	// **** Get the "chest" bone. take spine1.
	_ChestBoneId = _Skeleton.getBoneIdByName("Bip01 Spine1");
	if(_ChestBoneId == -1)
	{
#if !FINAL_VERSION
		pushDebugStr("The Bone for the Chest 'Bip01 Spine1' is missing.");
#endif // FINAL_VERSION
	}
}// computeSomeBoneId //


//-----------------------------------------------
// createPlayList :
// Create the play list for this entity.
//-----------------------------------------------
void CCharacterCL::createPlayList()
{
	// Release the old animation playlist.
	if(_PlayList)
	{
		EAM->deletePlayList(_PlayList);
		_PlayList = 0;
	}

	// Create the new animation playlist.
	_PlayList = EAM->createPlayList();
	if(!_PlayList)
	{
		pushDebugStr("Cannot create a playlist for the entity.");
		return;
	}

	// Initialize the new playlist.
	// MOVE Channel
	_PlayList->setSpeedFactor	(MOVE, 1.f);
	_PlayList->setWrapMode		(MOVE, UPlayList::Clamp);
	// ACTION Channel
	_PlayList->setSpeedFactor	(ACTION, 1.f);
	_PlayList->setWrapMode		(ACTION, UPlayList::Clamp);
}// createPlayList //



//-----------------------------------------------
// getGroundFX :
// retrieve ground fxs for that entity
//-----------------------------------------------
const std::vector<CGroundFXSheet> *CCharacterCL::getGroundFX() const
{
	return &(_Sheet->GroundFX);
}

//-----------------------------------------------
// build :
// Build the entity from a sheet.
//-----------------------------------------------
bool CCharacterCL::build(const CEntitySheet *sheet)	// virtual
{
	// Cast the sheet in the right type.
	_Sheet = dynamic_cast<const CCharacterSheet *>(sheet);
	if(!_Sheet)
	{
		pushDebugStr("This is not a character sheet -> entity not initialized.");
		return false;
	}

	// Type
	Type = (_Sheet->Race >= EGSPD::CPeople::Creature) ? Fauna : NPC;

	// Names
	if (Type == Fauna)
	{
		// Get the fauna name in the sheet
		const ucstring creatureName(STRING_MANAGER::CStringManagerClient::getCreatureLocalizedName(_Sheet->Id));
		if (creatureName.find(ucstring("<NotExist:")) != 0)
			_EntityName = creatureName;
	}
	else
	{
		// Name and title will be send by the server
	}

	// Get the DB Entry
	if(IngameDbMngr.getNodePtr())
	{
		CCDBNodeBranch *nodeRoot = dynamic_cast<CCDBNodeBranch *>(IngameDbMngr.getNodePtr()->getNode(0));
		if(nodeRoot)
		{
			_DBEntry = dynamic_cast<CCDBNodeBranch *>(nodeRoot->getNode(_Slot));
			if(_DBEntry == 0)
				pushDebugStr("Cannot get a pointer on the DB entry.");
		}
	}

	if (!ClientCfg.Light && !_Sheet->getSkelFilename().empty())
	{
		// Create the Playlist for the entity.
		createPlayList();
	}
	// Compute the first automaton.
	_CurrentAutomaton = automatonType() + "_normal.automaton";

	// Get the Character gender.
	_Gender = (GSGENDER::EGender)_Sheet->Gender;

	// Initialize the internal time.
	_LastFrameTime = ((double)T1) * 0.001;

	// Set the skeleton.
	if(!ClientCfg.Light && !_Sheet->getSkelFilename().empty() && skeleton(_Sheet->getSkelFilename()))
	{
		// Set the skeleton scale.
		skeleton()->setScale(getScale(), getScale(), getScale());

		// Can create all characters except NPC.
		if(isNPC()== false)
		{
			// Eyes Color
			if(_Sheet->EyesColor >= SheetMngr.nbEyesColor())
			{
				if (SheetMngr.nbEyesColor() == 0)
					_EyesColor = 0;
				else
					_EyesColor = rand()%SheetMngr.nbEyesColor();
			}
			else
			{
				_EyesColor = _Sheet->EyesColor;
			}

			// Hair Color
			if(_Sheet->HairColor >= SheetMngr.nbHairColor())
			{
				if (SheetMngr.nbHairColor() == 0)
					_HairColor = 0;
				else
					_HairColor = rand()%SheetMngr.nbHairColor();
			}
			else
			{
				_HairColor = _Sheet->HairColor;
			}

			// -- Dress the character --


			// Top Items
			buildEquipment(_Sheet->Body,	SLOTTYPE::CHEST_SLOT);
			buildEquipment(_Sheet->Arms,	SLOTTYPE::ARMS_SLOT);
			buildEquipment(_Sheet->Hands,	SLOTTYPE::HANDS_SLOT);
			// Bottom Items
			buildEquipment(_Sheet->Legs,	SLOTTYPE::LEGS_SLOT);
			buildEquipment(_Sheet->Feet,	SLOTTYPE::FEET_SLOT);
			// Face
			_FaceIdx = buildEquipment(_Sheet->Face,	SLOTTYPE::FACE_SLOT);

			// -- Manage the Head --
			// Display the helm.
			if(!_Sheet->Head.getItem().empty())
			{
				// Create the Helm.
				_HeadIdx = buildEquipment(_Sheet->Head, SLOTTYPE::HEAD_SLOT, -1, _HeadIdx);
				// Hide the face
				SInstanceCL *pInstFace = getFace();
				if(pInstFace)
				{
					if(!pInstFace->Current.empty())
						pInstFace->Current.hide();
					else
						pInstFace->KeepHiddenWhenLoaded = true;
				}
			}
			// Display the Hair.
			else
			{
				// Create the Hair.
				if(_HairIndex != _BadHairIndex)
					_HeadIdx = buildEquipment(_Sheet->HairItemList[_HairIndex], SLOTTYPE::HEAD_SLOT, -1, _HeadIdx);
				// Display the face.
				SInstanceCL *pInstFace = getFace();
				if(pInstFace)
					if(!pInstFace->Current.empty())
						pInstFace->Current.show();
			}

			// Objects in Hands
			_RHandInstIdx = buildEquipment(_Sheet->ObjectInRightHand, SLOTTYPE::RIGHT_HAND_SLOT, -1, _RHandInstIdx);	// In The Right Hand
			_LHandInstIdx = buildEquipment(_Sheet->ObjectInLeftHand,  SLOTTYPE::LEFT_HAND_SLOT,  -1, _LHandInstIdx);	// In The Left Hand

			// Look is now ready.
			_LookRdy = true;
		}
		// Cannot build as long as the alternative look property not received, so hide the entity.
		else
			skeleton()->hide();

		// Compute the animation set (after weapons are set to choose the right animation set).
		computeAnimSet();
		// Check the animation set is correct.
		if(_CurrentAnimSet[MOVE] == 0)
			pushDebugStr("Bad animation set");

		// Set the animation to idle.
		setAnim(CAnimationStateSheet::Idle);

		// Compute the bone for the name.
		computeSomeBoneId();

		// Compute pelvis bone
		//_PelvisBoneId = _Skeleton.getBoneIdByName("Bip01 Pelvis");

		// Setup Lod Character skeleton and shapes colors, if skeleton exist
		// Get Lod Character Id from the sheet.
		sint clodId = getLodCharacterId(*Scene, _Sheet->getLodCharacterName());
		if(clodId >= 0)
		{
			// Setup Lod Character shapes, if enabled.
			skeleton()->setLodCharacterShape(clodId);
			skeleton()->setLodCharacterDistance(_Sheet->LodCharacterDistance);
		}
	}
	// Instances
	else
	{
		uint32	idx= buildEquipment(_Sheet->Body,	SLOTTYPE::CHEST_SLOT);
		// must set the scale for the BotObject too
		if(idx<_Instances.size())
		{
			float	s= getScale();
			_Instances[idx].setScale(CVector(s,s,s));
		}
	}

	// Setup _CharacterScalePos
	_CharacterScalePos = _Sheet->CharacterScalePos;

	// Adjust the custom scale position according to the entity scale.
	_CustomScalePos *= getScale();

	// Create PACS Primitive.
	initPrimitive(_Sheet->ColRadius*getScale(), _Sheet->ColHeight*getScale(), _Sheet->ColLength, _Sheet->ColWidth, UMovePrimitive::DoNothing, UMovePrimitive::NotATrigger, MaskColNpc, MaskColNone, _Sheet->ClipRadius, _Sheet->ClipHeight);

	// Compute the element to be able to snap the entity to the ground.
	computeCollisionEntity();

	// Initialize properties of the entity (selectable/attackable/etc.).
	initProperties();

	// copy some properties (special bot objects). before buildInSceneInterface
	_DisplayInRadar= _Sheet->DisplayInRadar;
	_DisplayOSDName= _Sheet->DisplayOSDName;
	_DisplayOSDBars= _Sheet->DisplayOSDBars;
	_DisplayOSDForceOver= _Sheet->DisplayOSDForceOver;
	_Traversable= _Sheet->Traversable;
	_CanTurn = _Sheet->Turn;

	_SelectableBySpace = _Sheet->SelectableBySpace;

	// Rebuild interface
	buildInSceneInterface ();


	initStaticFX();



	// Entity created.
	return true;
}// build //

//-----------------------------------------------
// isKami()
//-----------------------------------------------
bool CCharacterCL::isKami() const
{
	if (!_Sheet)
		return false;
	return (_Sheet->Race == EGSPD::CPeople::Kami);
}

//-----------------------------------------------
// isUnknownRace()
//-----------------------------------------------
bool CCharacterCL::isUnknownRace() const
{
	if (!_Sheet)
		return false;
	return (_Sheet->Race == EGSPD::CPeople::Unknown);
}

//-----------------------------------------------
// getAttackHeight :
// Return the atk height.
// \todo GUIGUI : height relative to attacker instead of global height
//-----------------------------------------------
CCharacterCL::TAtkHeight CCharacterCL::getAttackHeight(CEntityCL *target, BODY::TBodyPart localisation, BODY::TSide side) const
{
	// Check there is a target.
	if(target == 0)
		return CCharacterCL::AtkMiddle;
	// Get the position for a bone.
	float height;
	if(target->getBoneHeight(localisation, side, height))
	{
		// Low
		if(height < 1.0f)
			return CCharacterCL::AtkLow;
		// High
		else if(height > 2.0f)
			return CCharacterCL::AtkHigh;
	}
	// Default is Middle atk.
	return CCharacterCL::AtkMiddle;
}// getAttackHeight //

//-----------------------------------------------
// getBoneHeight :
//-----------------------------------------------
bool CCharacterCL::getBoneHeight(BODY::TBodyPart localisation, BODY::TSide side, float &height) const	// virtual
{
	// If there is no skeleton return false
	if(_Skeleton.empty())
		return false;
	// Get the Bone Name
	const char *boneName = getBoneNameFromBodyPart(localisation, side);
	if(boneName == 0)
		return false;
	// Get the Bone Id
	sint boneId = _Skeleton.getBoneIdByName(std::string(boneName));
	if (boneId == -1)
		return false;
	if(_Skeleton.isBoneComputed(boneId) == false)
		return false;
	NL3D::UBone bone = _Skeleton.getBone(boneId);
	CMatrix BoneMat = bone.getLastWorldMatrixComputed();
	height = (float)(BoneMat.getPos().z-pos().z);
	if(height < 0.0f)
		height = 0.0f;
	else if(height > 10.0f)
		height = 10.0f;
	return true;
}// getBoneHeight //


//-----------------------------------------------
// lookAtItemsInHands :
// Look at items in hands to change the animation set.
// \return true if the mode is a mode where items in hands should be hidden
//-----------------------------------------------
bool CCharacterCL::modeWithHiddenItems() const
{
	return ((ClientCfg.PutBackItems && !isFighting()) || isSit() || _Mode==MBEHAV::SWIM || isRiding() || _Mode==MBEHAV::SWIM_DEATH || _Mode==MBEHAV::REST);
}// lookAtItemsInHands //


//-----------------------------------------------
// automatonType :
//-----------------------------------------------
string CCharacterCL::automatonType() const	// virtual
{
	return _Sheet->getAutomaton();
}// automatonType //

//-----------------------------------------------
// computeAutomaton :
// Compute the current automaton for the entity.
//-----------------------------------------------
void CCharacterCL::computeAutomaton()
{
	_CurrentAutomaton = automatonType() + "_" + NLMISC::toLower(MBEHAV::modeToString(_Mode)) + ".automaton";
}// computeAutomaton //


//-----------------------------------------------
// computeAnimSet :
// Compute the animation set to use according to weapons, mode and race.
//-----------------------------------------------
void CCharacterCL::computeAnimSet()
{
	if(ClientCfg.Light)
		return;
	// Use the generic method to compute the animation set.
	if(!::computeAnimSet(_CurrentAnimSet[MOVE], _Mode, _Sheet->getAnimSetBaseName(), _Items[SLOTTYPE::LEFT_HAND_SLOT].Sheet, _Items[SLOTTYPE::RIGHT_HAND_SLOT].Sheet, !modeWithHiddenItems()))
	{
		//nlwarning("CH:computeAnimSet:%d: pb when trying to compute the animset. Sheet Id '%u(%s)'.", _Slot, _SheetId.asInt(), _SheetId.toString().c_str());
	}

}// computeAnimSet //

//-----------------------------------------------
// adjustPI :
// Adjust the Predicted Interval to fix some errors according to the distance.
//-----------------------------------------------
NLMISC::TGameCycle CCharacterCL::adjustPI(float x , float y, float /* z */, const NLMISC::TGameCycle &pI)
{
	NLMISC::TGameCycle adjustedPI = pI;
	if(ClientCfg.RestrainPI && adjustedPI > 0)
	{
		double dist = (x-UserEntity->pos().x)*(x-UserEntity->pos().x) + (y-UserEntity->pos().y)*(y-UserEntity->pos().y);
		// If under 50m check Predicted Interval
		if(dist < 50*50)
		{
			NLMISC::TGameCycle maxPi = (NLMISC::TGameCycle)(sqrt(dist)/5.0)+1;
			if(adjustedPI > maxPi)
			{
				adjustedPI = maxPi;
				if(VerboseAnimSelection && _Slot == UserEntity->selection())
					nlinfo("CH:updtVPPos:%d: dist'%f' PI'%d' newPI'%d'.", _Slot, sqrt(dist), pI, adjustedPI);
			}
		}
	}
	return adjustedPI;
}// adjustPI //

//-----------------------------------------------
// updateVisualPropertyPos :
// Received a new position for the entity.
// \warning Do not send position for the user
//-----------------------------------------------
void CCharacterCL::updateVisualPropertyPos(const NLMISC::TGameCycle &gameCycle, const sint64 &prop, const NLMISC::TGameCycle &pI)
{
	// Check the DB entry (the warning is already done in the build method).
	if(_DBEntry == 0)
		return;
	// Get The property 'Y'.
	CCDBNodeLeaf *nodeY	= dynamic_cast<CCDBNodeLeaf *>(_DBEntry->getNode(CLFECOMMON::PROPERTY_POSY));
	if(nodeY == 0)
	{
		nlwarning("CH::updtVPPos:%d: Cannot find the property 'PROPERTY_POSY(%d)'.", _Slot, CLFECOMMON::PROPERTY_POSY);
		return;
	}
	// Get The property 'Z'.
	CCDBNodeLeaf *nodeZ	= dynamic_cast<CCDBNodeLeaf *>(_DBEntry->getNode(CLFECOMMON::PROPERTY_POSZ));
	if(nodeZ == 0)
	{
		nlwarning("CH::updtVPPos:%d: Cannot find the property 'PROPERTY_POSZ(%d)'.", _Slot, CLFECOMMON::PROPERTY_POSZ);
		return;
	}

	// Convert Database into a Position
	float x = (float)(prop)/1000.0f;
	float y = (float)(nodeY->getValue64())/1000.0f;
	float z = (float)(nodeZ->getValue64())/1000.0f;

#ifdef TMP_DEBUG_GUIGUI
	// Theoretical Position
	_TheoreticalPosition = CVectorD((double)x, (double)y, (double)z);
#endif // TMP_DEBUG_GUIGUI

	// First position Managed -> set the PACS Position
	if(_FirstPosManaged)
	{
		pacsPos(CVectorD(x, y, z));
		_FirstPosManaged = false;
		return;
	}

	// Wait for the entity to be spawned
	if(_First_Pos)
		return;

	// Stock the position (except if this is the user mount because it's the user that control him not the server)
	if( !isRiding() || _Rider != 0)
	{
		// Adjust the Predicted Interval to fix some "bug" into the Prediction Algo.
		NLMISC::TGameCycle adjustedPI = adjustPI(x, y, z, pI);
		// Add Stage.
		_Stages.addStage(gameCycle, PROPERTY_POSX, prop, adjustedPI);
		_Stages.addStage(gameCycle, PROPERTY_POSY, nodeY->getValue64());
		_Stages.addStage(gameCycle, PROPERTY_POSZ, nodeZ->getValue64());
	}
}// updateVisualPropertyPos //

//-----------------------------------------------
// updateVisualPropertyOrient :
// Received a new orientation.
//-----------------------------------------------
void CCharacterCL::updateVisualPropertyOrient(const NLMISC::TGameCycle &gameCycle, const sint64 &prop)
{
#ifdef TMP_DEBUG_GUIGUI
	// Backup the last orientation received.
	_TheoreticalOrientation = *(float *)(&prop);
#endif	// TMP_DEBUG_GUIGUI

	// New Mode Received.
	if(verboseVP(this))
	{
		float ori = *(float *)(&prop);
		nlinfo("(%05d,%03d) CH::updateVPOri:%d: '%f' received.", sint32(T1%100000), NetMngr.getCurrentServerTick(), _Slot, ori);
	}

	// if no skeleton we set the orientation
	if(_Skeleton.empty())
	{
		// server forces the entity orientation even if it cannot turn
		front(CVector((float)cos(_TheoreticalOrientation), (float)sin(_TheoreticalOrientation), 0.f), true, true, true);
		dir(front(), false, false);
		if(_Primitive)
			_Primitive->setOrientation(_TheoreticalOrientation, dynamicWI);
	}
	else
	{
		if( !isRiding() || _Rider != 0 )
		{
			// Add in right stage.
			_Stages.addStage(gameCycle, PROPERTY_ORIENTATION, prop);
		}
	}
}// updateVisualPropertyOrient //

//-----------------------------------------------
// updateVisualPropertyMode :
// New mode received.
// \warning For the first mode, we must have received the position and orientation (but this should be the case).
// \warning Read the position or orientation from the database when reading the mode (no more updated in updateVisualPropertyPos and updateVisualPropertyOrient).
//-----------------------------------------------
void CCharacterCL::updateVisualPropertyMode(const NLMISC::TGameCycle &gameCycle, const sint64 &prop)
{
	if(verboseVP(this))
		nlinfo("(%05d,%03d) CH:updtVPMode:%d: '%s(%d)' received.", sint32(T1%100000), NetMngr.getCurrentServerTick(), _Slot, modeToString((MBEHAV::EMode)prop).c_str(), (MBEHAV::EMode)prop);
	// New Mode Received : Set the Theoretical Current Mode if different.
	if(_TheoreticalMode != (MBEHAV::EMode)(prop & 0xffff))
		_TheoreticalMode = (MBEHAV::EMode)(prop & 0xffff);
	else
	{
		nlwarning("CH:updtVPMode:%d: The mode '%s(%d)' sent is the same as the current one.", _Slot, modeToString(_TheoreticalMode).c_str(), _TheoreticalMode);
		return;
	}
	// If it is the first mode, set the mode.
	if(_Mode == MBEHAV::UNKNOWN_MODE)
	{
		// SET THE FIRST POSITION
		//-----------------------
		// Check the DB entry (the warning is already done in the build method).
		if(_DBEntry == 0)
			return;
		// Get The property 'PROPERTY_POSX'.
		CCDBNodeLeaf *nodeX	= dynamic_cast<CCDBNodeLeaf *>(_DBEntry->getNode(CLFECOMMON::PROPERTY_POSX));
		if(nodeX == 0)
		{
			nlwarning("CH::updtVPMode:%d: Cannot find the property 'PROPERTY_POSX(%d)'.", _Slot, CLFECOMMON::PROPERTY_POSX);
			return;
		}
		// Get The property 'PROPERTY_POSY'.
		CCDBNodeLeaf *nodeY	= dynamic_cast<CCDBNodeLeaf *>(_DBEntry->getNode(CLFECOMMON::PROPERTY_POSY));
		if(nodeY == 0)
		{
			nlwarning("CH::updtVPMode:%d: Cannot find the property 'PROPERTY_POSY(%d)'.", _Slot, CLFECOMMON::PROPERTY_POSY);
			return;
		}
		// Get The property 'PROPERTY_POSZ'.
		CCDBNodeLeaf *nodeZ	= dynamic_cast<CCDBNodeLeaf *>(_DBEntry->getNode(CLFECOMMON::PROPERTY_POSZ));
		if(nodeZ == 0)
		{
			nlwarning("CH::updtVPMode:%d: Cannot find the property 'PROPERTY_POSZ(%d)'.", _Slot, CLFECOMMON::PROPERTY_POSZ);
			return;
		}
		// Next position will no longer be the first one.
		_First_Pos = false;
		// Insert the primitive into the world.
		if(_Primitive)
			_Primitive->insertInWorldImage(dynamicWI);
		// float makes a few cm error
		double x = (double)(nodeX->getValue64())/1000.0;
		double y = (double)(nodeY->getValue64())/1000.0;
		double z = (double)(nodeZ->getValue64())/1000.0;
		// Set the primitive position.
		pacsPos(CVectorD(x, y, z));
		// SET THE FIRST ORIENTATION
		//--------------------------
		// Get The property 'PROPERTY_ORIENTATION'.
		CCDBNodeLeaf *nodeOri = dynamic_cast<CCDBNodeLeaf *>(_DBEntry->getNode(CLFECOMMON::PROPERTY_ORIENTATION));
		if(nodeOri == 0)
		{
			nlwarning("CH::updtVPMode:%d: Cannot find the property 'PROPERTY_ORIENTATION(%d)'.", _Slot, CLFECOMMON::PROPERTY_ORIENTATION);
			return;
		}
		C64BitsParts parts;
		parts.i64[0] = nodeOri->getValue64();
		float angleZ = parts.f[0];
		// server forces the entity orientation even if it cannot turn
		front(CVector((float)cos(angleZ), (float)sin(angleZ), 0.f), true, true, true);
		dir(front(), false, false);
		_TargetAngle = angleZ;
		if(_Primitive)
			_Primitive->setOrientation(angleZ, dynamicWI);
		// SET THE FIRST MODE
		//-------------------
		// Set the mode Now
		_Mode       = _TheoreticalMode;
		_ModeWanted = _TheoreticalMode;
		if((_Mode == MBEHAV::MOUNT_NORMAL) && (_Rider == CLFECOMMON::INVALID_SLOT))
		{
			_Mode = MBEHAV::NORMAL;
			_ModeWanted = MBEHAV::MOUNT_NORMAL;
			// See also updateVisualPropertyRiderEntity() for the case when _Rider is received after the mode
			computeAutomaton();
			computeAnimSet();
			setAnim(CAnimationStateSheet::Idle);
			// Add the mode to the stage.
			_Stages.addStage(gameCycle, PROPERTY_MODE, prop);
		}
		computeAutomaton();
		computeAnimSet();
		setAnim(CAnimationStateSheet::Idle);
	}
	// Not the first mode -> Add to a stage.
	else
	{
		// Add the mode to the stage.
		_Stages.addStage(gameCycle, PROPERTY_MODE, prop);
		// Float mode push the orientation
		if(_TheoreticalMode == MBEHAV::COMBAT_FLOAT)
		{
			// Get The property 'PROPERTY_ORIENTATION'.
			CCDBNodeLeaf *nodeOri = dynamic_cast<CCDBNodeLeaf *>(_DBEntry->getNode(CLFECOMMON::PROPERTY_ORIENTATION));
			if(nodeOri == 0)
			{
				nlwarning("CH::updtVPMode:%d: Cannot find the property 'PROPERTY_ORIENTATION(%d)'.", _Slot, CLFECOMMON::PROPERTY_ORIENTATION);
				return;
			}
			_Stages.addStage(gameCycle, CLFECOMMON::PROPERTY_ORIENTATION, nodeOri->getValue64());
		}
		// Any other mode push the position
		else
		{
			if(_TheoreticalMode != MBEHAV::MOUNT_NORMAL)
			{
				// Check the DB entry (the warning is already done in the build method).
				if(_DBEntry == 0)
					return;
				// Get The property 'PROPERTY_POSX'.
				CCDBNodeLeaf *nodeX	= dynamic_cast<CCDBNodeLeaf *>(_DBEntry->getNode(CLFECOMMON::PROPERTY_POSX));
				if(nodeX == 0)
				{
					nlwarning("CH::updtVPMode:%d: Cannot find the property 'PROPERTY_POSX(%d)'.", _Slot, CLFECOMMON::PROPERTY_POSX);
					return;
				}
				// Get The property 'PROPERTY_POSY'.
				CCDBNodeLeaf *nodeY	= dynamic_cast<CCDBNodeLeaf *>(_DBEntry->getNode(CLFECOMMON::PROPERTY_POSY));
				if(nodeY == 0)
				{
					nlwarning("CH::updtVPMode:%d: Cannot find the property 'PROPERTY_POSY(%d)'.", _Slot, CLFECOMMON::PROPERTY_POSY);
					return;
				}
				// Get The property 'PROPERTY_POSZ'.
				CCDBNodeLeaf *nodeZ	= dynamic_cast<CCDBNodeLeaf *>(_DBEntry->getNode(CLFECOMMON::PROPERTY_POSZ));
				if(nodeZ == 0)
				{
					nlwarning("CH::updtVPMode:%d: Cannot find the property 'PROPERTY_POSZ(%d)'.", _Slot, CLFECOMMON::PROPERTY_POSZ);
					return;
				}
				// Add Stage.
				_Stages.addStage(gameCycle, CLFECOMMON::PROPERTY_POSX, nodeX->getValue64());
				_Stages.addStage(gameCycle, CLFECOMMON::PROPERTY_POSY, nodeY->getValue64());
				_Stages.addStage(gameCycle, CLFECOMMON::PROPERTY_POSZ, nodeZ->getValue64());
			}
		}
	}
}// updateVisualPropertyMode //

//-----------------------------------------------
// updateVisualPropertyBehaviour :
// New Behaviour received.
//-----------------------------------------------
void CCharacterCL::updateVisualPropertyBehaviour(const NLMISC::TGameCycle &gameCycle, const sint64 &prop)
{
	// New Behaviour Received.
	CBehaviour beh(prop);
	if(verboseVP(this))
		nlinfo("(%05d,%03d) CH::updateVPBeha:%d: '%s(%d)' received.", sint32(T1%100000), NetMngr.getCurrentServerTick(), _Slot, behaviourToString((EBehaviour)beh.Behaviour).c_str(), (sint)beh.Behaviour);

	// Add in right stage.
	_Stages.addStage(gameCycle, PROPERTY_BEHAVIOUR, prop);
}// updateVisualPropertyBehaviour //

void CCharacterCL::updateVisualPropertyTargetList(const NLMISC::TGameCycle &gameCycle, const sint64 &prop, uint listIndex)
{
	// Add in right stage.
	_Stages.addStage(gameCycle, PROPERTY_TARGET_LIST_0 + listIndex, prop);
}

void CCharacterCL::updateVisualPropertyVisualFX(const NLMISC::TGameCycle &gameCycle, const sint64 &prop)
{
	_Stages.addStage(gameCycle, PROPERTY_VISUAL_FX, prop);
}
//-----------------------------------------------
// updateVisualPropertyName :
// Received the name Id.
//-----------------------------------------------
void CCharacterCL::updateVisualPropertyName(const NLMISC::TGameCycle &/* gameCycle */, const sint64 &prop)
{
	// Update the entity name (do not need to be managed with LCT).
	uint32 nameId = *(uint32 *)(&prop);

	// Store the name Id
	_NameId = nameId;

//	STRING_MANAGER::CStringManagerClient::instance()->waitString(nameId, this, &_Name);
	STRING_MANAGER::CStringManagerClient::instance()->waitString(nameId, this);

	//if(!getEntityName().empty())
	//	nlwarning("CH::updateVPName:%d: name Id '%d' received but no name allocated.", _Slot, nameId);
	//else if(verboseVP(this))
	//	nlinfo("(%05d,%03d) CH::updateVPName:%d: name '%s(%d)' received.", sint32(T1%100000), NetMngr.getCurrentServerTick(), _Slot, getEntityName().toString().c_str(), nameId);

	updateMissionTarget();
}// updateVisualPropertyName //

//-----------------------------------------------
// updateVisualPropertyTarget :
// Received the new target for the entity
// \todo GUIGUI : should be added in a stage.
//-----------------------------------------------
void CCharacterCL::updateVisualPropertyTarget(const NLMISC::TGameCycle &gameCycle, const sint64 &prop)
{
	// New target Received.
	sint targ = (sint)prop;

	if(verboseVP(this))
		nlinfo("(%05d,%03d) CH::updateVPTarget:%d: '%d' received.", sint32(T1%100000), NetMngr.getCurrentServerTick(), _Slot, targ);

	// New entity target
	_TargetSlotNoLag = (CLFECOMMON::TCLEntityId)targ;

	// Add in right stage.
	_Stages.addStage(gameCycle, PROPERTY_TARGET_ID, prop);
}// updateVisualPropertyTarget //

//-----------------------------------------------
// updateVisualPropertyVpa :
// Received the new target for the entity
// \todo GUIGUI : should be added in a stage.
//-----------------------------------------------
void CCharacterCL::updateVisualPropertyVpa(const NLMISC::TGameCycle &/* gameCycle */, const sint64 &prop)
{
	// VPA only useful for NPC
	if(isNPC()==false)
	{
		//nlwarning("CH:updtVPVpa:%d: VPA received but NOT an NPC. Sheet Id '%u(%s)'.", _Slot, _SheetId.asInt(), _SheetId.toString().c_str());
		return;
	}

	// NO SKELETON -> NO VPA
	if(_Skeleton.empty())
		return;

	// Get the alternative look property.
	SAltLookProp altLookProp = *(SAltLookProp *)(&prop);
	// Display debug infos
	if(verboseVP(this))
	{
		nlinfo("(%05d,%03d) CH:updtVPVpa:%d: TopColor(%d) BotColor(%d) RH(%d) LH(%d) Hat(%d) Seed(%d) HairColor(%d)",
			sint32(T1%100000), NetMngr.getCurrentServerTick(), _Slot,
			(uint)altLookProp.Element.ColorTop,        (uint)altLookProp.Element.ColorBot,
			(uint)altLookProp.Element.WeaponRightHand, (uint)altLookProp.Element.WeaponLeftHand,
			(uint)altLookProp.Element.Hat,             (uint)altLookProp.Element.Seed,
			(uint)altLookProp.Element.ColorHair);
	}

	// Dress the character.
	if(!_LookRdy)
	{
		// The entity is now visually ready.
		_LookRdy = true;

		// Generate a new random.
		NLMISC::CRandom rnd;
		rnd.srand((sint)altLookProp.Element.Seed);

		// Retrieve the right sheet for clothes.
		_ClothesSheet = _Sheet;
		if(!_Sheet->IdAlternativeClothes.empty())
		{
			sint32 num = rnd.rand()%(_Sheet->IdAlternativeClothes.size()+1);
			if(num > 0)
			{
				CSheetId altClothesId(_Sheet->getAlternativeClothes(num-1));
				const CEntitySheet *sheetAlt = SheetMngr.get(altClothesId);
				if(dynamic_cast<const CCharacterSheet *>(sheetAlt))
					_ClothesSheet = dynamic_cast<const CCharacterSheet *>(sheetAlt);
			}
		}

		// Eyes Color
		if(_Sheet->EyesColor >= SheetMngr.nbEyesColor())
		{
			if (SheetMngr.nbEyesColor() == 0)
				_EyesColor = 0;
			else
				_EyesColor = (sint8)(rnd.rand()%SheetMngr.nbEyesColor());
		}
		else
			_EyesColor = _Sheet->EyesColor;
		// Hair Color
		if (SheetMngr.nbHairColor() == 0)
			_HairColor = 0;
		else
			_HairColor = (sint8)altLookProp.Element.ColorHair%SheetMngr.nbHairColor();
		// Hair Index
		if(!_Sheet->HairItemList.empty())
		{
			sint32 num = rnd.rand()%_Sheet->HairItemList.size();
			if(num>=0 && num <_BadHairIndex)
				_HairIndex = (uint8)num;
			else
				nlwarning("CH:updtVPVpa:%d: Bad Hair Index '%d'", _Slot, num);
		}

		// -- Dress the character -- (all parts that should not change)
		/** tmp : remove all fx item
		  * \TODO delete an item only if changed
		  */
		buildEquipment(_ClothesSheet->Body,		SLOTTYPE::CHEST_SLOT,	altLookProp.Element.ColorTop);		// Chest
		buildEquipment(_ClothesSheet->Arms,		SLOTTYPE::ARMS_SLOT,	altLookProp.Element.ColorArm);		// Arms
		buildEquipment(_ClothesSheet->Hands,	SLOTTYPE::HANDS_SLOT,	altLookProp.Element.ColorGlove);	// Gloves
		buildEquipment(_ClothesSheet->Legs,		SLOTTYPE::LEGS_SLOT,	altLookProp.Element.ColorBot);		// Legs
		buildEquipment(_ClothesSheet->Feet,		SLOTTYPE::FEET_SLOT,	altLookProp.Element.ColorBoot);		// Boots
		// Face
		_FaceIdx = buildEquipment(_Sheet->Face,			SLOTTYPE::FACE_SLOT);

		// Entity is now dressed
		skeleton()->show();
	}

	// -- Manage the Head --
	// Display the helm.
	if(altLookProp.Element.Hat!=0 && !_ClothesSheet->Head.getItem().empty())
	{
		// Create the Helm.
		_HeadIdx = buildEquipment(_ClothesSheet->Head, SLOTTYPE::HEAD_SLOT, altLookProp.Element.ColorHair, _HeadIdx);
		// Hide the face.
		SInstanceCL *pInstFace = getFace();
		if(pInstFace)
		{
			if(pInstFace->Current.empty() == false)
				pInstFace->Current.hide();
			else
				pInstFace->KeepHiddenWhenLoaded = true;
		}
	}
	// Display the Hair.
	else
	{
		// Create the Hair.
		if(_HairIndex != _BadHairIndex)
			_HeadIdx = buildEquipment(_Sheet->HairItemList[_HairIndex], SLOTTYPE::HEAD_SLOT, altLookProp.Element.ColorHair, _HeadIdx);
		// Display the face.
		SInstanceCL *pInstFace = getFace();
		if(pInstFace)
			if(!pInstFace->Current.empty())
				pInstFace->Current.show();
	}

	// -- Manage weapons -- (weapons can change)

	// Right Hand
	const CItemSheet *newRightHand = SheetMngr.getItem(SLOTTYPE::RIGHT_HAND_SLOT, (uint)altLookProp.Element.WeaponRightHand);
	if (newRightHand != _Items[SLOTTYPE::RIGHT_HAND_SLOT].Sheet) // item changed ?
	{
		// Remove the old Item in the right hand
		if(_RHandInstIdx != CEntityCL::BadIndex)
		{
			// remove shape
			_RHandInstIdx = addInstance("", "", -1, _RHandInstIdx);
			// remove fxs
			_Items[SLOTTYPE::RIGHT_HAND_SLOT].release();
		}
		// set new one
		_Items[SLOTTYPE::RIGHT_HAND_SLOT].Sheet = newRightHand;
		if (newRightHand)
		{
			if( newRightHand->ItemType != ITEM_TYPE::MAGICIAN_STAFF )
				_RHandInstIdx = createItemInstance(*newRightHand, _RHandInstIdx, SLOTTYPE::RIGHT_HAND_SLOT, "box_arme", -1, -1);
			else
				_RHandInstIdx = createItemInstance(*newRightHand, _RHandInstIdx, SLOTTYPE::RIGHT_HAND_SLOT, "", -1, -1);
		}
	}
	// update fx for right hand (trail may have been activated, or advantage fx)
	if (newRightHand)
	{
		SInstanceCL *instCLRH = idx2Inst(_RHandInstIdx);
		if(instCLRH)
		{
			NL3D::UInstance itemInstance = (!instCLRH->Loading.empty()) ? instCLRH->Loading : instCLRH->Current;
			if (!itemInstance.empty())
			{
				// update fxs
				_Items[SLOTTYPE::RIGHT_HAND_SLOT].enableAdvantageFX(itemInstance);
				if ( _CurrentBehaviour.Behaviour != MBEHAV::EXTRACTING )
					_Items[SLOTTYPE::RIGHT_HAND_SLOT].setTrailSize(altLookProp.Element.RTrail);
			}
		}
	}

	// Left Hand
	const CItemSheet *newLeftHand = SheetMngr.getItem(SLOTTYPE::LEFT_HAND_SLOT, (uint)altLookProp.Element.WeaponLeftHand);
	if (newLeftHand != _Items[SLOTTYPE::LEFT_HAND_SLOT].Sheet) // item changed ?
	{
		// Remove the old Item in the left hand
		if(_LHandInstIdx != CEntityCL::BadIndex)
		{
			// remove shape
			_LHandInstIdx = addInstance("", "", -1, _LHandInstIdx);
			// remove fxs
			_Items[SLOTTYPE::LEFT_HAND_SLOT].release();
		}
		// set new one
		_Items[SLOTTYPE::LEFT_HAND_SLOT].Sheet = newLeftHand;
		if (newLeftHand)
		{
			string bindBone;
			if(newLeftHand->getAnimSet() == "s")
				bindBone = "Box_bouclier";
			else
				bindBone = "box_arme_gauche";
			_LHandInstIdx = createItemInstance(*newLeftHand, _LHandInstIdx, SLOTTYPE::LEFT_HAND_SLOT, bindBone, -1, -1);
		}
	}
	// update fx for left hand (trail may have been activated, or advantage fx)
	if (newLeftHand)
	{
		SInstanceCL *instCLLH = idx2Inst(_LHandInstIdx);
		if(instCLLH)
		{
			NL3D::UInstance itemInstance = (!instCLLH->Loading.empty()) ? instCLLH->Loading : instCLLH->Current;
			if (!itemInstance.empty())
			{
				// update fxs
				_Items[SLOTTYPE::LEFT_HAND_SLOT].enableAdvantageFX(itemInstance);
				_Items[SLOTTYPE::LEFT_HAND_SLOT].setTrailSize((uint) (2 * altLookProp.Element.LTrail));
			}
		}
	}


	// -- Update Animation --  (after all those changes animation could change).
	computeAnimSet();
	setAnim(animState(MOVE));
}// updateVisualPropertyVpb //

//-----------------------------------------------
// updateVisualPropertyVpb :
//-----------------------------------------------
void CCharacterCL::updateVisualPropertyVpb(const NLMISC::TGameCycle &/* gameCycle */, const sint64 &prop)
{
	// Get the alternative look property.
	SAltLookProp2 altLookProp = *(SAltLookProp2 *)(&prop);
	// Display debug infos
	if(verboseVP(this))
	{
		nlinfo("(%05d,%03d) CH:updtVPVpb:%d: Scale(%d)", sint32(T1%100000), NetMngr.getCurrentServerTick(), _Slot,
			(uint)altLookProp.PropertySubData.Scale);
	}
	// Save old scale
	float oldCustomScale = _CustomScale;
	// Set new scale
	if (altLookProp.PropertySubData.Scale==0)
		_CustomScale = 1.f;
	else
		_CustomScale = (float)altLookProp.PropertySubData.Scale/100.f;
	// Apply modification
	_CustomScalePos /= oldCustomScale;
	_CustomScalePos *= _CustomScale;
	// change the scale of the skeleton according to the new people
	USkeleton * skel = skeleton();
	if( skel )
	{
		skel->setScale(getScale(), getScale(), getScale());

		// modify the stick bone scale to not propagate scale to child
		sint boneID = skel->getBoneIdByName("stick_1");
		if( boneID != -1 )
		{
			UBone bone = skel->getBone(boneID);
			CVector newBoneScale = bone.getScale() * oldCustomScale/_CustomScale;
			bone.setScale( newBoneScale );
		}
	}
	// must set the new scale for the BotObject too
	else if(!_Instances.empty())
	{
		float	s= getScale();
		_Instances[0].setScale(CVector(s,s,s));
	}


	if (_Primitive)
	{
		float width, depth;
		_Primitive->getSize(width, depth);
		UMovePrimitive::TType primtype = _Primitive->getPrimitiveType();
		_Primitive->setPrimitiveType(UMovePrimitive::_2DOrientedBox);
		_Primitive->setSize((width / oldCustomScale) * _CustomScale, (depth / oldCustomScale) * _CustomScale);
		_Primitive->setPrimitiveType(primtype);
	}

}// updateVisualPropertyVpb //

//-----------------------------------------------
// updateVisualPropertyEntityMounted :
// Update Entity Mount
//-----------------------------------------------
void CCharacterCL::updateVisualPropertyEntityMounted(const NLMISC::TGameCycle &gameCycle, const sint64 &prop)
{
	// New target Received.
	sint mountSlot = (sint)prop;
	_TheoreticalMount = (CLFECOMMON::TCLEntityId)mountSlot;
	if(verboseVP(this))
		nlinfo("(%05d,%03d) CH::updateVPMount:%d: '%d' received.", sint32(T1%100000), NetMngr.getCurrentServerTick(), _Slot, mountSlot);

	// Add in right stage.
	_Stages.addStage(gameCycle, CLFECOMMON::PROPERTY_ENTITY_MOUNTED_ID, prop);
}// updateVisualPropertyEntityMounted //

//-----------------------------------------------
// updateVisualPropertyRiderEntity :
// Update Entity Rider
//-----------------------------------------------
void CCharacterCL::updateVisualPropertyRiderEntity(const NLMISC::TGameCycle &gameCycle, const sint64 &prop)
{
	// New target Received.
	sint riderSlot = (sint)prop;
	_TheoreticalRider = (CLFECOMMON::TCLEntityId)riderSlot;
	if(verboseVP(this))
		nlinfo("(%05d,%03d) CH::updateVPRider:%d: '%d' received.", sint32(T1%100000), NetMngr.getCurrentServerTick(), _Slot, riderSlot);

	// Add in right stage.
	_Stages.addStage(gameCycle, CLFECOMMON::PROPERTY_RIDER_ENTITY_ID, prop);
}// updateVisualPropertyRiderEntity //

//-----------------------------------------------
// updateVisualPropertyBars :
// Update Entity Bars
//-----------------------------------------------
void CCharacterCL::updateVisualPropertyBars(const NLMISC::TGameCycle &gameCycle, const sint64 &prop)	// virtual
{
	CBarManager::CBarInfo	barInfo;

	// Encode HP to 7 bits
	barInfo.Score[SCORES::hit_points]	= (sint8)((prop&0x7ff) * 127 / 1023);
	// NB: barInfo are sint8, but no problem, since anything following is 7 bits.
    barInfo.Score[SCORES::stamina]		= (uint8)((prop>>11)&0x7f);
    barInfo.Score[SCORES::sap]			= (uint8)((prop>>18)&0x7f);
    barInfo.Score[SCORES::focus]		= (uint8)((prop>>25)&0x7f);

	// update The Bar manager
	CBarManager	*pBM= CBarManager::getInstance();
	/* ***********
	  WHY gameCycle+1 ?????  (yoyo)
		It's because sometimes I have a bug With target DB update and VP update. This is the scenario
		where I suppose the problem rises:
		tick=320:	EGS::tickUpdate(): player.DBTargetHP.setProp(49)
		tick=321:	EGS::combat update, target ennemy receives a Hit, VPHp=10 => transmitted to client with timestamp=321
					EGS::databaseUpdate(), DB updated, with timestamp=321!!!

		Thus I receives on client:
			first the VP with Hp=10, timestamp=321
			second the DB with Hp=49, timestamp=321 too => replaced => BUG
		NB: DB is typically sent at low frequency by FrontEnd, thus received later on client.

		Since databaseUpdate() is called every 2 ticks, adding +1 to VP timestamps solve easily the problem.

		NB: the problem occurs because tickUpdate() and databaseUpdate() are called typically with 1 tick shift (tickUpdate()
			on even ticks, and databaseUpdate() on odd ticks for instance).

		NB: moreover, tickupdate() is called every 8 (or 16) ticks, and databaseUpdate() every 2 ticks. So there is one more
			possible bug:
			318:	EGS::tickUpdate(): player.DBTargetHP.setProp(49)
			319:	EGS::combat update, target ennemy receives a Hit, VPHp=10 => transmitted to client with timestamp=319
					EGS::databaseUpdate(), BUT decide to send only a small subset of DB (because lot of things to send)
						=> our TargetHP is not updated
			320:	nothing. tickupdate() is not called, since every 8 ticks
			321:	EGS::databaseUpdate(), update TargetHP, with timestamp=321 !!!!! => Bug

		(remind that we cannot store a timestamp for each DB property, else would be too big to store and to send...)

		BTW, this last bug should be very rare, so don't care.
	*********** */
	pBM->updateBars(dataSetId(), barInfo, gameCycle+1,
		CBarManager::HpFlag | CBarManager::StaFlag | CBarManager::SapFlag | CBarManager::FocusFlag);

}// updateVisualPropertyBars //

//-----------------------------------------------
// updateVisualPropertyGuildSymbol :
//
//-----------------------------------------------
void CCharacterCL::updateVisualPropertyGuildSymbol(const NLMISC::TGameCycle &/* gameCycle */, const sint64 &prop)
{
	_GuildSymbol = prop;

	// maybe need to rebuild the in scene interface
	if(_InSceneUserInterface && _InSceneUserInterface->needGuildSymbolId())
		buildInSceneInterface();
} // updateVisualPropertyGuildSymbol //

//-----------------------------------------------
// updateVisualPropertyGuildNameID :
//
//-----------------------------------------------
void CCharacterCL::updateVisualPropertyGuildNameID(const NLMISC::TGameCycle &/* gameCycle */, const sint64 &prop)
{
	_GuildNameId = uint32(prop);

	// maybe need to rebuild the in scene interface
	if(_InSceneUserInterface && _InSceneUserInterface->needGuildNameId())
		buildInSceneInterface();
} // updateVisualPropertyGuildNameID //

//-----------------------------------------------
// updateVisualPropertyEventFactionID :
//
//-----------------------------------------------
void CCharacterCL::updateVisualPropertyEventFactionID(const NLMISC::TGameCycle &/* gameCycle */, const sint64 &prop)
{
	// ODD Hack by Ulukyn
	//_EventFactionId = uint32(prop);
	_PvpMode = uint32(prop);

	buildInSceneInterface();

	if (isUser())
	{
		uint i;
		uint numEntity = (uint)EntitiesMngr.entities().size();
		for (i=0; i<numEntity; i++)
		{
			CEntityCL *entity = EntitiesMngr.entity(i);
			if (entity)
			{
				CCharacterCL *character = dynamic_cast<CCharacterCL*>(entity);
				if (character)
				{
					if( character->getPvpMode() != 0 && !character->isUser())
						character->buildInSceneInterface ();
				}
			}
		}
	}
} // updateVisualPropertyEventFactionID //

//-----------------------------------------------
// updateVisualPropertyPvpMode :
//
//-----------------------------------------------
void CCharacterCL::updateVisualPropertyPvpMode(const NLMISC::TGameCycle &/* gameCycle */, const sint64 &prop)
{
	//_PvpMode = uint32(prop);
	//buildInSceneInterface();

} // updateVisualPropertyPvpMode //

//-----------------------------------------------
// updateVisualPropertyPvpClan :
//
//-----------------------------------------------
void CCharacterCL::updateVisualPropertyPvpClan(const NLMISC::TGameCycle &/* gameCycle */, const sint64 &prop)
{
	_LeagueId = uint32(prop);

	buildInSceneInterface();

	if (isUser())
	{
		uint i;
		uint numEntity = (uint)EntitiesMngr.entities().size();
		for (i=0; i<numEntity; i++)
		{
			CEntityCL *entity = EntitiesMngr.entity(i);
			if (entity)
			{
				CCharacterCL *character = dynamic_cast<CCharacterCL*>(entity);
				if (character)
				{
					if( character->getPvpMode() != 0 && !character->isUser())
						character->buildInSceneInterface ();
				}
			}
		}
	}
} // updateVisualPropertyPvpClan //

//-----------------------------------------------
// updateVisualPropertyStatus :
// Update Entity Status
//-----------------------------------------------
void CCharacterCL::updateVisualPropertyStatus(const NLMISC::TGameCycle &/* gameCycle */, const sint64 &/* prop */)	// virtual
{
	nlinfo("CH:updtVPStatus:%d: received.", _Slot);
}// updateVisualPropertyStatus //

//-----------------------------------------------
// updateVisualPropertyContextual :
// Update Entity Status
//-----------------------------------------------
void CCharacterCL::updateVisualPropertyContextual(const NLMISC::TGameCycle &gameCycle, const sint64 &prop)
{
	bool	precAttackable= _Properties.attackable();

	// call parent
	CEntityCL::updateVisualPropertyContextual(gameCycle, prop);

	// if attack modified, and npc/fauna, must rebuild the in scene interface,
	// cause sheets 'Attackable' property not always correclty filled
	if( (isNPC()||isFauna()) && precAttackable!=_Properties.attackable())
		buildInSceneInterface();
}


//-----------------------------------------------
// updateVisualPropertyOwnerPeople :
//
//-----------------------------------------------
void CCharacterCL::updateVisualPropertyOwnerPeople(const NLMISC::TGameCycle &/* gameCycle */, const sint64 &prop)
{
	if( _OwnerPeople != MOUNT_PEOPLE::TMountPeople(prop) )
	{
		// reset scale pos
		float oldPeopleScaleFactor;
		switch( _OwnerPeople )
		{
			case MOUNT_PEOPLE::Fyros : oldPeopleScaleFactor = ClientCfg.FyrosScale; break;
			case MOUNT_PEOPLE::Matis : oldPeopleScaleFactor = ClientCfg.MatisScale; break;
			case MOUNT_PEOPLE::Tryker : oldPeopleScaleFactor = ClientCfg.TrykerScale; break;
			case MOUNT_PEOPLE::Zorai : oldPeopleScaleFactor = ClientCfg.ZoraiScale; break;
			default:
				oldPeopleScaleFactor = 1.f;
		}
		_CustomScalePos /= oldPeopleScaleFactor;

		// set the new scale pos
		float newPeopleScaleFactor;
		_OwnerPeople = MOUNT_PEOPLE::TMountPeople(prop);
		switch( _OwnerPeople )
		{
			case MOUNT_PEOPLE::Fyros : newPeopleScaleFactor = ClientCfg.FyrosScale; break;
			case MOUNT_PEOPLE::Matis : newPeopleScaleFactor = ClientCfg.MatisScale; break;
			case MOUNT_PEOPLE::Tryker : newPeopleScaleFactor = ClientCfg.TrykerScale; break;
			case MOUNT_PEOPLE::Zorai : newPeopleScaleFactor = ClientCfg.ZoraiScale; break;
			default:
				newPeopleScaleFactor = 1.f;
		}
		_CustomScalePos *= newPeopleScaleFactor;

		// change the scale of the skeleton according to the new people
		USkeleton * skel = skeleton();
		if( skel )
		{
			skel->setScale(getScale(), getScale(), getScale());

			// modify the stick bone scale to not propagate scale to child
			sint boneID = skel->getBoneIdByName("stick_1");
			if( boneID != -1 )
			{
				UBone bone = skel->getBone(boneID);
				CVector newBoneScale = bone.getScale() * oldPeopleScaleFactor/newPeopleScaleFactor;
				bone.setScale( newBoneScale );
			}
		}
	}

} // updateVisualPropertyOwnerPeople //



//-----------------------------------------------
// updateVisualPropertyOutpostInfos :
//
//-----------------------------------------------
void CCharacterCL::updateVisualPropertyOutpostInfos(const NLMISC::TGameCycle &/* gameCycle */, const sint64 &prop)
{
	_OutpostId = ((uint16)prop)&0x7FFF;
	uint16 side = (((uint16)prop)&0x8000)>>15;
	_OutpostSide = (OUTPOSTENUMS::TPVPSide)side;

	nldebug("<CCharacterCL::updateVisualPropertyOutpostInfos> prop = %d, id=%d side=%d",(uint16)prop,_OutpostId,_OutpostSide);

	buildInSceneInterface();

} // updateVisualPropertyOutpostInfos //


//-----------------------------------------------
// skin :
// Get The Entity Skin
//-----------------------------------------------
sint CCharacterCL::skin() const	// virtual
{
	return _Sheet->Skin;
}// skin //


//-----------------------------------------------
// initProperties :
// Initialize properties of the entity (according to the class).
//-----------------------------------------------
void CCharacterCL::initProperties()
{
	properties().selectable(_Sheet->Selectable);
	properties().talkableTo(_Sheet->Talkable);
	properties().attackable(_Sheet->Attackable);
	properties().givable(_Sheet->Givable);
	properties().mountable(_Sheet->Mountable);
	properties().invitable(false);										// You cannot group with a bot.
	properties().afk(false);

	switch(_Sheet->HLState)
	{
	case LHSTATE::LOOTABLE:
		properties().lootable(true);		// You can loot the creature
		properties().harvestable(false);	// You cannot harvest the creature
		break;
	case LHSTATE::HARVESTABLE:
		properties().lootable(false);		// You cannot loot the creature
		properties().harvestable(true);		// You can harvest the creature
		break;
	case LHSTATE::LOOTABLE_HARVESTABLE:
		properties().lootable(true);		// You can loot the creature
		properties().harvestable(true);		// You can harvest the creature
		break;

	default:
		properties().lootable(false);		// You cannot loot the creature
		properties().harvestable(false);	// You cannot harvest the creature
		break;
	}
}// initProperties //


//-----------------------------------------------
// computeTimeStep :
// Compute the elapsed time since last call.
// \param currentTime : current time in sec.
// \return double : elapsed time.
//-----------------------------------------------
double CCharacterCL::computeTimeStep(const double &currentTime)
{
	// Last Time greater than Current Time.
	if(_LastFrameTime > currentTime)
	{
		nlwarning("CCharacterCL::computeTimeStep : Time since last frame is negative (%f). Set _LastFrameTime with currentTime", _LastFrameTime - currentTime);
		_LastFrameTime = currentTime;
	}

	// Time since last Time >= 0
	return currentTime - _LastFrameTime;
}// computeTimeStep //


//-----------------------------------------------
// computeSpeed :
// \todo GUIGUI : to do an average speed, there is a problem if time become very small because small frame or _LastFrameTime increase when looping
//-----------------------------------------------
double CCharacterCL::computeSpeed()
{
	double spd;
	double t = _DestTime - _LastFrameTime;
	if(dist2Dest() <= 0.0)					// Already at destination.
		spd = 0.0;
	else if(_LastFrameTime == 0.0)			// First frame
		spd = 1.0;
	else if(t < 0.0001)	// We should already be at destination.
		spd = 1000.0;//-1.0;
	else
	{
		spd = dist2Dest()/t;
		if(spd>0 && spd<0.001)
			spd = 0.001;
		if(spd > 1000.0)
			spd = 1000.0;
	}
	speed(spd);
	return spd;
}// computeSpeed //

//-----------------------------------------------
// computeSpeedFactor :
// Compute and return the speed factor to apply to the animation.
// \param speedToDest : evaluted speed to destination.
// \return double : the speed factor to use for the current animation.
// \todo GUIGUI : review this scale problem and optimize it.
//-----------------------------------------------
double CCharacterCL::computeSpeedFactor(double speedToDest)
{
	double speedFactor = 1.0;

	// \todo GUIGUI : optimize emotes, currently it's badly designed.
	const CAnimationState *animStatePtr;
	// If the current animation is an emote, get the right animation state.
	if(animState(MOVE) == CAnimationStateSheet::Emote)
		animStatePtr = _CurrentAnimSet[MOVE]->getAnimationState(_SubStateKey);
	else
		animStatePtr = _CurrentAnimSet[MOVE]->getAnimationState(animState(MOVE));
	if(animStatePtr)
	{
		// Get the animation
		const CAnimation *anim = animStatePtr->getAnimation(animIndex(MOVE));
		if(anim)
		{
			// If the animation is a move (not idle, turn, etc.).
			if(_CurrentState)
			{
				// Move : adjust speed factor according to the animation.
				if(_CurrentState->Move)
				{
					// Check for oo speed.
					if(speedToDest != -1)
					{
						// Compute the animation average speed according to the scale.
						double animSpeed = EAM->getAnimationAverageSpeed(anim->id())*getSheetScale()*_CustomScalePos*_CharacterScalePos;
						if(animSpeed > 0.0)
							speedFactor = speedToDest / animSpeed;
						else
							nlwarning("The animation is a move but animation speed is %f !", animSpeed);
					}
					// \todo GUIGUI : unlimited speed, perhaps return a special value.
					// We should be arrived so speed is maximum.
					else
						speedFactor = 1000.0;
				}
				// The current animation is a rotation so adjust the rotation speed according to the angle.
				if(_CurrentState->Rotation && _RotationFactor > 0.0)
				{
					speedFactor /= _RotationFactor;
					speedFactor = std::min(speedFactor, 1.5);
					speedFactor = std::max(speedFactor, 0.5);
				}
				// This animation must be play in a maximum time when there is someting to do after.
				// (must be done after the rotation speed adjustment)
				if(_CurrentState->MaxAnimDuration > 0.00f)
				{
					if(dist2Dest() >= 0.0)
					{
						double animLength = EAM->getAnimationLength(anim->id());
						double speedFactorBackup = speedFactor;
						speedFactor = animLength/_CurrentState->MaxAnimDuration;
						// If the animation speed should have been greater, let it play faster.
						if(speedFactor < speedFactorBackup)
							speedFactor = speedFactorBackup;
					}
				}
				// Panic mode (too late => accelerate)
				if(!_CurrentState->Move && _ImportantStepTime!=0.0)
				{
					const float	beginPanic= 1.5f;		// start panic when too late of 1.5 seconds
					const float endPanic= 5.f;			// max panic factor at 5 seconds of interval
					const float	maxPanicSpeedFactor= 10.f;
					float	t= float(TimeInSec - _ImportantStepTime);
					if(t>beginPanic)
					{
						float	lerp= (t-beginPanic)/(endPanic-beginPanic);
						clamp(lerp, 0.f, 1.f);
						float	panicSF= lerp*maxPanicSpeedFactor;
						if(panicSF>speedFactor)
							speedFactor= panicSF;
					}
				}
				// Special panic mode because there is a position just after
				// NB: don't accelerate animations that can be breaked because of move
				// But still allow acceleration for mode animation transition (_Mode!=_ModeWanted)
				if( !_CurrentState->Move && _RunStartTimeNoPop!=INVALID_TIME &&
					(!_CurrentState->BreakableOnMove || _Mode!=_ModeWanted) )
				{
					const float maxPanicSpeedFactor= 1.5f;
					// compare time of rest of animation, to remain time to the first move
					float	remainAnimTime= float(EAM->getAnimationLength(anim->id()) - animOffset(MOVE));
					remainAnimTime= max(remainAnimTime, 0.f);
					float	panicSF;
					// if already too late, then maximize speed
					if(TimeInSec>=_RunStartTimeNoPop)
					{
						panicSF= maxPanicSpeedFactor;
					}
					// else target the animation speed so it ends at estimated start of move
					else
					{
						panicSF= float(remainAnimTime/(_RunStartTimeNoPop-TimeInSec));
						panicSF= min(panicSF, maxPanicSpeedFactor);
					}
					// only if greater than prec
					if(panicSF>speedFactor)
						speedFactor= panicSF;
				}

				// TestYoyo
				/*
				if(_Slot==WatchedEntitySlot && EntitiesMngr.isLogingStageChange())
				{
					sint64	refLT= EntitiesMngr.getLogStageChangeStartLocalTime();
					NLMISC::createDebug();
					NLMISC::DebugLog->displayRawNL("** Entity %d: (t=%3d) animState %s: %.2f/%.2f. move: %d. rstnp: %d. sf: %.2f",
						(sint32)_Slot, sint32(T1-refLT),
						CAnimationState::getAnimationStateName(animStatePtr->state()).c_str(),
						float(animOffset(MOVE)), float(EAM->getAnimationLength(anim->id())),
						uint(_CurrentState->Move), _RunStartTimeNoPop==INVALID_TIME?-1:sint32(sint64(_RunStartTimeNoPop*1000)-refLT),
						speedFactor
						);
				}
				*/
			}
		}
	}

	// \todo GUIGUI : corriger pour enlever le speed factor min.
	// Adjuste speed factor
	if(speedFactor < 0.5)
		speedFactor = 0.5;

	// Check negative or null speed factor.
	if(speedFactor <= 0.0)
	{
		nlwarning("CCharacterCL::computeSpeedFactor: speedFactor = %f and this should never be <= 0.", speedFactor);
		speedFactor = 1.0;
	}

	// Return the speed factor.
	return speedFactor;
}// computeSpeedFactor //

//-----------------------------------------------
// endAnimTransition :
// Call it at the end of the current animation to choose the next one.
//-----------------------------------------------
void CCharacterCL::endAnimTransition()
{
	// One more animation played.
	_NbLoopAnim++;

	// Hide the entity if needed.
	if(_HideSkin)
		hideSkin();

	// Debug Animation for the selection
	if(VerboseAnimSelection && _Slot == UserEntity->selection())
		nlinfo("CH:endAnimTransition:%d: current animation finished.", _Slot);
	// If the animation is a rotation, set the character direction he should have at the end of the animation.
	if(_CurrentState->Rotation)
	{
		if(isUser())
		{
			nldebug("<CCharacterCL::endAnimTransition> rotation : set dir as end anim dir");
		}

		dir(dirEndAnim());
	}
	// Fit the current direction to the target when attacking.
	if(_CurrentState->Attack)
	{
		dir(front());
	}
	// If user is in range attack and not moving, set dir to target
	if( isUser() )
	{
		if(_CurrentBehaviour.Behaviour == MBEHAV::RANGE_ATTACK && _Mode==MBEHAV::COMBAT && !UserControls.isMoving())
		{
			dir( dirToTarget() );

			float frontYawBefore = frontYaw();
			front(dir());
			float frontYawAfter = frontYaw();
			float	deltaYaw= frontYawAfter - frontYawBefore;
			UserControls.appendCameraDeltaYaw(-deltaYaw);

			if( ClientCfg.AutomaticCamera )
			{
				UserControls.resetSmoothCameraDeltaYaw();
			}
		}
	}

	// If the next mode in the automaton != Current Mode
	if(_CurrentState->NextMode != _Mode)
	{
		// Undo previous behaviour
		if (_Mode == MBEHAV::DEATH)
		{
			// Restore collisions.
			if (_Primitive)
			{
				// TODO: Without this dynamic cast
				if (dynamic_cast<CPlayerCL *>(this))
					_Primitive->setOcclusionMask(MaskColPlayer);
				else
					_Primitive->setOcclusionMask(MaskColNpc);
			}
		}

		if (ClientCfg.UsePACSForAll && _Primitive)
			_Primitive->setCollisionMask(MaskColNone);

		//// ADDED ////
		switch(_CurrentState->NextMode)
		{
		// Combat
		case MBEHAV::COMBAT:
		case MBEHAV::COMBAT_FLOAT:
			if(ClientCfg.UsePACSForAll && _Primitive)
				_Primitive->setCollisionMask(MaskColPlayer | MaskColNpc | MaskColDoor);	// Collision with player and npc.
			break;
		// Mount
		case MBEHAV::MOUNT_NORMAL:
			parent(_Mount);
			// Remove collisions if needed.
			if(_Mount != CLFECOMMON::INVALID_SLOT)
			{
				if(_Primitive)
					_Primitive->setOcclusionMask(MaskColNone);
			}
			break;
		// Death
		case MBEHAV::DEATH:
			setDead();
			break;
		// UNKNOWN
		case MBEHAV::UNKNOWN_MODE:
			if(ClientCfg.Check)
				nlstop;
			// NO BREAK is Normal here
		// Normal
		case MBEHAV::NORMAL:
//			_Mount = CLFECOMMON::INVALID_SLOT;
//			_Rider = CLFECOMMON::INVALID_SLOT;
			parent(CLFECOMMON::INVALID_SLOT);
			dir(front());
			/*
			front(CVector(1.f, 0.f, 0.f));
			dir(front());
			*/
			break;
		default:
			break;
		}
		// Change the current mode.
		if ( _ModeWanted != MBEHAV::UNKNOWN_MODE )
		{
			_Mode = _CurrentState->NextMode;
		}
		//else
		//	nlinfo( "NO mode change from %u to %u, %s S%hu", _Mode, _CurrentState->NextMode, _SheetId.toString().c_str(), _Slot );
		// Change the current automaton.
		computeAutomaton();
		// Update the animation set according to the new automaton.
		computeAnimSet();
	}
	// Select the Default Next Animation.
	setAnim(_CurrentState->NextState);
}// endAnimTransition //

//-----------------------------------------------
// onMove :
//-----------------------------------------------
CCharacterCL::TOnMove CCharacterCL::onMove(const CAutomatonStateSheet &curAnimState)
{
	// Animation is breakable if the distance to destination is long enough (at least > 0).
	if(curAnimState.BreakableOnMove && dist2Dest()>0.0)
	{
		// \todo GUIGUI : take the next position to current one (it could be possible this position was the same as the first).
		CVectorD dirToFirstPos = _FirstPos-pos();
		dirToFirstPos.z = 0.0;
		if(dirToFirstPos != CVectorD::Null)
			dirToFirstPos.normalize();
		else
		{
			nlwarning("CH:onMove:%d: First pos == pos -> take the dir(%f,%f,%f) instead.", _Slot, dir().x, dir().y, dir().z);
			dirToFirstPos = dir();
		}

		// Compute Angle between the front and the first position.
		double angToDest = computeShortestAngle(atan2(front().y, front().x), atan2(dirToFirstPos.y, dirToFirstPos.x));
		if(!_MaxLoop)
		{
			// Strafe Left
			if(curAnimState.OnMoveLeft     != CAnimationStateSheet::UnknownState)
				if((angToDest>Pi/3.0) && (angToDest<2.0*Pi/3.0))
					return OnMoveLeft;
			// Strafe Right
			if(curAnimState.OnMoveRight    != CAnimationStateSheet::UnknownState)
				if((angToDest<-Pi/3.0) && (angToDest>-2.0*Pi/3.0))
					return OnMoveRight;
			// Backward
			if(curAnimState.OnMoveBackward != CAnimationStateSheet::UnknownState)
				if(fabs(angToDest)>1.92)
					return OnMoveBackward;
		}
		// Forward (default)
		if(curAnimState.OnMoveForward  != CAnimationStateSheet::UnknownState)
		{
//			if(_MaxLoop || fabs(angToDest)<=1.92)
				return OnMoveForward;
		}
		else
			nlwarning("CH:onMove:%d: the current state is breakable on Move and the dist to dest is not Null, but there is no animation to move.", _Slot);
	}
	// No Move
	return OnMoveNone;
}// onMove //

//-----------------------------------------------
// onRotation :
//-----------------------------------------------
CCharacterCL::TOnRot CCharacterCL::onRotation(const CAutomatonStateSheet &curAnimState, CVector &dirEndA)
{
	// Turn and About Face
	if(curAnimState.BreakableOnRotation)
	{
		CVector bodyDir = dir();
		CVector destDir = front();

		// when user is attacking, his dest is his target
		if( isUser() && _CurrentBehaviour.Behaviour == MBEHAV::RANGE_ATTACK && _Mode==MBEHAV::COMBAT && !UserControls.isMoving() )
		{
			destDir = dirToTarget();
		}

		// Compute the angle between the current heading and computed heading.
		double angToDest = computeShortestAngle(atan2(bodyDir.y, bodyDir.x), atan2(destDir.y, destDir.x));
		// Rotation to the left.
		if(angToDest >=  (ClientCfg.AnimatedAngleThreshold*Pi/180.0))
		{
			dirEndA = destDir;
			return OnRotLeft;
		}
		// Rotation to the right.
		if(angToDest <= -(ClientCfg.AnimatedAngleThreshold*Pi/180.0))
		{
			dirEndA = destDir;
			return OnRotRight;
		}
	}
	// No Rot
	return OnRotNone;
}// onRotation //

//-----------------------------------------------
// onBigBend :
//-----------------------------------------------
CCharacterCL::TOnBigBend CCharacterCL::onBigBend(const CAutomatonStateSheet &curAnimState, CVector &dirEndA)
{
	// If the current direction is too different of the direction to the first destination -> play a rotation.
	if(curAnimState.BrkOnBigBend)
	{
		CVector dirToFirstPos;
		if(setVect(dirToFirstPos, _FirstPos - pos(), true, false))
		{
			dirToFirstPos = curAnimState.getMatrix()*dirToFirstPos;
			double angToDest = computeShortestAngle(atan2(dir().y, dir().x), atan2(dirToFirstPos.y, dirToFirstPos.x));
			// Rotation to the left.
			if(angToDest >= 1.5)
			{
				dirEndA = dirToFirstPos;
				return OnBendLeft;
			}
			// Rotation to the right.
			if(angToDest <= -1.5)
			{
				dirEndA = dirToFirstPos;
				return OnBendRight;
			}
			// Smooth dir
			if(fabs(angToDest) > 0.1)
			{
				double newAngle = atan2(dir().y, dir().x) + angToDest/2.0;
				dir(CVector((float)cos(newAngle), (float)sin(newAngle), dir().z));
			}
			else
				dir(dirToFirstPos);
		}
	}
	// No Bend
	return OnBendNone;
}// onBigBend //

//-----------------------------------------------
// onBadHeading :
//-----------------------------------------------
bool CCharacterCL::onBadHeading(const CAutomatonStateSheet &curAnimState)
{
	// Bad Heading
	if(curAnimState.BreakableOnBadHeading && !_MaxLoop)
	{
		CVector dirToFirstPos;
		if(setVect(dirToFirstPos, _FirstPos - pos(), true, false))
		{
			// Compute the angle between the front and the next body direction.
			double angToDest = computeShortestAngle(atan2(front().y, front().x), atan2(dirToFirstPos.y, dirToFirstPos.x));
			if(curAnimState.BadHeadingMin <= curAnimState.BadHeadingMax)
			{
				if((angToDest<curAnimState.BadHeadingMin) || (angToDest>curAnimState.BadHeadingMax))
					return true;
			}
			else
			{
				if((angToDest<curAnimState.BadHeadingMin) && (angToDest>curAnimState.BadHeadingMax))
					return true;
			}
		}
	}
	// No bad Heading
	return false;
}// onBadHeading //

//-----------------------------------------------
// setAnim :
// Select a new animation for the entity.
// \todo GUIGUI : better manage when there is no skeleton
// \todo GUIGUI : simplify head control
//-----------------------------------------------
ADD_METHOD(void CCharacterCL::setAnim(TAnimStateKey newKey, TAnimStateKey subKey, uint animID))
	if(ClientCfg.Light)
		return;

	// Debug Animation for the target
	if(VerboseAnimSelection && _Slot == UserEntity->selection())
		nlinfo("CH:setAnim:%d: state '%s'.", _Slot, CAnimationState::getAnimationStateName (newKey).c_str());


	// RELEASE THE OLD ANIMATION
	TAnimStateId lastAnimStateId = animState(MOVE);	// Bkup the current anim state Id.

	// \todo GUIGUI : Faire une fonction pour savoir si on a changer de type d'animation.
	// Reset loop counter
	if((newKey != animState(MOVE)) || (_OldAutomaton != _CurrentAutomaton))
		_NbLoopAnim = 0;

	// RESET THE CURRENT ANIMATION
	_HideSkin = false;
	CAnimation::TAnimId buIndex = animIndex(MOVE);
	animIndex (MOVE,           CAnimation::UnknownAnim);				// Reset the current animation Index
	animState (MOVE,	       CAnimationStateSheet::UnknownState);		// Reset the current animation state
	animOffset(MOVE,           0.0);									// Reset the current animation offset
	animIndex (MOVE_BLEND_OUT, CAnimation::UnknownAnim);				// Reset the current animation Index
	animState (MOVE_BLEND_OUT, CAnimationStateSheet::UnknownState);		// Reset the current animation state
	animOffset(MOVE_BLEND_OUT, 0.0);									// Reset the current animation offset
	_RotationFactor		= 1.0;											// New animation -> default rotation factor for the time.
	_RightFXActivated	= false;
	_LeftFXActivated	= false;
	_RotationFactor		= 1.0f;											// Rotation factor as the animation for the time.
	_SubStateKey		= CAnimationStateSheet::UnknownState;			// No SubStateKey for the time.
	dirEndAnim(dir());													// For the time the direction at the end of the animation is the current direction.

	// CHECK
	// If there is no animation set ->There is nothing we can do properly.
	if(_CurrentAnimSet[MOVE] == 0)
		return;


	// INITIALIZE
	if(!animationStateKey(MOVE, newKey))
	{
		nlwarning("CH:setAnim:%d: automaton '%s': animation state key '%s' asked is not valid -> trying Idle.", _Slot, _CurrentAutomaton.c_str(), CAnimationState::getAnimationStateName (newKey).c_str());
		if(!animationStateKey(MOVE, CAnimationStateSheet::Idle))
			nlwarning("CH:setAnim:%d: Idle is not warking too", _Slot);
	}

	// Compute Speed
	double speedToDest = computeSpeed();
	// Compute the direction to the first position (direction = front if there is not first pos)
	CVector dirToFirstPos;
	if(dist2FirstPos() > 0.0)
		dirToFirstPos = (_FirstPos - pos()).normed();
	else
		dirToFirstPos = front();

	uint antiFreezeCounter = 0;
// Loop until the process find a steady state.
KeyChosen:
	// Get the state for the current animation.
	const CAutomatonStateSheet *state = EAM->mState(_CurrentAutomaton, animState(MOVE));
	if(state == 0)
	{
		nlwarning("CH:setAnim:%d: State '%s' not in the automaton '%s'.", _Slot, CAnimationStateSheet::getAnimationStateName(animState(MOVE)).c_str(), _CurrentAutomaton.c_str());
		// No animation playing
		if(_PlayList)
			_PlayList->setAnimation(MOVE, UPlayList::empty);
		return;
	}
	const CAutomatonStateSheet &curAnimState = *state;
	//--------------------//
	//--------------------//
	// ANTI-FREEZE SYSTEM //
	// If too many loop, display some infos
	if(antiFreezeCounter > 10)
	{
/*
		nlwarning("CH:setAnim:anitFreeze:%d: Automaton '%s'",           _Slot, _CurrentAutomaton.c_str());
		nlwarning("CH:setAnim:anitFreeze:%d: _IsThereAMode '%s'",       _Slot, _IsThereAMode?"true":"false");
		nlwarning("CH:setAnim:anitFreeze:%d: dist2Dest '%f'",           _Slot, dist2Dest());
		nlwarning("CH:setAnim:anitFreeze:%d: Mode '%s(%d)'",            _Slot, modeToString(_Mode).c_str(), _Mode);
		nlwarning("CH:setAnim:anitFreeze:%d: Mode Wanted '%s(%d)'",     _Slot, modeToString(_ModeWanted).c_str(), _ModeWanted);
		nlwarning("CH:setAnim:anitFreeze:%d: Anim State Move '%s(%d)'", _Slot, CAnimationStateSheet::getAnimationStateName(animState(MOVE)).c_str(), animState(MOVE));
*/
		// Once too many more time reached, leave the method.
		if(antiFreezeCounter > 20)
			return;
	}
	// Update antiFreezeCounter.
	++antiFreezeCounter;
	// ANTI-FREEZE SYSTEM //
	//--------------------//
	//--------------------//
	// Is there a mode in the queue
//	if(_IsThereAMode && (dist2Dest()==INVALID_DIST))
	{
		// Is the current mode not already the mode wanted.
		if((_Mode != _ModeWanted) && (dist2Dest()==INVALID_DIST))
		{
			TAnimStateKey transition;
			// Check Default Mode Connection.
			if(curAnimState.getModeConnection(_ModeWanted, transition))
			{
				// Mode Mount need to be synchro
				if(_ModeWanted == MBEHAV::MOUNT_NORMAL || _ModeWanted == MBEHAV::MOUNT_SWIM)
				{
					// The Mount
					if(_Rider != CLFECOMMON::INVALID_SLOT)
					{
						if(animationStateKey(MOVE, transition))
							goto KeyChosen;
						else
							nlwarning("CH:setAnim:%d: Mode Wanted '%d' : automaton '%s': state '%s': Transition '%s' is not valid.", _Slot, _ModeWanted, _CurrentAutomaton.c_str(), CAnimationState::getAnimationStateName (curAnimState.MoveState).c_str(), CAnimationState::getAnimationStateName (transition).c_str());
					}
					// The Rider
					else if(_Mount != CLFECOMMON::INVALID_SLOT)
					{
						CEntityCL *mountTmp = EntitiesMngr.entity(_Mount);
						CCharacterCL *mount = dynamic_cast<CCharacterCL *>(mountTmp);
						if(mount)
						{
							if(mountTmp->mode() == _ModeWanted)
							{
								if(animationStateKey(MOVE, transition))
									goto KeyChosen;
								else
								{
									nlwarning("CH:setAnim:%d: automaton '%s': state '%s': MountDefaultModeTransition '%s' is not valid.", _Slot, _CurrentAutomaton.c_str(), CAnimationState::getAnimationStateName (curAnimState.MoveState).c_str(), CAnimationState::getAnimationStateName (transition).c_str());
								}
							}
						}
						else
						{
							nlwarning("CH:setAnim:%d: Mode Wanted '%s' but the mount does not exist.", _Slot, MBEHAV::modeToString(_ModeWanted).c_str());
						}
					}
				}
				// Other modes have the same code.
				else
				{
					if(animationStateKey(MOVE, transition))
						goto KeyChosen;
					else
						nlwarning("CH:setAnim:%d: Mode Wanted '%d' : automaton '%s': state '%s': Transition '%s' is not valid.", _Slot, _ModeWanted, _CurrentAutomaton.c_str(), CAnimationState::getAnimationStateName (curAnimState.MoveState).c_str(), CAnimationState::getAnimationStateName (transition).c_str());
				}
			}
		}
	}


	// Should we stop the animation once at destination.
	if(curAnimState.BrkAtDest && (dist2Dest() <= ClientCfg.DestThreshold))
	{
		_MaxLoop = false;
		if(animationStateKey(MOVE, CAnimationStateSheet::Idle))
			goto KeyChosen;
		else
			nlwarning("CH:setAnim:%d: automaton '%s': state '%s': BrkAtDest 'idle' is not valid.", _Slot, _CurrentAutomaton.c_str(), CAnimationState::getAnimationStateName (curAnimState.MoveState).c_str());
	}

	// On Move
	switch(onMove(curAnimState))
	{
	// On Move Forward
	case OnMoveForward:
		if(animationStateKey(MOVE, curAnimState.OnMoveForward))
			goto KeyChosen;
		else
			nlwarning("CH::setAnim:%d: automaton '%s': state '%s': OnMoveForeward '%s' is not valid.", _Slot, _CurrentAutomaton.c_str(), CAnimationState::getAnimationStateName(curAnimState.MoveState).c_str(), CAnimationState::getAnimationStateName(curAnimState.OnMoveForward).c_str());
		break;
	// On Move Backward
	case OnMoveBackward:
		if(animationStateKey(MOVE, curAnimState.OnMoveBackward))
			goto KeyChosen;
		else
			nlwarning("CH::setAnim:%d: automaton '%s': state '%s': OnMoveBackward '%s' is not valid.", _Slot, _CurrentAutomaton.c_str(), CAnimationState::getAnimationStateName(curAnimState.MoveState).c_str(), CAnimationState::getAnimationStateName(curAnimState.OnMoveBackward).c_str());
		break;
	// On Move Left
	case OnMoveLeft:
		if(animationStateKey(MOVE, curAnimState.OnMoveLeft))
			goto KeyChosen;
		else
			nlwarning("CH::setAnim:%d: automaton '%s': state '%s': OnMoveLeft '%s' is not valid.",     _Slot, _CurrentAutomaton.c_str(), CAnimationState::getAnimationStateName(curAnimState.MoveState).c_str(), CAnimationState::getAnimationStateName(curAnimState.OnMoveLeft).c_str());
		break;
	// On Move Right
	case OnMoveRight:
		if(animationStateKey(MOVE, curAnimState.OnMoveRight))
			goto KeyChosen;
		else
			nlwarning("CH::setAnim:%d: automaton '%s': state '%s': OnMoveRight '%s' is not valid.",    _Slot, _CurrentAutomaton.c_str(), CAnimationState::getAnimationStateName(curAnimState.MoveState).c_str(), CAnimationState::getAnimationStateName(curAnimState.OnMoveRight).c_str());
		break;
	default:
		break;
	}

	// On Rotation/About Face
	CVector dirEndA(0.0f, 0.0f, 0.0f);
	switch(onRotation(curAnimState, dirEndA))
	{
	// On Rot Left
	case OnRotLeft:
		if(animationStateKey(MOVE, curAnimState.OnLeftRotation))
		{
			dirEndAnim(dirEndA);
			goto KeyChosen;
		}
		else
			nlwarning("CH::setAnim:%d: automaton '%s': state '%s': OnLeftRotation '%s' is not valid.",     _Slot, _CurrentAutomaton.c_str(), CAnimationState::getAnimationStateName(curAnimState.MoveState).c_str(), CAnimationState::getAnimationStateName(curAnimState.OnLeftRotation).c_str());
		break;
	// On Rot Right
	case OnRotRight:
		if(animationStateKey(MOVE, curAnimState.OnRightRotation))
		{
			dirEndAnim(dirEndA);
			goto KeyChosen;
		}
		else
			nlwarning("CH::setAnim:%d: automaton '%s': state '%s': OnRightRotation '%s' is not valid.",    _Slot, _CurrentAutomaton.c_str(), CAnimationState::getAnimationStateName(curAnimState.MoveState).c_str(), CAnimationState::getAnimationStateName(curAnimState.OnRightRotation).c_str());
		break;
	default:
		break;
	}

	// Max Loop
	if(curAnimState.MaxLoop && curAnimState.MaxLoop<=_NbLoopAnim)
	{
		if(animationStateKey(MOVE, CAnimationStateSheet::Idle))
		{
			_MaxLoop = true;
			_NbLoopAnim = 0;
			goto KeyChosen;
		}
	}

	// On Bad Heading
	if(onBadHeading(curAnimState))
	{
		if(animationStateKey(MOVE, CAnimationStateSheet::Idle))
			goto KeyChosen;
		else
			nlwarning("CH::setAnim:%d: automaton '%s': state '%s': 'Idle' is not valid.",    _Slot, _CurrentAutomaton.c_str(), CAnimationState::getAnimationStateName(curAnimState.MoveState).c_str());
	}

	// On Big Bend
	switch(onBigBend(curAnimState, dirEndA))
	{
		// On Bend Left
	case OnBendLeft:
		if(animationStateKey(MOVE, curAnimState.OnBigBendLeft))
		{
			dirEndAnim(dirEndA);
			goto KeyChosen;
		}
		else
			nlwarning("CH::setAnim:%d: automaton '%s': state '%s': OnBigBendLeft '%s' is not valid.",     _Slot, _CurrentAutomaton.c_str(), CAnimationState::getAnimationStateName(curAnimState.MoveState).c_str(), CAnimationState::getAnimationStateName(curAnimState.OnBigBendLeft).c_str());
		break;
		// On Bend Right
	case OnBendRight:
		if(animationStateKey(MOVE, curAnimState.OnBigBendRight))
		{
			dirEndAnim(dirEndA);
			goto KeyChosen;
		}
		else
			nlwarning("CH::setAnim:%d: automaton '%s': state '%s': OnBigBendRight '%s' is not valid.",    _Slot, _CurrentAutomaton.c_str(), CAnimationState::getAnimationStateName(curAnimState.MoveState).c_str(), CAnimationState::getAnimationStateName(curAnimState.OnBigBendRight).c_str());
		break;
	default:
		break;
	}

	// If the animation change according to a high speed and speed high enough or oo.
	if(ClientCfg.BlendForward == false)
	{
		if(curAnimState.OnMaxSpeed.Breakable)
		{
			if(speedToDest >= _CurrentAnimSet[MOVE]->speedToRun() ||  speedToDest == -1.0)
			{
				if(animationStateKey(MOVE, curAnimState.OnMaxSpeed.NextStateKey))
					goto KeyChosen;
				else
					nlwarning("CH::setAnim: Char '%d': automaton '%s': state '%s': OnMaxSpeed.NextStateKey '%s' is not valid.", _Slot, _CurrentAutomaton.c_str(), CAnimationState::getAnimationStateName (curAnimState.MoveState).c_str(), CAnimationState::getAnimationStateName (curAnimState.OnMaxSpeed.NextStateKey).c_str());
			}
		}
	}

	// If the animation can change with a low speed.
	if(curAnimState.OnMinSpeed.Breakable)
	{
		// If the speed is low enough (check this is not -1 (infinite speed)) -> update the animation to play.
		if(speedToDest != -1.0 && speedToDest <= _CurrentAnimSet[MOVE]->speedToWalk())
		{
			if(animationStateKey(MOVE, curAnimState.OnMinSpeed.NextStateKey))
				goto KeyChosen;
			else
				 nlwarning("CH::setAnim: Char '%d': automaton '%s': state '%s': OnMinSpeed.NextStateKey '%s' is not valid.", _Slot, _CurrentAutomaton.c_str(), CAnimationState::getAnimationStateName (curAnimState.MoveState).c_str(), CAnimationState::getAnimationStateName (curAnimState.OnMinSpeed.NextStateKey).c_str());
		}
	}
	//// END LOOP /////


	// \todo GUIGUI : better manage automate change
	// Current animation is not of the same kind as the old one.
	bool sameAnim = lastAnimStateId == animState(MOVE) && _OldAutomaton == _CurrentAutomaton;
	if(!sameAnim)
	{
		// Stop FXs.
		stopItemAttackFXs();
		stopAttachedFXForCurrrentAnim(true); // stop all anim fx, including looping fxs
	}
	else
	{
		stopAttachedFXForCurrrentAnim(false); // stop all anim fxs, but do not stop looping fxs (because the same anim is repeating)
	}

	// Compute the current animation state.
	_CurrentState = EAM->mState(_CurrentAutomaton, animState(MOVE));
	// If the state does not exist.
	if(_CurrentState == 0)
	{
		nlwarning("CH:setAnim:%d: State '%s' not in the automaton '%s'.", _Slot, CAnimationStateSheet::getAnimationStateName (animState(MOVE)).c_str(), _CurrentAutomaton.c_str());

		// No animation playing
		if(_PlayList)
			_PlayList->setAnimation(MOVE, UPlayList::empty);
	}
	// The state is valid.
	else
	{
		double angToDest = 0.0;
		// If the new state is a rotation.
		if(_CurrentState->Rotation)
			angToDest = computeShortestAngle(atan2(dir().y, dir().x), atan2(dirEndAnim().y, dirEndAnim().x));
		// Get the right animation state and choose an animation.
		{
			// Get the animation state
			const CAnimationState *animationState = 0;
			if(animState(MOVE) == CAnimationStateSheet::Emote)
			{
				_SubStateKey = subKey;
				animationState = _CurrentAnimSet[MOVE]->getAnimationState(_SubStateKey);
			}
			else
				animationState = _CurrentAnimSet[MOVE]->getAnimationState(animState(MOVE));
			if(animationState)
			{
				// Choose the animation
				CAnimation::TAnimId index;
				if(sameAnim)
					index = buIndex;
				else
					index = CAnimation::UnknownAnim;
				animIndex(MOVE, animationState->chooseAnim(_AnimJobSpecialisation, people(), getGender(), angToDest, index));
				if(animID != NL3D::UAnimationSet::NotFound)
					animId(MOVE, animID);


				// Should the objects in hands be displayed ?
				_ObjectsVisible = animationState->areObjectsVisible();
				showOrHideBodyParts( _ObjectsVisible );

				// in case of user manage the internal view
				if( isUser() )
				{
					UserEntity->updateVisualDisplay();
				}
			}
		}
		// Initialize the animation
		if(animIndex(MOVE) != CAnimation::UnknownAnim)
		{
			// If the new state is a rotation.
			if(_CurrentState->Rotation)
			{
				// Get the animation rotation.
				double animAngle = CAnimationMisc::getAnimationRotation(EAM->getAnimationSet(), animId(MOVE));
				// Compute the rotation factor.
				if(animAngle != 0.0)
					_RotationFactor = fabs(angToDest/animAngle);
				else
					_RotationFactor = -1.0;	// \todo GUIGUI : see which value we should use if we have a rot anim without rot and which should rotate character
			}

			// If the animation is an atk or forage extraction -> Start all dynamic FXs.
			if (_CurrentBehaviour.Behaviour == MBEHAV::EXTRACTING)
			{
				// True Extract Animation only for Use AnimationState type
				// \todo yoyo: ugly?
				if( animState(MOVE)==CAnimationStateSheet::UseLoop )
				{
					_Items[SLOTTYPE::RIGHT_HAND_SLOT].setTrailSize(_CurrentBehaviour.ForageExtraction.Level);
					startItemAttackFXs(true, 1);
				}
			}
			else if (_CurrentState->Attack)
			{
				if(_CurrentBehaviour.Behaviour == MBEHAV::RANGE_ATTACK)
				{
					startItemAttackFXs(_CurrentBehaviour.Range.ImpactIntensity != 0, _CurrentBehaviour.Range.ImpactIntensity);
				}
				else
				{
					startItemAttackFXs(_CurrentBehaviour.Combat.ImpactIntensity != 0 && _CurrentBehaviour.Combat.HitType != HITTYPE::Failed, _CurrentBehaviour.Combat.ImpactIntensity);
				}
			}


			// Initialize the new animation.
			if(_PlayList)
			{
				// Blend the last animation and the new one.
				if(ClientCfg.BlendFrameNumber && _BlendRemaining <= 0								// Blend On ?
				&& animIndex(ACTION) != CAnimation::UnknownAnim										// Last Animation Valid ?
				&& ((lastAnimStateId != animState(MOVE)) || (_OldAutomaton != _CurrentAutomaton)
				   || (animState(MOVE) == CAnimationStateSheet::Emote))	// Last anim != or automaton != ?
				&& !isRiding())											// No Blend on a mount. \todo GUIGUI trouver un meilleur moyen.
				{
					// Get the rotation of the last animation for the blend.
					if(!_Skeleton.empty())
						_OldRotQuat = _Skeleton.getRotQuat();
					_BlendRemaining = ClientCfg.BlendFrameNumber;
					// Set animation
					_PlayList->setAnimation(ACTION, animId(ACTION));
					// Compute weight step.
					float w = 1.f/((float)(ClientCfg.BlendFrameNumber+1));
					// Set Old Anim Weight.
					_PlayList->setWeight(ACTION, 1.f-w);
					// Set New Anim Weight.
					_PlayList->setWeight(MOVE, w);
					// Copy Reverse
					_AnimReversed[ACTION] = _AnimReversed[MOVE];
				}
				// Set Animation.
				_PlayList->setAnimation (MOVE, animId(MOVE));
				// Blend between Walk and Run.
				if(ClientCfg.BlendForward && (animState(MOVE) == CAnimationStateSheet::Walk))
				{
					_CurrentAnimSet[MOVE_BLEND_OUT] = _CurrentAnimSet[MOVE];
					animState(MOVE_BLEND_OUT, CAnimationStateSheet::Run);
					const CAnimationState *animationBlendState = _CurrentAnimSet[MOVE_BLEND_OUT]->getAnimationState(animState(MOVE_BLEND_OUT));
					if(animationBlendState)
					{
						animIndex(MOVE_BLEND_OUT, animationBlendState->chooseAnim(_AnimJobSpecialisation, people(), getGender()));
						_PlayList->setAnimation(MOVE_BLEND_OUT, animId(MOVE_BLEND_OUT));
						_PlayList->setWeight(MOVE_BLEND_OUT, 1.0f);		// \todo GUIGUI : verify what is happening if animId is "empty".
					}
					else
						nlwarning("setAnim:%d: animationBlendState is Null.", _Slot);
				}

				// Set children animation.
				std::list<CEntityCL *>::iterator it = _Children.begin();
				while(it != _Children.end())
				{
					if(*it)
					{
						CCharacterCL *child = dynamic_cast<CCharacterCL *>(*it);
						if(child)
						{
							// Set the Child as the parent.
							child->computeAnimSet();
							child->currentAutomaton() = _CurrentAutomaton;	// \todo GUIGUI : CA VA PAS MARCHER A CAUSE DU TYPE !!!
							child->animOffset(MOVE, animOffset(MOVE));
							child->animState(MOVE, animState(MOVE));
							child->currentState(currentState());
							child->animIndex(MOVE, CAnimation::UnknownAnim);
							const CAnimationState *animStatePtr = child->currentAnimSet()[MOVE]->getAnimationState(child->animState(MOVE));
							if(animStatePtr)
							{
								child->animIndex(MOVE, animStatePtr->chooseAnim(_AnimJobSpecialisation, people(), getGender(), angToDest));
								child->playList()->setAnimation(MOVE, child->animId(MOVE));
							}
							// TEMP : \todo GUIGUI : Pour le moment on enlever le Blend sur les montures.
							{
								child->playList()->setAnimation(ACTION, UPlayList::empty);
								child->currentAnimSet()[ACTION]       = child->currentAnimSet()[MOVE];
								child->animState (ACTION, child->animState (MOVE));
								child->animIndex (ACTION, child->animIndex (MOVE));
								child->animOffset(ACTION, child->animOffset(MOVE));
							}

						}
						else
							nlwarning("CH:setAnim:%d: Child is not a 'CCharacterCL'.", _Slot);
					}
					else
						nlwarning("CH:setAnim:%d: Child not allocated.", _Slot);

					// Next Child
					++it;
				}
			}

			// Get the animation.
			const CAnimationState *animStatePtr = _CurrentAnimSet[MOVE]->getAnimationState((animState(MOVE) ==  CAnimationStateSheet::Emote)?subKey:animState(MOVE));
			if(animStatePtr)
			{
				const CAnimation *anim = animStatePtr->getAnimation(animIndex(MOVE));
				if(anim)
				{
					_HideSkin = anim->hideAtEndAnim();
					// Reverse ?
					_AnimReversed[MOVE] = anim->isReverse();
					// Is the head controlable.
					_TargetAnimCtrl.Enabled = anim->headControlable();
					// Select the sound ID
					_SoundId[MOVE] = anim->soundId();
					// look in behaviour if there's a spell to play
					if (_CurrentAttack)
					{
						if (_CurrentAttackInfo.Intensity >= 1 &&  _CurrentAttackInfo.Intensity <= MAGICFX::NUM_SPELL_POWER)
						{
							MAGICFX::TSpellCastStage attackStage;
							switch(newKey)
							{
								case CAnimationStateSheet::OffensiveCastBegin:
								case CAnimationStateSheet::CurativeCastBegin:
								case CAnimationStateSheet::MixedCastBegin:
								case CAnimationStateSheet::AcidCastInit:
								case CAnimationStateSheet::BlindCastInit:
								case CAnimationStateSheet::ColdCastInit:
								case CAnimationStateSheet::ElecCastInit:
								case CAnimationStateSheet::FearCastInit:
								case CAnimationStateSheet::FireCastInit:
								case CAnimationStateSheet::HealHPCastInit:
								case CAnimationStateSheet::MadCastInit:
								case CAnimationStateSheet::PoisonCastInit:
								case CAnimationStateSheet::RootCastInit:
								case CAnimationStateSheet::RotCastInit:
								case CAnimationStateSheet::ShockCastInit:
								case CAnimationStateSheet::SleepCastInit:
								case CAnimationStateSheet::SlowCastInit:
								case CAnimationStateSheet::StunCastInit:
									attackStage = MAGICFX::CastBegin;
								break;
								case CAnimationStateSheet::OffensiveCastLoop:
								case CAnimationStateSheet::CurativeCastLoop:
								case CAnimationStateSheet::MixedCastLoop:
								case CAnimationStateSheet::AcidCastLoop:
								case CAnimationStateSheet::BlindCastLoop:
								case CAnimationStateSheet::ColdCastLoop:
								case CAnimationStateSheet::ElecCastLoop:
								case CAnimationStateSheet::FearCastLoop:
								case CAnimationStateSheet::FireCastLoop:
								case CAnimationStateSheet::HealHPCastLoop:
								case CAnimationStateSheet::MadCastLoop:
								case CAnimationStateSheet::PoisonCastLoop:
								case CAnimationStateSheet::RootCastLoop:
								case CAnimationStateSheet::RotCastLoop:
								case CAnimationStateSheet::ShockCastLoop:
								case CAnimationStateSheet::SleepCastLoop:
								case CAnimationStateSheet::SlowCastLoop:
								case CAnimationStateSheet::StunCastLoop:
									attackStage = MAGICFX::CastLoop;
								break;
								case CAnimationStateSheet::OffensiveCastSuccess:
								case CAnimationStateSheet::CurativeCastSuccess:
								case CAnimationStateSheet::MixedCastSuccess:
								case CAnimationStateSheet::AcidCastEnd:
								case CAnimationStateSheet::BlindCastEnd:
								case CAnimationStateSheet::ColdCastEnd:
								case CAnimationStateSheet::ElecCastEnd:
								case CAnimationStateSheet::FearCastEnd:
								case CAnimationStateSheet::FireCastEnd:
								case CAnimationStateSheet::HealHPCastEnd:
								case CAnimationStateSheet::MadCastEnd:
								case CAnimationStateSheet::PoisonCastEnd:
								case CAnimationStateSheet::RootCastEnd:
								case CAnimationStateSheet::RotCastEnd:
								case CAnimationStateSheet::ShockCastEnd:
								case CAnimationStateSheet::SleepCastEnd:
								case CAnimationStateSheet::SlowCastEnd:
								case CAnimationStateSheet::StunCastEnd:
									attackStage = MAGICFX::CastEnd;
								break;
								case CAnimationStateSheet::OffensiveCastFail:
								case CAnimationStateSheet::OffensiveCastFumble:
								case CAnimationStateSheet::CurativeCastFail:
								case CAnimationStateSheet::CurativeCastFumble:
								case CAnimationStateSheet::MixedCastFail:
								case CAnimationStateSheet::MixedCastFumble:
								case CAnimationStateSheet::AcidCastFail:
								case CAnimationStateSheet::BlindCastFail:
								case CAnimationStateSheet::ColdCastFail:
								case CAnimationStateSheet::ElecCastFail:
								case CAnimationStateSheet::FearCastFail:
								case CAnimationStateSheet::FireCastFail:
								case CAnimationStateSheet::HealHPCastFail:
								case CAnimationStateSheet::MadCastFail:
								case CAnimationStateSheet::PoisonCastFail:
								case CAnimationStateSheet::RootCastFail:
								case CAnimationStateSheet::RotCastFail:
								case CAnimationStateSheet::ShockCastFail:
								case CAnimationStateSheet::SleepCastFail:
								case CAnimationStateSheet::SlowCastFail:
								case CAnimationStateSheet::StunCastFail:
									attackStage = MAGICFX::CastFail;
								break;
								// attacks
								case CAnimationStateSheet::DefaultAtkLow:
								case CAnimationStateSheet::DefaultAtkMiddle:
								case CAnimationStateSheet::DefaultAtkHigh:
								case CAnimationStateSheet::PowerfulAtkLow:
								case CAnimationStateSheet::PowerfulAtkMiddle:
								case CAnimationStateSheet::PowerfulAtkHigh:
								case CAnimationStateSheet::AreaAtkLow:
								case CAnimationStateSheet::AreaAtkMiddle:
								case CAnimationStateSheet::AreaAtkHigh:
								case CAnimationStateSheet::Attack1:
								case CAnimationStateSheet::Attack2:
								case CAnimationStateSheet::FirstPersonAttack:
									attackStage = MAGICFX::CastEnd;
								break;
								default:
									attackStage = MAGICFX::SpellCastStageCount;
								break;
							}
							const CAnimationFXSet *afs = NULL;
							switch(attackStage)
							{
								case MAGICFX::CastBegin: afs = &_CurrentAttack->AttackBeginFX; break;
								case MAGICFX::CastLoop:  afs = &_CurrentAttack->AttackLoopFX; break;
								case MAGICFX::CastEnd:   afs = &_CurrentAttack->AttackEndFX; break;
								case MAGICFX::CastFail:  afs = &_CurrentAttack->AttackFailFX; break;
								default: break;
							}
							playCastFX(afs, _CurrentAttackInfo.Intensity);
						}
					}
					// start forage prospection anim fx(s)
					if ( (behaviour() == MBEHAV::PROSPECTING) || (behaviour() == MBEHAV::PROSPECTING_END) )
					{
						const CAnimationFXSet& fxSet = anim->getFXSet();
						std::vector<UParticleSystemInstance> fxInstances;
						CAttachedFX::CBuildInfo bi;
						CAttachedFX::CTargeterInfo ti;
						for (uint k = 0; k < fxSet.FX.size(); ++k)
						{
							CAttachedFX::TSmartPtr fx = new CAttachedFX;
							bi.Sheet = &(fxSet.FX[k]);
							fx->create(*this, bi, ti);
							if (!fx->FX.empty())
							{

								attachFXInternal(fx,FXListCurrentAnim);
								if (k == 0)
								{
									// Set user param for size of prospection area
									{
										fx->FX.setUserParam( 0, ((float)(_CurrentBehaviour.ForageProspection.Range)) / 127.0f );
										float up [3];
										switch ( _CurrentBehaviour.ForageProspection.Angle )
										{
										case 0:	up[2] = up[1] = up[0] = 0.0f; break;
										case 1: up[0]=1.0f; up[1]=0.0f; up[2]=0.0f; break;
										case 2: up[0]=1.0f; up[1]=1.0f; up[2]=0.0f; break;
										default: up[0]=1.0f; up[1]=1.0f; up[2]=1.0f; break;
										}
										fx->FX.setUserParam( 1, up[0] );
										fx->FX.setUserParam( 2, up[1] );
										fx->FX.setUserParam( 3, up[2] );
										//nlinfo( "Prospection %s %u %u", behaviour()==MBEHAV::PROSPECTING?"PROSPTG":(behaviour()==MBEHAV::PROSPECTING_END?"PRO_END":"OTHER"), _CurrentBehaviour.ForageProspection.Range, _CurrentBehaviour.ForageProspection.Angle );
									}
								}
								else if (k == 1)
								{
									// Set user param for level of prospection
									float up [4];
									switch ( _CurrentBehaviour.ForageProspection.Level )
									{
									case 0: up[3] = up[2] = up[1] = up[0] = 0.0f; break;
									case 1: up[0]=0.0f; up[1]=1.0f; up[2]=0.0f; up[3]=0.0f; break;
									case 2: up[0]=1.0f; up[1]=1.0f; up[2]=0.0f; up[3]=0.0f; break;
									case 3: up[0]=1.0f; up[1]=1.0f; up[2]=1.0f; up[3]=0.0f; break;
									default: up[3] = up[2] = up[1] = up[0] = 1.0f; break;
									}
									fx->FX.setUserParam( 0, up[0] );
									fx->FX.setUserParam( 1, up[1] );
									fx->FX.setUserParam( 2, up[2] );
									fx->FX.setUserParam( 3, up[3] );
								}
							}
						}
					}
					// start standard anim fx
					else
					{
						CAttachedFX::CBuildInfo bi;
						CAttachedFX::CTargeterInfo ti;
						bi.MaxNumAnimCount = MAX_FX_ANIM_COUNT;
						for (uint k = 0; k < anim->getFXSet().FX.size(); ++k)
						{
							// if the fx is in looping mode, & the anim has already done a loop, then don't recreate it
							if (anim->getFXSet().FX[k].Sheet->RepeatMode == CAnimationFXSheet::Loop && sameAnim) continue;
							CAttachedFX::TSmartPtr fx = new CAttachedFX;
							bi.Sheet = &(anim->getFXSet().FX[k]);
							//bi.StickMode = &bi.Sheet->FX[k].StickMode;
							if (anim->getFXSet().FX[k].Sheet)
							{
								bi.StickMode = &(anim->getFXSet().FX[k].Sheet->StickMode);
							}
							fx->create(*this, bi, ti);
							if (!fx->FX.empty())
							{
								attachFXInternal(fx, FXListAuto);
							}
						}
					}
				}
			}
			else
				nlwarning("CH:setAnim:%d: cannot get the pointer on the animation.", _Slot);
		}
		// No animation found -> check if it is just a transition or is there really an animation missing
		else
		{
			// INFO : Verbose mode for Animations of the selection.
			if(VerboseAnimSelection && _Slot == UserEntity->selection())
				nlinfo("CH:setAnim:%d: Anim Not Found, state '%s'.", _Slot, CAnimationState::getAnimationStateName(animState(MOVE)).c_str());

			// If the next animation or automaton is not the same -> this is a transition -> no animation needed.
			if(_CurrentState->MoveState != _CurrentState->NextState || (_CurrentState->NextMode != _Mode))
			{
				// Choose the next animation.
				endAnimTransition();
			}
			// Else -> Animation Missing.
		}
	}
	// Set the LOD Animation.
	setAnimLOD(((lastAnimStateId != animState(MOVE)) || (_OldAutomaton != _CurrentAutomaton)));
}// setAnim //


//-----------------------------------------------
// playCastFX
//-----------------------------------------------
void CCharacterCL::playCastFX(const CAnimationFXSet *afs, uint power)
{
	if (!afs) return;
	if (power <= 0 || power > 5) return;
	static const float castFXUserParams[MAGICFX::NUM_SPELL_POWER][4] =
	{
		{ 0.f, 0.f, 0.f, 0.f},
		{ 1.f, 0.f, 0.f, 0.f},
		{ 1.f, 1.f, 0.f, 0.f},
		{ 1.f, 1.f, 1.f, 0.f},
		{ 1.f, 1.f, 1.f, 1.f}
	};
	CAttachedFX::CBuildInfo bi;
	CAttachedFX::CTargeterInfo ti;
	for (uint k = 0; k < afs->FX.size(); ++k)
	{
		CAttachedFX::TSmartPtr fx = new CAttachedFX;
		bi.Sheet = &afs->FX[k];
		fx->create(*this, bi, ti);
		if (!fx->FX.empty())
		{
				for(uint l = 0; l < 4; ++l)
				{
					fx->FX.setUserParam(l, castFXUserParams[power - 1][l]);
				}
				attachFXInternal(fx, FXListCurrentAnim);
		}
	}
}


//-----------------------------------------------
// showOrHideBodyParts
//-----------------------------------------------
void CCharacterCL::showOrHideBodyParts( bool objectsVisible )
{
	// UnHide all user body parts.
	for(uint i=0; i<_Instances.size(); ++i)
		if(!_Instances[i].Current.empty())
			_Instances[i].Current.show();

	// hide or show the face
	if( _Items[SLOTTYPE::HEAD_SLOT].Sheet && _Items[SLOTTYPE::HEAD_SLOT].Sheet->Family == ITEMFAMILY::ARMOR )
	{
		// Get the face
		SInstanceCL *face = getFace ();

		// hide if helmet
		if(face)
		{
			if(!face->Current.empty())
				face->Current.hide();
			else
				face->KeepHiddenWhenLoaded = true;
		}
	}
	else
	{
		// Get the face
		SInstanceCL *face = getFace ();

		// hide if helmet
		if(face)
		{
			if(!face->Current.empty())
				face->Current.show();
			else
				face->KeepHiddenWhenLoaded = false;
		}
	}

	// get the instance index for right hand and left hand
	uint32 rHandInstIdx;
	uint32 lHandInstIdx;
	if( isPlayer() || isUser() )
	{
		rHandInstIdx = SLOTTYPE::RIGHT_HAND_SLOT;
		lHandInstIdx = SLOTTYPE::LEFT_HAND_SLOT;

		// hide gloves(armor) if player has magician amplifier
		if( _Items[rHandInstIdx].Sheet && (_Items[rHandInstIdx].Sheet->ItemType == ITEM_TYPE::MAGICIAN_STAFF) )
		{
			if( !_Instances[SLOTTYPE::HANDS_SLOT].Current.empty() )
				_Instances[SLOTTYPE::HANDS_SLOT].Current.hide();
			else
				_Instances[SLOTTYPE::HANDS_SLOT].KeepHiddenWhenLoaded = true;
		}
	}
	else
	{
		rHandInstIdx = _RHandInstIdx;
		lHandInstIdx = _LHandInstIdx;
	}

	// if not already hidden and need to hide :
	if( !objectsVisible )
	{
		// Right Hand
		if(rHandInstIdx<_Instances.size())
			if( !(_Items[rHandInstIdx].Sheet && _Items[rHandInstIdx].Sheet->NeverHideWhenEquipped ) )
				if(!_Instances[rHandInstIdx].Current.empty())
				{
					_Instances[rHandInstIdx].Current.hide();
					_Instances[rHandInstIdx].hideStaticFXs();
				}
		// Left Hand
		if(lHandInstIdx <_Instances.size())
			if( !(_Items[lHandInstIdx].Sheet && _Items[lHandInstIdx].Sheet->NeverHideWhenEquipped ) )
				if(!_Instances[lHandInstIdx].Current.empty())
				{
					_Instances[lHandInstIdx].Current.hide();
					_Instances[lHandInstIdx].hideStaticFXs();
				}
	}
	else
	{
		// Right Hand
		if(rHandInstIdx<_Instances.size())
			if(!_Instances[rHandInstIdx].Current.empty())
			{
				_Instances[rHandInstIdx].Current.show();
				_Instances[rHandInstIdx].showStaticFXs();
			}
		// Left Hand
		if(lHandInstIdx <_Instances.size())
			if(!_Instances[lHandInstIdx].Current.empty())
			{
				_Instances[lHandInstIdx].Current.show();
				_Instances[lHandInstIdx].showStaticFXs();
			}
	}
}

//-----------------------------------------------
// setAnimLOD :
// Set the LOD animation.
//-----------------------------------------------
ADD_METHOD(void CCharacterCL::setAnimLOD(bool changed))
	// reset LOD animation.
	_LodCharacterAnimEnabled = false;
	// Setup new LOD animation.
	if(skeleton())
	{
		// if the entity has a lod Character
		sint lodId = skeleton()->getLodCharacterShape();
		if(lodId >= 0)
		{
			// Setup Lod anim.
			_LodCharacterAnimEnabled	= true;
			_LodCharacterMasterAnimSlot	= MOVE;
			_LodCharacterAnimTimeOffset	= 0;
			// do complex stuff only if the anim state has really changed.
			if(changed)
			{
				// get the anim state from the set.
				const CAnimationState *animStatePtr = _CurrentAnimSet[MOVE]->getAnimationState(animState(MOVE));
				// if animStatePtr found.
				if(animStatePtr)
				{
					// get Lod Character animation Name from the anim state.
					const string &lodAnimName = animStatePtr->getLodCharacterAnimation();
					// Find the anim in the UScene LodCharacterManager
					sint animId = Scene->getCLodAnimIdByName(lodId, lodAnimName);
					// if Anim not found, get the "idle" anim, with the Id 0.
					if(animId < 0)
						animId = 0;
					// setup the skeleton.
					skeleton()->setLodCharacterAnimId(animId);
				}
			}
		}
	}
}// setAnimLOD //


//-----------------------------------------------
// updateAnimationState :
// \todo GUIGUI : precalculate distance to destination when receiving Stages.
// \todo GUIGUI : improve, we are setting often 'idle' to recompute orientation at the end of animation instead of doing directly the right one.
//-----------------------------------------------
ADD_METHOD(void CCharacterCL::updateAnimationState())
	// If the current state is invalid -> return.
	if(_CurrentState == 0)
		return;

	// Get the Animation Length.
	double animLength = EAM->getAnimationLength(animId(MOVE));
	// Check Anim length
	if(animOffset(MOVE) >= animLength)
	{
		// Choose the next animation.
		endAnimTransition();
	}
	// Last animation not finished check for some chances to break current animation.
	else
	{
		// Check Modes.
//		if(_IsThereAMode && (dist2Dest()==INVALID_DIST))
		{
			// Is the current mode not already the mode wanted.
			if((_Mode != _ModeWanted) && (dist2Dest()==INVALID_DIST))
			{
				if((_ModeWanted != MBEHAV::MOUNT_NORMAL && _ModeWanted != MBEHAV::MOUNT_SWIM) || (_Rider != CLFECOMMON::INVALID_SLOT))
				{
					// Is there a possible connection with the mode wanted.
					TAnimStateKey transition;
					if(_CurrentState->getModeConnection(_ModeWanted, transition))
					{
						setAnim(transition);
						return;
					}
				}
				else
				{
					//InfoLog->displayRawNL("(%d)_Rider=%d  _Mount=%d  _ModeWanted=%s  _Mode=%s  offset=%f  length=%f",_Slot,_Rider,_Mount,MBEHAV::modeToString(_ModeWanted).c_str(),MBEHAV::modeToString(_Mode).c_str(),animOffset(MOVE),animLength);
					// anti-bug : sometimes _rider is not set yet and we stay in an infinite move
					_Rider = _TheoreticalRider;
				}
			}
		}

		// Should we stop the animation once at destination.
		if(_CurrentState->BrkAtDest && dist2Dest() <= ClientCfg.DestThreshold)
		{
			_MaxLoop = false;
			setAnim(CAnimationStateSheet::Idle);
			return;
		}

		// ON MOVE
		switch(onMove(*_CurrentState))
		{
		// On Move Forward
		case OnMoveForward:
			setAnim(_CurrentState->OnMoveForward);
			return;
		// On Move Backward
		case OnMoveBackward:
			setAnim(_CurrentState->OnMoveBackward);
			return;
		// On Move Left
		case OnMoveLeft:
			setAnim(_CurrentState->OnMoveLeft);
			return;
		// On Move Right
		case OnMoveRight:
			setAnim(_CurrentState->OnMoveRight);
			return;
		default:
			break;
		}

		// ON ROTATION
		CVector tmp;
		switch(onRotation(*_CurrentState, tmp))
		{
		// Rotation Left
		case OnRotLeft:
			setAnim(CAnimationStateSheet::Idle);
			return;
		// Rotation Right
		case OnRotRight:
			setAnim(CAnimationStateSheet::Idle);
			return;
		default:
			break;
		}

		// ON BAD HEADING
		if(onBadHeading(*_CurrentState))
		{
			setAnim(CAnimationStateSheet::Idle);
			return;
		}

		// ON BIG BEND
		switch(onBigBend(*_CurrentState, tmp))
		{
		// Big Bend Left and Right
		case OnBendLeft:
		case OnBendRight:
			setAnim(_CurrentState->MoveState);
			return;
		default:
			break;
		}

		// \todo GUIGUI : changer de place cette partie je pense.
		// Adjust the direction to fit the front
		if( !(isUser() && ClientCfg.AutomaticCamera==false) )
		{
			if(_CurrentState->AdjustOri)
			{
				// Adjust before the half of the attack animation.
				const double animL = animLength/2.0;
				// Half already reatch, dir should be as the front now
				if(animOffset(MOVE) > animL)
					dir(front());
				else
				{
					double ang = computeShortestAngle(atan2(dir().y, dir().x), atan2(front().y, front().x));
					if(ang)
					{
						double ang2 = (animOffset(MOVE)/animL)*ang/animL;
						double angleZ = ang2+atan2(dir().y, dir().x);
						dir(CVector((float)cos(angleZ), (float)sin(angleZ), 0.f));
					}
				}
			}
		}
	}
}// updateAnimationState //

//-----------------------------------------------
// computeMotion :
//-----------------------------------------------
ADD_METHOD(double CCharacterCL::computeMotion(const double &oldMovingTimeOffset, TAnimationType channel) const)
	H_AUTO_USE ( RZ_Client_Entity_CL_Update_Pos_Compute_Motion )

	// Check the state is valid.
	if(_CurrentState == 0)
		return 0.0;

	// Calculate movement for given animation segment.
	if(_CurrentState->Move)
	{
		// Animation is unknown, no move in it.
		if(animIndex(channel) == CAnimation::UnknownAnim)
			return 0.0;

		CVector	oldPos, newPos;
		uint animID = animId(channel);
		if(EAM->interpolate(animID, oldMovingTimeOffset, oldPos))
		{
			if(EAM->interpolate(animID, animOffset(channel), newPos))
			{
				CVector mov = newPos - oldPos;
				// Scale it by the CharacterScalePos, if needed, according to the animation.
				bool mustApplyCharacterScalePosFactor = true;
				const CAnimationState *animStatePtr = _CurrentAnimSet[channel]->getAnimationState(animState(channel));
				if(animStatePtr)
				{
					const CAnimation *anim = animStatePtr->getAnimation(animIndex(channel));
					if(anim)
						mustApplyCharacterScalePosFactor = anim->applyCharacterScalePosFactor();
				}
				// scale it according to the species.
				if(mustApplyCharacterScalePosFactor)
					mov*= _CharacterScalePos;
				// Scale according to the gabarit.
				mov *= _CustomScalePos;
				// Return a significant move.
				double distDone = mov.norm();
				if(distDone>0.0 && distDone<ClientCfg.SignificantDist)
					distDone = ClientCfg.SignificantDist;
				return distDone;
			}
		}

		// Miss the position's track.
		nlwarning("CCharacterCL::computeMotion : Animation should have a track for the position.");
		return 0.0;
	}
	// The animation is not one to move.
	else
		return 0.0;
}// computeMotion //

//-----------------------------------------------
// beginCast :
//-----------------------------------------------
void CCharacterCL::beginCast(const MBEHAV::CBehaviour &behaviour)
{
	// if the player has a target, force him to face this target
	CEntityCL *target = EntitiesMngr.entity(targetSlot());
	if(target && !target->isUser() )
	{
		CVectorD dirToTarget = target->pos() - pos();
		dirToTarget.z = 0;
		dirToTarget.normalize();
		front( dirToTarget );
		dir( dirToTarget );
	}

	switch(behaviour.Behaviour)
	{
	////////////////
	// BEGIN CAST //
	// OFFENSIVE CAST BEGIN
	case MBEHAV::CAST_OFF:
		setAnim(CAnimationStateSheet::OffensiveCastInit);
		break;
	// CURATIVE CAST BEGIN
	case MBEHAV::CAST_CUR:
		setAnim(CAnimationStateSheet::CurativeCastInit);
		break;
	// MIXED CAST BEGIN
	case MBEHAV::CAST_MIX:
		setAnim(CAnimationStateSheet::MixedCastInit);
		break;
	// IDLE
	case MBEHAV::IDLE:
		setAnim(CAnimationStateSheet::Idle);
		break;
	//
	case MBEHAV::CAST_ACID:
		setAnim(CAnimationStateSheet::AcidCastInit);
		break;
	case MBEHAV::CAST_BLIND:
		setAnim(CAnimationStateSheet::BlindCastInit);
		break;
	case MBEHAV::CAST_COLD:
		setAnim(CAnimationStateSheet::ColdCastInit);
		break;
	case MBEHAV::CAST_ELEC:
		setAnim(CAnimationStateSheet::ElecCastInit);
		break;
	case MBEHAV::CAST_FEAR:
		setAnim(CAnimationStateSheet::FearCastInit);
		break;
	case MBEHAV::CAST_FIRE:
		setAnim(CAnimationStateSheet::FireCastInit);
		break;
	case MBEHAV::CAST_HEALHP:
		setAnim(CAnimationStateSheet::HealHPCastInit);
		break;
	case MBEHAV::CAST_MAD:
		setAnim(CAnimationStateSheet::MadCastInit);
		break;
	case MBEHAV::CAST_POISON:
		setAnim(CAnimationStateSheet::PoisonCastInit);
		break;
	case MBEHAV::CAST_ROOT:
		setAnim(CAnimationStateSheet::RootCastInit);
		break;
	case MBEHAV::CAST_ROT:
		setAnim(CAnimationStateSheet::RotCastInit);
		break;
	case MBEHAV::CAST_SHOCK:
		setAnim(CAnimationStateSheet::ShockCastInit);
		break;
	case MBEHAV::CAST_SLEEP:
		setAnim(CAnimationStateSheet::SleepCastInit);
		break;
	case MBEHAV::CAST_SLOW:
		setAnim(CAnimationStateSheet::SlowCastInit);
		break;
	case MBEHAV::CAST_STUN:
		setAnim(CAnimationStateSheet::StunCastInit);
		break;
	default:
		break;
	}
}// beginCast //

//-----------------------------------------------
// endCast :
//-----------------------------------------------
void CCharacterCL::endCast(const MBEHAV::CBehaviour &behaviour, const MBEHAV::CBehaviour &lastBehaviour)
{
	if( !(isUser() && isSit()) )
	{
		switch(lastBehaviour.Behaviour)
		{
		case MBEHAV::CAST_ACID:
			setAnim(CAnimationStateSheet::AcidCastEnd);
			break;
		case MBEHAV::CAST_BLIND:
			setAnim(CAnimationStateSheet::BlindCastEnd);
			break;
		case MBEHAV::CAST_COLD:
			setAnim(CAnimationStateSheet::ColdCastEnd);
			break;
		case MBEHAV::CAST_ELEC:
			setAnim(CAnimationStateSheet::ElecCastEnd);
			break;
		case MBEHAV::CAST_FEAR:
			setAnim(CAnimationStateSheet::FearCastEnd);
			break;
		case MBEHAV::CAST_FIRE:
			setAnim(CAnimationStateSheet::FireCastEnd);
			break;
		case MBEHAV::CAST_HEALHP:
			setAnim(CAnimationStateSheet::HealHPCastEnd);
			break;
		case MBEHAV::CAST_MAD:
			setAnim(CAnimationStateSheet::MadCastEnd);
			break;
		case MBEHAV::CAST_POISON:
			setAnim(CAnimationStateSheet::PoisonCastEnd);
			break;
		case MBEHAV::CAST_ROOT:
			setAnim(CAnimationStateSheet::RootCastEnd);
			break;
		case MBEHAV::CAST_ROT:
			setAnim(CAnimationStateSheet::RotCastEnd);
			break;
		case MBEHAV::CAST_SHOCK:
			setAnim(CAnimationStateSheet::ShockCastEnd);
			break;
		case MBEHAV::CAST_SLEEP:
			setAnim(CAnimationStateSheet::SleepCastEnd);
			break;
		case MBEHAV::CAST_SLOW:
			setAnim(CAnimationStateSheet::SlowCastEnd);
			break;
		case MBEHAV::CAST_STUN:
			setAnim(CAnimationStateSheet::StunCastEnd);
			break;
		case MBEHAV::IDLE:
			setAnim(CAnimationStateSheet::Idle);
			break;
		// Old One
		default:
			{
				switch(behaviour.Behaviour)
				{
					//////////////
					// END CAST //
					// OFFENSIVE CAST END
				case MBEHAV::CAST_OFF_FAIL:
					setAnim(CAnimationStateSheet::OffensiveCastFail);
					break;
				case MBEHAV::CAST_OFF_FUMBLE:
					setAnim(CAnimationStateSheet::OffensiveCastFumble);
					break;
				case MBEHAV::CAST_OFF_SUCCESS:
					setAnim(CAnimationStateSheet::OffensiveCastSuccess);
					break;
				case MBEHAV::CAST_OFF_LINK:
					setAnim(CAnimationStateSheet::OffensiveCastLink);
					break;
					// CURATIVE CAST END
				case MBEHAV::CAST_CUR_FAIL:
					setAnim(CAnimationStateSheet::CurativeCastFail);
					break;
				case MBEHAV::CAST_CUR_FUMBLE:
					setAnim(CAnimationStateSheet::CurativeCastFumble);
					break;
				case MBEHAV::CAST_CUR_SUCCESS:
					setAnim(CAnimationStateSheet::CurativeCastSuccess);
					break;
				case MBEHAV::CAST_CUR_LINK:
					setAnim(CAnimationStateSheet::CurativeCastLink);
					break;
					// MIXED CAST END
				case MBEHAV::CAST_MIX_FAIL:
					setAnim(CAnimationStateSheet::MixedCastFail);
					break;
				case MBEHAV::CAST_MIX_FUMBLE:
					setAnim(CAnimationStateSheet::MixedCastFumble);
					break;
				case MBEHAV::CAST_MIX_SUCCESS:
					setAnim(CAnimationStateSheet::MixedCastSuccess);
					break;
				case MBEHAV::CAST_MIX_LINK:
					setAnim(CAnimationStateSheet::MixedCastLink);
					break;
				default:
					break;
				}
			}
			break;
		}
	}
}// endCast //


// *************************************************************************************************
void CCharacterCL::updateCurrentAttack()
{
	// This is a behaviour for the magic.
	if(_CurrentBehaviour.isMagic())
	{
		_CurrentAttackID.Type = CAttackIDSheet::Magic;
		_CurrentAttackID.SpellInfo.Mode = (MAGICFX::TSpellMode) _CurrentBehaviour.Spell.SpellMode;
		_CurrentAttackID.SpellInfo.ID = (MAGICFX::TMagicFx) _CurrentBehaviour.Spell.SpellId;
	}
	// This is a behaviour for the combat.
	else if(_CurrentBehaviour.Behaviour == MBEHAV::RANGE_ATTACK)
	{
		_CurrentAttackID.Type = CAttackIDSheet::Range;
		_CurrentAttackID.RangeWeaponType = (RANGE_WEAPON_TYPE::TRangeWeaponType) _CurrentBehaviour.Range.WeaponType;
	}
	else if (_CurrentBehaviour.isCombat())
	{
		_CurrentAttackID.Type = CAttackIDSheet::Melee;
	}
	else if (_CurrentBehaviour.isCreatureAttack())
	{
		_CurrentAttackID.Type = CAttackIDSheet::Creature;
		_CurrentAttackID.CreatureAttackIndex = _CurrentBehaviour.Behaviour == MBEHAV::CREATURE_ATTACK_0 ? 0 : 1;
	}
	else
	{
		// the behaviour does not generate an attack
		_CurrentAttack = NULL;
		_CurrentAttackID.Type = CAttackIDSheet::Unknown;
		return;
	}
	_CurrentAttack = getAttack(_CurrentAttackID);
	// update current attack infos
	if(_CurrentBehaviour.isMagic())
	{
		_CurrentAttackInfo.Intensity = _CurrentBehaviour.Spell.SpellIntensity;
		// physical damge are irrelevant for magic
		_CurrentAttackInfo.DamageType = DMGTYPE::UNDEFINED;
		_CurrentAttackInfo.HitType = HITTYPE::Undefined;
		_CurrentAttackInfo.Localisation = BODY::UnknownBodyPart;
		_CurrentAttackInfo.PhysicalImpactIntensity = 0;
	}
	// This is a behaviour for the combat.
	else if(_CurrentBehaviour.Behaviour == MBEHAV::RANGE_ATTACK)
	{
		_CurrentAttackInfo.Intensity = _CurrentBehaviour.Range.ImpactIntensity;
		_CurrentAttackInfo.DamageType = DMGTYPE::UNDEFINED;
		_CurrentAttackInfo.HitType = HITTYPE::Undefined;
		_CurrentAttackInfo.Localisation = (BODY::TBodyPart) _CurrentBehaviour.Range.Localisation;
		_CurrentAttackInfo.PhysicalImpactIntensity = 0;
	}
	else if (_CurrentBehaviour.isCombat())
	{
		_CurrentAttackInfo.Intensity = _CurrentBehaviour.Combat.ImpactIntensity;
		_CurrentAttackInfo.DamageType = (DMGTYPE::EDamageType) _CurrentBehaviour.Combat2.DamageType;
		_CurrentAttackInfo.HitType = (HITTYPE::THitType) _CurrentBehaviour.Combat.HitType;
		_CurrentAttackInfo.Localisation = (BODY::TBodyPart) _CurrentBehaviour.Combat.Localisation;
		_CurrentAttackInfo.PhysicalImpactIntensity = _CurrentBehaviour.Combat.ImpactIntensity;
	}
	else if (_CurrentBehaviour.isCreatureAttack())
	{
		// creature attack is the most general form
		_CurrentAttackInfo.Intensity = _CurrentBehaviour.CreatureAttack.MagicImpactIntensity;
		_CurrentAttackInfo.DamageType = (DMGTYPE::EDamageType) _CurrentBehaviour.CreatureAttack2.DamageType;
		_CurrentAttackInfo.HitType = (HITTYPE::THitType) _CurrentBehaviour.CreatureAttack2.HitType;
		_CurrentAttackInfo.Localisation = (BODY::TBodyPart) _CurrentBehaviour.CreatureAttack.Localisation;
		_CurrentAttackInfo.PhysicalImpactIntensity = _CurrentBehaviour.CreatureAttack.ImpactIntensity;
	}
	_CurrentAttackInfo.Side = (rand() & 1) ? BODY::Left : BODY::Right;
}


// utility function for performCurrentAttackEnd
inline static void getResistAndDistance(uint8 packedInfo, bool isDirectAttack, bool isCombat, bool &resist, uint &distance)
{
	// get the distance from attacker to defender (consider 0 if a direct attack)
	if (isDirectAttack)
		distance = 0;
	else
		distance = packedInfo & 127;
	// resisted?
	if(isCombat)
		resist= false;
	else
		resist = (packedInfo & 128) != 0;
}

// *********************************************************************************************
void CCharacterCL::performCurrentAttackEnd(const CBehaviourContext &bc, bool directOffensifSpell, vector<double> &targetHitDates, TAnimStateKey animForCombat)
{
	if (!_CurrentAttack) return;
	if (!_CurrentAttack->Sheet) return;
	if (bc.Targets.Targets.empty())
	{
		nlwarning ("No target available for current attack.");
		return;
	}
	nlassert(targetHitDates.size() == bc.Targets.Targets.size());

	CAttackInfo attackInfo = _CurrentAttackInfo;

	const CAttackSheet &sheet = *_CurrentAttack->Sheet;


	// should cast FX for static Objects like towers be used ?
	bool usesStaticCastFX = _Sheet && !_Sheet->ProjectileCastRay.empty();

	CProjectileBuild pb;


	// ray of cast for static object with several cast points
	CVector castWorldOrigin;
	CVector castWorldPos;
	CVector additionnalOffset = NLMISC::CVector::Null;
	bool castRayValid = false;
	uint mainCastFXIntensity = attackInfo.Intensity;


	// *** Compute castStartTime (time at which the projectile is casted)

	// *** Compute castStartTime (time at which the projectile is casted)

	float delay = 0.f; // by default, no delay before impact
	double timeFactor = 1;

	// Combat (range or melee) => no resist (yoyo: legacy code. Actually the server should set the resist bit to 0 in Target.Info)
	bool isCombat= _CurrentBehaviour.isCombat();

	// An attack is said 'direct' when no projectile is casted (Generally those are melee attack, but also pistol range attack for instance)
	// In this case, all targets are hit at the same time, no matter what date is supplied for them.
	bool isDirectAttack = sheet.ProjectileFX.empty();

	if (isDirectAttack)
	{
		///////////////////
		// DIRECT ATTACK //
		///////////////////
		// compute impact date. It is given by the trigger on right hand in the animation
		// Get the current animation id.
		if (sheet.ForceUseProjectileDelay)
		{
			delay = sheet.ProjectileDelay;
		}
		else
		if (!directOffensifSpell)
		{
			if ((_CurrentAttackID.Type != CAttackIDSheet::Range) && (_PlayList != NULL))
			{
				// default
				delay= 0.5f;
				// if the animation has been correctly chosen
				if(animForCombat!=CAnimationStateSheet::UnknownState)
				{
					// try to get the MeleeImpactDelay that is stored in the sheet (given by graphists)
					const CAnimationSet	*animSet= currentAnimSet()[MOVE];
					if(animSet)
					{
						const CAnimationState *animState  = animSet->getAnimationState(animForCombat);
						if(animState)
							delay= animState->getMeleeImpactDelay();
					}
				}
			}
			else
			{
				// see if weapon is known, and in this case, delay the impact by the same amount
				const CItemSheet *sheet = _Items[SLOTTYPE::RIGHT_HAND_SLOT].Sheet;
				if (sheet) delay = sheet->FX.ImpactFXDelay;
			}
		}
		// all target are reached at the same time
		timeFactor = 0;
	}
	else
	{
		// there's a projectile
		if (usesStaticCastFX)
		{
			delay = sheet.StaticObjectProjectileDelay;
		}
		else
		{
			if (!directOffensifSpell)
			{
				// if object has a list of cast rays, then we assume it is a static object (like guard towers)
				// projectile cast from a character
				delay = sheet.ProjectileDelay;
			}
		}
	}

	// then castStartTime is just start of behav + animation delay
	double	castStartTime;
	// Special for direct attack. because of lag sometimes behavTime<TimeInSec, which results
	// on too early played hits regarding animation played
	if(isDirectAttack)
	{
		// start at max(behavTime, TimeInSec), but with a limit of bc.BehavTime+0.5 sec
		if(TimeInSec > bc.BehavTime+0.5)
			castStartTime= bc.BehavTime + 0.5;
		else if(TimeInSec > bc.BehavTime)
			castStartTime= TimeInSec;
		else
			castStartTime= bc.BehavTime;
		// add the delay
		castStartTime+= delay;
	}
	else
	{
		// In case of magic or range (with projectile), this is not required because the projectilemanager should take cares of
		// cast start time and current time (and therfore advance the projectile if required)
		castStartTime= bc.BehavTime + delay;
	}

	// *** Casts projectiles and Impacts
	bool resist;
	uint distance;
	// there's a projectile
	switch(sheet.ProjectileMode)
	{
		// TODO: homin code for projectile look quite similar, maybe can merge ?
		case MAGICFX::Bomb:
		{
			getResistAndDistance(bc.Targets.Targets[0].Info, isDirectAttack, isCombat, resist, distance);
			double mainStartDate = castStartTime;
			double mainEndDate = mainStartDate + timeFactor * double(distance * MULTI_TARGET_DISTANCE_UNIT / MAGICFX::PROJECTILE_SPEED);
			CCharacterCL *mainTarget = dynamic_cast<CCharacterCL *>(EntitiesMngr.entity(bc.Targets.Targets[0].TargetSlot));
			if (mainTarget)
			{
				computeTargetStickMode(*_CurrentAttack->Sheet, attackInfo, pb.ProjectileAimingPoint, *mainTarget);
				if (usesStaticCastFX)
				{
					// compute the cast pos
					computeBestCastRay(*mainTarget, pb.ProjectileAimingPoint, castWorldOrigin, castWorldPos, additionnalOffset);
					castRayValid = true;
				}

				// the target hit date
				targetHitDates[0]= mainEndDate;

				// Add the projectile to queue
				if (createCurrentAttackEndPart(pb,
					                           _CurrentAttack,
											   *mainTarget,
											   NULL,
											   mainStartDate,
											   mainEndDate,
											   true,
											   sheet.PlayImpactAnim,
											   resist,
											   sheet.IsImpactLocalised,
											   attackInfo,
											   additionnalOffset
											  ))
				{
					CProjectileManager::getInstance().addProjectileToQueue(pb);

				}
				attackInfo.Intensity = attackInfo.Intensity != 0 ? 1 : 0;
				attackInfo.PhysicalImpactIntensity =  attackInfo.PhysicalImpactIntensity != 0 ? 1 : 0;
				// all subsequent projectiles are casted from the secondary target, from the first impact point, and have level 1
				for(uint k = 1; k < bc.Targets.Targets.size(); ++k)
				{
					getResistAndDistance(bc.Targets.Targets[k].Info, isDirectAttack, isCombat, resist, distance);
					double secondaryEndDate = mainEndDate + timeFactor * ((double) (distance * MULTI_TARGET_DISTANCE_UNIT / MAGICFX::PROJECTILE_SPEED));
					CCharacterCL *secondaryTarget = dynamic_cast<CCharacterCL *>(EntitiesMngr.entity(bc.Targets.Targets[k].TargetSlot));
					if (secondaryTarget)
					{
						// the target hit date
						targetHitDates[k]= secondaryEndDate;

						// Add the projectile to queue
						if (mainTarget->createCurrentAttackEndPart(pb,
							                                       _CurrentAttack,
																   *secondaryTarget,
																   &pb.ProjectileAimingPoint,
																   mainEndDate,
																   secondaryEndDate,
																   k != 0 ? !sheet.PlayImpactFXOnlyOnMainTarget : true,
																   sheet.PlayImpactAnim,
																   resist,
																   sheet.IsImpactLocalised,
																   attackInfo
																  ))
						{
							computeTargetStickMode(*_CurrentAttack->Sheet, attackInfo, pb.ProjectileAimingPoint, *secondaryTarget);
							CProjectileManager::getInstance().addProjectileToQueue(pb);
						}
					}
				}
			}
		}
		break;
		case MAGICFX::Chain:
		{
			double currDate = castStartTime;
			CCharacterCL *currCaster = this;
			const CFXStickMode *projectileStartPoint = NULL; // by default, start at caster hand
			CFXStickMode currStickMode;
			for(uint k = 0; k < bc.Targets.Targets.size(); ++k)
			{
				if (k == 1)
				{
					// for secondary impacts, intensity is 0 or 1
					attackInfo.Intensity = attackInfo.Intensity != 0 ? 1 : 0;
					attackInfo.PhysicalImpactIntensity =  attackInfo.PhysicalImpactIntensity != 0 ? 1 : 0;
				}
				getResistAndDistance(bc.Targets.Targets[k].Info, isDirectAttack, isCombat, resist, distance);
				double nextDate = currDate + timeFactor * ((double) (distance * MULTI_TARGET_DISTANCE_UNIT / MAGICFX::PROJECTILE_SPEED));
				CCharacterCL *currTarget = dynamic_cast<CCharacterCL *>(EntitiesMngr.entity(bc.Targets.Targets[k].TargetSlot));
				if (!currTarget) break;


				computeTargetStickMode(*_CurrentAttack->Sheet, attackInfo, pb.ProjectileAimingPoint, *currTarget);


				if (k == 0 && usesStaticCastFX)
				{
					// compute the initial cast pos for objects with multiple possible cast positions
					computeBestCastRay(*currTarget, pb.ProjectileAimingPoint, castWorldOrigin, castWorldPos, additionnalOffset);
					castRayValid = true;
				}

				// the target hit date
				targetHitDates[k]= nextDate;

				// Add the projectile to queue
				if (currCaster->createCurrentAttackEndPart(pb,
														   _CurrentAttack,
														   *currTarget,
														   projectileStartPoint,
														   currDate,
														   nextDate,
														   k != 0 ? !sheet.PlayImpactFXOnlyOnMainTarget : true,
														   sheet.PlayImpactAnim,
														   resist,
														   sheet.IsImpactLocalised,
														   attackInfo,
														   k == 0 ? additionnalOffset : CVector::Null
														  ))
				{
					CProjectileManager::getInstance().addProjectileToQueue(pb);
				}
				currStickMode = pb.ProjectileAimingPoint;
				projectileStartPoint = &currStickMode;
				currCaster = currTarget;
				if (!currCaster) break;
				currDate = nextDate;
			}
		}
		break;
		case MAGICFX::Spray:
		{
			for(uint k = 0; k < bc.Targets.Targets.size(); ++k)
			{
				getResistAndDistance(bc.Targets.Targets[k].Info, isDirectAttack, isCombat, resist, distance);
				double startDate = castStartTime;
				double endDate = startDate + timeFactor * ((double) (distance * MULTI_TARGET_DISTANCE_UNIT / MAGICFX::PROJECTILE_SPEED));
				CCharacterCL *currTarget = dynamic_cast<CCharacterCL *>(EntitiesMngr.entity(bc.Targets.Targets[k].TargetSlot));
				if (k == 1)
				{
					// for secondary impacts, intensity is 0 or 1
					attackInfo.Intensity = attackInfo.Intensity != 0 ? 1 : 0;
					attackInfo.PhysicalImpactIntensity =  attackInfo.PhysicalImpactIntensity != 0 ? 1 : 0;
				}
				if (currTarget)
				{
					computeTargetStickMode(*_CurrentAttack->Sheet, attackInfo, pb.ProjectileAimingPoint, *currTarget);
					if (k == 0 && usesStaticCastFX)
					{
						// compute the initial cast pos for objects with multiple possible cast positions
						computeBestCastRay(*currTarget, pb.ProjectileAimingPoint, castWorldOrigin, castWorldPos, additionnalOffset);
						castRayValid = true;
					}

					// the target hit date
					targetHitDates[k]= endDate;

					// nb : only main target display the spell with full power
					if (createCurrentAttackEndPart(pb,
						                           _CurrentAttack,
												   *currTarget,
												   NULL,
												   startDate,
												   endDate,
												   k != 0 ? !sheet.PlayImpactFXOnlyOnMainTarget : true,
												   sheet.PlayImpactAnim,
												   resist,
												   sheet.IsImpactLocalised,
												   attackInfo,
												   k == 0 ? additionnalOffset : CVector::Null
												  ))
					{
						CProjectileManager::getInstance().addProjectileToQueue(pb);
					}
				}
			}
		}
		break;
		default:
		break;
	}

	// if object has a list of cast rays, then we assume it is a static object (like guard towers)
	if (usesStaticCastFX && castRayValid)
	{
		buildStaticObjectCastFX(castWorldOrigin, castWorldPos, *_CurrentAttack->Sheet, mainCastFXIntensity);
	}


	// *** Play damage shields when melee attack is done
	/*
	// TODO: to finalize (server code not done).
	if (ClientCfg.DamageShieldEnabled && _CurrentBehaviour.isCombat() && _CurrentBehaviour.todoNotRange())
	{
		for(uint k = 0; k < bc.Targets.Targets.size(); ++k)
		{
			uint power = bc.Targets.Targets[k].Info & 7;
			if (power)
			{
				uint dmType = bc.Targets.Targets[k].Info >> 3;
				//
				CAttackIDSheet damageShieldID;
				damageShieldID.Type = CAttackIDSheet::DamageShield;
				damageShieldID.DamageShieldType = dmType;
				CCharacterCL *currTarget = dynamic_cast<CCharacterCL *>(EntitiesMngr.entity(bc.Targets.Targets[k].TargetSlot));
				if (!currTarget) continue;
				const CAttack *damageShieldReaction = currTarget->getAttack(damageShieldID);
				if (!damageShieldReaction) continue;
				CAttackInfo attackInfo;
				attackInfo.Intensity = power;
				attackInfo.PhysicalImpactIntensity = 0;
				attackInfo.Localisation = BODY::UnknownBodyPart;
				// no physical part
				const CAttackSheet &damageShieldSheet = *damageShieldReaction->Sheet;
				computeTargetStickMode(damageShieldSheet, attackInfo, pb.ProjectileAimingPoint, *this);
				if (currTarget->createCurrentAttackEndPart(pb,
					                                   damageShieldReaction,
													   *this,
													   NULL,
													   castStartTime,
													   castStartTime,
													   true,
													   damageShieldSheet.PlayImpactAnim,
													   false,
													   false,
													   attackInfo))
				{
					// play "CastEnd" at the good date (if any ...)
					pb.CastAspect = &damageShieldReaction->AttackEndFX;
					pb.CastPower = power;
					pb.ForcePlayImpact = true;
					CProjectileManager::getInstance().addProjectileToQueue(pb);
				}
			}
		}
	}
	*/
}

// *********************************************************************************************
void CCharacterCL::buildStaticObjectCastFX(const NLMISC::CVector &castWorldOrigin, NLMISC::CVector &castWorldPos, const CAttackSheet &/* sheet */, uint intensity)
{
	if (intensity == 0) return;
	const float *userParams = CProjectileManager::getProjectileFXUserParams(intensity);
	// create additionnal cast fxs on the tower or other static object (if any)
	// Build lookat matrix (with respect to axis) looking from castWorldOrigin to castWorldPos
	CVector dir = castWorldPos - castWorldOrigin;
	CVector I = dir.normed();
	CVector K = (CVector::K - (I * CVector::K) * I).normed();
	CMatrix castMat;
	castMat.setPos(castWorldPos);
	castMat.setRot(I, K ^ I, K);
	CAttachedFX::CBuildInfo bi;
	CAttachedFX::CTargeterInfo ti;
	bi.StaticMatrix = &castMat;
	const CAnimationFXSet &afs =_CurrentAttack->AttackStaticObjectCastFX;
	for (uint k = 0; k < afs.FX.size(); ++k)
	{
		// if the fx is in looping mode, & the anim has already done a loop, then don't recreate it
		CAttachedFX::TSmartPtr fx = new CAttachedFX;
		bi.Sheet = &afs.FX[k];
		fx->create(*this, bi, ti);
		if (!fx->FX.empty())
		{
			if (userParams)
			{
				for(uint l = 0; l < 4; ++l)
				{
					fx->FX.setUserParam(l, userParams[l]);
				}
			}
			attachFX(fx);
		}
	}
}

// *********************************************************************************************
void CCharacterCL::computeTargetStickMode(const CAttackSheet &sheet, const CAttackInfo &attackInfo, CFXStickMode &dest, CEntityCL &target)
{
	bool hasPhysicalImpact = false;
	if (attackInfo.Localisation != BODY::UnknownBodyPart &&
		attackInfo.PhysicalImpactIntensity >= 1 &&
		attackInfo.PhysicalImpactIntensity <= MAGICFX::NUM_SPELL_POWER &&
		attackInfo.HitType != HITTYPE::Failed &&
		attackInfo.HitType != HITTYPE::Undefined &&
		attackInfo.DamageType != DMGTYPE::UNDEFINED)
	{
		hasPhysicalImpact = true;
	}

	if (sheet.IsImpactLocalised || hasPhysicalImpact)
	{
		// get projectile impact point from localisation
		// & generate stick mode
		const char *targetBoneName = target.getBoneNameFromBodyPart(attackInfo.Localisation, attackInfo.Side);
		if (targetBoneName)
		{
			if (sheet.DefaultAimingPoint.Mode == CFXStickMode::UserBoneOrientedTowardTargeter)
			{
				dest.Mode = CFXStickMode::UserBoneOrientedTowardTargeter;
			}
			else
			{
				dest.Mode = CFXStickMode::UserBone;
			}
			dest.UserBoneName = CStringMapper::map(targetBoneName);
		}
	}
	else
	{
		// use default aiming point given in sheet
		dest = sheet.DefaultAimingPoint;
	}
}


// *********************************************************************************************
bool CCharacterCL::createCurrentAttackEndPart(CProjectileBuild &destPB,
											  const CAttack *currentAttack,
											  const CCharacterCL &target,
										      const CFXStickMode *sm,
										      double spawnDate,
										      double hitDate,
										      bool playImpactFX,
											  bool playImpactAnim,
										      bool magicResist,
										      bool /* mainImpactIsLocalised */,
										      const CAttackInfo &attackInfo,
											  const NLMISC::CVector &additionnalOffset /*= NLMISC::CVector::Null*/
										     )
{
	if (!currentAttack) return false;
	if (!currentAttack->Sheet) return false;


	const CAttackSheet &sheet = *currentAttack->Sheet;

	// dates
	destPB.StartDate = spawnDate;
	destPB.EndDate = hitDate;
	// choose fx for projectile
	if (attackInfo.Intensity >= 1 && attackInfo.Intensity <= MAGICFX::NUM_SPELL_POWER)
	{
		destPB.ProjectileAspect = &currentAttack->ProjectileFX;
	}
	else
	{
		destPB.ProjectileAspect = NULL;
	}
	// choose fx for impact
	if (!playImpactFX)
	{
		destPB.ImpactAspect = NULL;
	}
	else
	{
		if (attackInfo.Intensity  >= 1 && attackInfo.Intensity <= MAGICFX::NUM_SPELL_POWER) // impact has same intensity than projectile
		{
			destPB.ImpactAspect = &currentAttack->ImpactFX;
		}
		else
		{
			destPB.ImpactAspect = NULL;
		}
	}

	// FILL PROJECTILE BUILD
	destPB.AttackInfo = attackInfo;
	destPB.TargeterInfo.Slot = slot();
	//

	destPB.LocalizedImpact = sheet.IsImpactLocalised;
	// If this is a secondary projectile, it may start from another location, which is the impact point of the previous projectile
	// (so it doesn't start from the caster hand, or any around settings that is read from the spell sheet)
	if (sm) // start stickmode wanted ?
	{
		destPB.TargeterInfo.StickMode = *sm;
	}
	else
	{
		// if no stick mode is not forced, then use the one given in the  projectile sheet
		if (destPB.ProjectileAspect && !destPB.ProjectileAspect->FX.empty())
		{
			destPB.TargeterInfo.StickMode = destPB.ProjectileAspect->FX[0].Sheet->StickMode;
		}
		else
		{
			// if no projectile is given, then uses the default casting point
			destPB.TargeterInfo.StickMode = sheet.DefaultCastingPoint;
		}
	}
	destPB.Mode = sheet.ProjectileMode;
	destPB.Target.Slot = target.slot();
	destPB.TargeterInfo.StickOffset = CVector::Null;
	destPB.PlayImpactAnim = playImpactAnim;
	destPB.LetProjectileStickedOnTarget = sheet.LetProjectileStickedOnTarget;
	destPB.TargeterInfo.DefaultPos = pos().asVector();
	//
	destPB.MagicResist = magicResist;
	// offset if projectile is launched from a range weapon and projectile is sticked to box_arme
	if (destPB.TargeterInfo.StickMode.Mode == CFXStickMode::UserBone && sheet.ApplyItemOffsetToWeaponBone)
	{
		// should be fired from the 'box_arme' bone, which means it is fired from a weapon
		if (CStringMapper::unmap(destPB.TargeterInfo.StickMode.UserBoneName) == "box_arme")
		{
			NLMISC::CVector projectileOffset = NLMISC::CVector::Null;
			const CItemSheet *is = getRightHandItemSheet();
			if (is)
			{
				destPB.TargeterInfo.StickOffset = is->FX.AttackFXOffset;
			}
			destPB.TargeterInfo.StickOffset += additionnalOffset;
		}
	}
	destPB.TargeterInfo.StickOffset += sheet.AdditionnalStartOffset;
	return true;
}


// *********************************************************************************************
void CCharacterCL::computeBestCastRay(CEntityCL			 &targetEntity,
									  const CFXStickMode &targetStickMode,
									  NLMISC::CVector    &castWorldOrigin,
									  NLMISC::CVector    &castWorldPos,
									  NLMISC::CVector    &worldOffsetToCasterPivot
									 ) const
{
	// additionnal offset taken from sheet. Useful for towers that have no bones, but can fire projectiles anyway
	nlassert(_Sheet && !_Sheet->ProjectileCastRay.empty());
	// if several offsets are provided, then choose the one that has the smallest angle towards target
	CVector target;
	CProjectileManager::evalFXPosition(&targetStickMode, targetEntity, target);
	float   maxDP3 = -FLT_MAX;
	// NB : the offset is relative to object pivot, not to a bone
	CMatrix casterMatrix;
	buildAlignMatrix(casterMatrix);
	for(uint k = 0; k < _Sheet->ProjectileCastRay.size(); ++k)
	{
		CVector currCastWorldPos    = casterMatrix * _Sheet->ProjectileCastRay[k].Pos;
		CVector currCastWorldOrigin = casterMatrix * _Sheet->ProjectileCastRay[k].Origin;
		float dp3 = (target - currCastWorldPos).normed() * (currCastWorldPos - currCastWorldOrigin).normed();
		if (dp3 > maxDP3)
		{
			maxDP3 = dp3;
			worldOffsetToCasterPivot = casterMatrix.mulVector(_Sheet->ProjectileCastRay[k].Pos);
			castWorldOrigin = currCastWorldOrigin;
			castWorldPos = currCastWorldPos;
		}
	}
}

// *********************************************************************************************
bool CCharacterCL::isCurrentBehaviourAttackEnd() const
{
	switch(_CurrentBehaviour.Behaviour)
	{
		case MBEHAV::CAST_OFF_SUCCESS:
		case MBEHAV::CAST_OFF_LINK:
		case MBEHAV::CAST_CUR_SUCCESS:
		case MBEHAV::CAST_CUR_LINK:
		case MBEHAV::CAST_MIX_SUCCESS:
		case MBEHAV::CAST_MIX_LINK:
		case MBEHAV::RANGE_ATTACK:
		case MBEHAV::CREATURE_ATTACK_0:
		case MBEHAV::CREATURE_ATTACK_1:
		case MBEHAV::DEFAULT_ATTACK:
		case MBEHAV::POWERFUL_ATTACK:
		case MBEHAV::AREA_ATTACK:
			return true;
		default:
			break;
	}
	return false;
}


// ***************************************************************************
void CCharacterCL::applyBehaviourFlyingHPs(const CBehaviourContext &bc, const MBEHAV::CBehaviour &behaviour,
								 const vector<double> &targetHitDates)
{
	nlassert(targetHitDates.size()==bc.Targets.Targets.size());

	if(!bc.Targets.Targets.empty())
	{
		if(behaviour.DeltaHP != 0)
		{
			CRGBA deltaHPColor(0, 0, 0);
			// if it's a hit
			if( behaviour.DeltaHP < 0 )
			{
				// if the behaviour is casted by the user
				if( slot() == 0 )
				{
					deltaHPColor = ClientCfg.SystemInfoParams["dgm"].Color;
				}
				else
					// if the behaviour is casted by an entity that target the user
					if( targetSlot() == 0 )
					{
						CEntityCL *actor = EntitiesMngr.entity(slot());
						if( actor )
						{
							// if actor is player : use pvp color
							if( actor->isPlayer() )
								deltaHPColor = ClientCfg.SystemInfoParams["dgp"].Color;
							else
								deltaHPColor = ClientCfg.SystemInfoParams["dg"].Color;
						}
					}
					else
					{
						deltaHPColor = CRGBA(127,127,127);
					}
			}
			else
			{
				deltaHPColor = CRGBA(0,220,0);
			}

			// Set the delta HP
			for (size_t i=0; i<bc.Targets.Targets.size(); ++i)
			{
				CEntityCL *target2 = EntitiesMngr.entity(bc.Targets.Targets[i].TargetSlot);
				if(target2)
					target2->addHPOutput(behaviour.DeltaHP, deltaHPColor, float(targetHitDates[i]-TimeInSec));
			}
		}
	}
}


//-----------------------------------------------
// Apply the behaviour.
// \param behaviour : the behaviour to apply.
//-----------------------------------------------
void CCharacterCL::applyBehaviour(const CBehaviourContext &bc)	// virtual
{
	// Backup the current behaviour.
	CBehaviour previousBehaviour = _CurrentBehaviour;
	_CurrentBehaviour = bc.Behav;
	const CBehaviour &behaviour = bc.Behav;

	// check if self-target
	bool selfSpell = false;
	if (bc.Targets.Targets.size() == 1)
	{
		if (bc.Targets.Targets[0].TargetSlot == 0)
		{
			selfSpell = true;
		}
	}
	bool isOffensif;
	switch(behaviour.Behaviour)
	{
		case MBEHAV::CAST_OFF:
		case MBEHAV::CAST_OFF_FAIL:
		case MBEHAV::CAST_OFF_SUCCESS:
		case MBEHAV::CAST_OFF_LINK:
			isOffensif = true;
		break;
		default:
			isOffensif = false;
		break;
	}

	// Get a pointer on the target.
	CEntityCL *target = EntitiesMngr.entity(targetSlot());


	// ***** Choose Combat Animation to apply

	TAnimStateKey	combatAnimState= CAnimationStateSheet::UnknownState;
	bool			isMovingCombatAnimState= false;
	// if the behaviour is for combat, compute now the animation to apply
	if( !behaviour.isMagic() && ( behaviour.isCombat() || behaviour.isCreatureAttack() ) )
	{
		// Atk Animation when moving
		if(_CurrentState && _CurrentState->Move && (_CurrentState->OnAtk != CAnimationStateSheet::UnknownState))
		{
			combatAnimState= _CurrentState->OnAtk;
			isMovingCombatAnimState= true;
		}
		// Atk Animation when NOT moving
		else
		{
			// select the combat animation.
			switch(behaviour.Behaviour)
			{
			case CREATURE_ATTACK_0:
				combatAnimState= CAnimationStateSheet::Attack1;
				break;
			case CREATURE_ATTACK_1:
				combatAnimState= CAnimationStateSheet::Attack2;
				break;
			// Default Animation
			case DEFAULT_ATTACK:
				switch(getAttackHeight(target, (BODY::TBodyPart)behaviour.Combat.Localisation, BODY::Right))
				{
				// LOW
				case CCharacterCL::AtkLow:
					combatAnimState= CAnimationStateSheet::DefaultAtkLow;
					break;
				// HIGH
				case CCharacterCL::AtkHigh:
					combatAnimState= CAnimationStateSheet::DefaultAtkHigh;
					break;
				// MIDDLE or Default
				case CCharacterCL::AtkMiddle:
				default:
					combatAnimState= CAnimationStateSheet::DefaultAtkMiddle;
					break;
				}
				break;
			// Powerful Animation
			case POWERFUL_ATTACK:
				switch(getAttackHeight(target, (BODY::TBodyPart)behaviour.Combat.Localisation, BODY::Right))
				{
				// LOW
				case CCharacterCL::AtkLow:
					combatAnimState= CAnimationStateSheet::PowerfulAtkLow;
					break;
				// HIGH
				case CCharacterCL::AtkHigh:
					combatAnimState= CAnimationStateSheet::PowerfulAtkHigh;
					break;
				// MIDDLE or Default
				case CCharacterCL::AtkMiddle:
				default:
					combatAnimState= CAnimationStateSheet::PowerfulAtkMiddle;
					break;
				}
				break;
			// Area Animation
			case AREA_ATTACK:
				switch(getAttackHeight(target, (BODY::TBodyPart)behaviour.Combat.Localisation, BODY::Right))
				{
				// LOW
				case CCharacterCL::AtkLow:
					combatAnimState= CAnimationStateSheet::AreaAtkLow;
					break;
				// HIGH
				case CCharacterCL::AtkHigh:
					combatAnimState= CAnimationStateSheet::AreaAtkHigh;
					break;
				// MIDDLE or Default
				case CCharacterCL::AtkMiddle:
				default:
					combatAnimState= CAnimationStateSheet::AreaAtkMiddle;
					break;
				}
				break;
			// Range Animation
			case RANGE_ATTACK:
				combatAnimState= CAnimationStateSheet::Attack1;
				break;
			default:
				break;
			}
		}
	}


	// ***** Compute Impact delays and cast missiles

	// Default target hit dates
	static	vector<double>	targetHitDates;
	targetHitDates.clear();
	targetHitDates.resize(bc.Targets.Targets.size(), TimeInSec);

	// Update Attack Projectiles and FXs
	updateCurrentAttack();
	if (isCurrentBehaviourAttackEnd())
	{
		// retrieve target hit dates, so flying HPs have the correct ones
		performCurrentAttackEnd(bc, selfSpell && isOffensif, targetHitDates, combatAnimState);
	}

	// INFO : display some debug information.
	if((VerboseAnimUser && _Slot==0) || (VerboseAnimSelection && _Slot == UserEntity->selection()))
		nlinfo("CH:applyBeh:%d: '%d(%s)'", _Slot, (sint)behaviour.Behaviour, behaviourToString((EBehaviour)behaviour.Behaviour).c_str());


	// ***** Apply the behaviour according to type

	// This is a behaviour for the magic.
	if(behaviour.isMagic())
	{
		// Execute the magic behaviour.
		switch(behaviour.Behaviour)
		{
			////////////////
			// BEGIN CAST //
			case MBEHAV::CAST_OFF:
			case MBEHAV::CAST_CUR:
			case MBEHAV::CAST_MIX:
			case MBEHAV::CAST_ACID:
			case MBEHAV::CAST_BLIND:
			case MBEHAV::CAST_COLD:
			case MBEHAV::CAST_ELEC:
			case MBEHAV::CAST_FEAR:
			case MBEHAV::CAST_FIRE:
			case MBEHAV::CAST_HEALHP:
			case MBEHAV::CAST_MAD:
			case MBEHAV::CAST_POISON:
			case MBEHAV::CAST_ROOT:
			case MBEHAV::CAST_ROT:
			case MBEHAV::CAST_SHOCK:
			case MBEHAV::CAST_SLEEP:
			case MBEHAV::CAST_SLOW:
			case MBEHAV::CAST_STUN:
				beginCast(behaviour);
				break;
			//////////////
			// END CAST //
			case MBEHAV::CAST_OFF_FAIL:
			case MBEHAV::CAST_OFF_FUMBLE:
				if (!selfSpell) endCast(behaviour, previousBehaviour);
			break;
			case MBEHAV::CAST_OFF_SUCCESS:
			case MBEHAV::CAST_OFF_LINK:
				endCast(behaviour, previousBehaviour);
			break;
			case MBEHAV::CAST_CUR_FAIL:
			case MBEHAV::CAST_CUR_FUMBLE:
				endCast(behaviour, previousBehaviour);
			break;
			case MBEHAV::CAST_CUR_SUCCESS:
			case MBEHAV::CAST_CUR_LINK:
				endCast(behaviour, previousBehaviour);
			break;
			case MBEHAV::CAST_MIX_FAIL:
			case MBEHAV::CAST_MIX_FUMBLE:
				endCast(behaviour, previousBehaviour);
			break;
			case MBEHAV::CAST_MIX_SUCCESS:
			case MBEHAV::CAST_MIX_LINK:
				endCast(behaviour, previousBehaviour);
			break;
			default:
			break;
		}
		// DeltaHP
		applyBehaviourFlyingHPs(bc, behaviour, targetHitDates);
	}
	// This is a behaviour for the combat.
	else if(behaviour.isCombat() || behaviour.isCreatureAttack())
	{
		float frontYawBefore = 0.f;
		float frontYawAfter = 0.f;

		// Atk Animation when NOT moving?
		if(target && !isMovingCombatAnimState)
		{
			// orientate to target
			CVectorD dirToTarget = target->pos() - pos();
			dirToTarget.z = 0;
			dirToTarget.normalize();
			if( !(isUser() && ClientCfg.AutomaticCamera == false) )
			{
				// backup front yaw
				frontYawBefore = frontYaw();
				front( dirToTarget );
			}
			dir( dirToTarget );
		}

		// Apply the state animation chosen before
		if(combatAnimState!=CAnimationStateSheet::UnknownState)
			setAnim(combatAnimState);

		// move camera so view doesn't change
		if( isUser() && frontYawBefore != 0.f )
		{
			frontYawAfter = frontYaw();
			float deltaYaw = frontYawAfter - frontYawBefore;
			if( deltaYaw !=0 )
			{
				UserControls.appendCameraDeltaYaw(-deltaYaw);
			}
		}

		// reset yaw smoothly to center view behind user
		if( isUser() && target && !target->isUser() && ClientCfg.AutomaticCamera )
		{
			UserControls.resetSmoothCameraDeltaYaw();
		}

		// DeltaHP
		applyBehaviourFlyingHPs(bc, behaviour, targetHitDates);
	}
	// Emote
	else if(behaviour.isEmote())
	{
		if(ClientCfg.Light==false && ClientCfg.EAMEnabled)
		{
			TAnimStateId emot;
			if (EAM)
			{
				/*
				// old code : fxs attached to emotes
				uint emoteIndex = behaviour.Behaviour-EMOTE_BEGIN;
				CTextEmotListSheet *pTELS = dynamic_cast<CTextEmotListSheet*>(SheetMngr.get(CSheetId("list.text_emotes")));
				if (pTELS)
				{
					if (emoteIndex < pTELS->TextEmotList.size())
					{
						const CTextEmotListSheet::STextEmot &emot = pTELS->TextEmotList[emoteIndex];
						if (!emot.FXToSpawn.empty())
						{
							// Compute the direction Matrix
							CMatrix fxMatrix;
							CVector vi = dir() ^ CVector::K;
							CVector vk = vi ^ dir();
							fxMatrix.setRot(vi, UserEntity->dir(), vk, true);
							fxMatrix.setPos(pos().asVector() + fxMatrix.getJ() * emot.FXSpawnDist);
							FXMngr.deferFX(emot.FXToSpawn, fxMatrix, emot.FXSpawnDelay);
						}
					}
				}
				*/
				if(EAM->getEmot(behaviour.Behaviour-EMOTE_BEGIN, emot))
					setAnim(CAnimationStateSheet::Emote, emot);
				else
					nlwarning("CH:applyBeh:%d: Emot '%d' unknown.", _Slot, behaviour.Behaviour-EMOTE_BEGIN);
			}
		}
	}
	// Others
	else
	{
		switch(behaviour.Behaviour)
		{
		// Loot Begin
		case MBEHAV::LOOT_INIT:
			setAnim(CAnimationStateSheet::LootInit);
			break;
		// Loot End
		case MBEHAV::LOOT_END:
			setAnim(CAnimationStateSheet::LootEnd);
			break;
		// Prospecting Begin
		case MBEHAV::PROSPECTING:
			setAnim(CAnimationStateSheet::ProspectingInit);
			break;
		// Prospecting End
		case MBEHAV::PROSPECTING_END:
			setAnim(CAnimationStateSheet::ProspectingEnd);
			break;
		// Extracting Begin
		case MBEHAV::EXTRACTING:
			// DeltaHP
			if(target)
				if(behaviour.DeltaHP != 0)
					target->addHPOutput(behaviour.DeltaHP,CRGBA(0,220,0));
			// If receiving a new DeltaHP in the current extraction, don't reset the animation
			if ( previousBehaviour.Behaviour != _CurrentBehaviour.Behaviour )
				setAnim(CAnimationStateSheet::UseInit);
			break;
		// Extracting End
		case MBEHAV::EXTRACTING_END:
			setAnim(CAnimationStateSheet::UseEnd);
			break;
		// Care Begin
		case MBEHAV::CARE:
			setAnim(CAnimationStateSheet::CareInit);
			break;
		// Care End
		case MBEHAV::CARE_END:
			setAnim(CAnimationStateSheet::CareEnd);
			break;

		// Begin to use a tool
		case MBEHAV::HARVESTING:
		case MBEHAV::FABER:
		case MBEHAV::REPAIR:
		case MBEHAV::REFINE:
		case MBEHAV::TRAINING:
			setAnim(CAnimationStateSheet::UseInit);
			break;

		// End to use a tool
		case MBEHAV::HARVESTING_END:
		case MBEHAV::FABER_END:
		case MBEHAV::REPAIR_END:
		case MBEHAV::REFINE_END:
		case MBEHAV::TRAINING_END:
			setAnim(CAnimationStateSheet::UseEnd);
			break;

		// Begin Stun
		case MBEHAV::STUNNED:
			setAnim(CAnimationStateSheet::StunBegin);
			break;

		// End Stun
		case MBEHAV::STUN_END:
			setAnim(CAnimationStateSheet::StunEnd);
			break;

		// Idle
		case IDLE:
			break;

		// Unknown behaviour -> idle.
		case UNKNOWN_BEHAVIOUR:
		default:
			nlwarning("CH::computeBehaviour : Entity in slot %d has an unknown behaviour %d to manage.", _Slot, (sint)behaviour.Behaviour);
			break;
		}
	}
}// computeBehaviour //

//-----------------------------------------------
// impact :
// Play an impact on the entity
// \param impactType : 0=magic, 1=melee
// \param type : see behaviour for spell
// \param intensity : see behaviour for spell
// \param id : see behaviour for spell
//-----------------------------------------------
void CCharacterCL::impact(uint /* impactType */, uint type, uint id, uint intensity)	// virtual
{
	// Display Magic Debug Infos
	if(Verbose & VerboseMagic)
		nlinfo("CH:impact:%d: type: %d, id: %d, intensity: %d", _Slot, type, id, intensity);
	// No Intensity -> No Impact
	if(intensity==0)
		return;
	// Invalid Intensity -> No Impact
	else if(intensity>5)
	{
		nlwarning("CH:impact:%d: invalid intensity %u", _Slot, intensity);
		return;
	}
	// RESIST : temp until resist is in the enum.
	if(type==0)
	{
		// Create the FX
		NL3D::UInstance resistFX = Scene->createInstance("Sp_Resist_Lev5.ps");
		if(!resistFX.empty())
			resistFX.setPos(pos());
		return;
	}
	// Compute the impact name
	string impact;
	if(id < ClientCfg.OffImpactFX.size())
		impact = ClientCfg.OffImpactFX[id];
	// Create the FX
	if(!impact.empty())
	{

		NL3D::UInstance impactFX = Scene->createInstance(impact);
		if(!impactFX.empty())
		{
			impactFX.setPos(pos());
			UParticleSystemInstance instFX;
			instFX.cast (impactFX);
			if(!instFX.empty())
			{
				// UserParam  |  Intensity 1  |  Intensity 2  |  Intensity 3  |  Intensity 4  |  Intensity 5
				//     0      |       0       |       0       |       1       |       1       |       1
				//     1      |       0       |       1       |       1       |       1       |       1
				//     2      |       0       |       0       |       0       |       1       |       1
				//     3      |       0       |       0       |       0       |       0       |       1
				float userParam0 = 0.0f;
				float userParam1 = 0.0f;
				float userParam2 = 0.0f;
				float userParam3 = 0.0f;
				// WARNING : there is no break and this is correct.
				switch(intensity)
				{
				case 5:
					userParam3 = 1.0f;
				case 4:
					userParam2 = 1.0f;
				case 3:
					userParam0 = 1.0f;
				case 2:
					userParam1 = 1.0f;
				}
				instFX.setUserParam(0, userParam0);
				instFX.setUserParam(1, userParam1);
				instFX.setUserParam(2, userParam2);
				instFX.setUserParam(3, userParam3);
			}
		}
	}
}// impact //

//-----------------------------------------------
// meleeImpact ::
//-----------------------------------------------
void CCharacterCL::meleeImpact(const CAttackInfo &attack)
{
	if (_Skeleton.empty()) return;
	if (attack.PhysicalImpactIntensity < 1 || attack.PhysicalImpactIntensity > 5) return;
	if (attack.HitType == HITTYPE::Failed) return;
	const char *boneName = getBoneNameFromBodyPart(attack.Localisation, attack.Side);
	if (!boneName) return;
	sint boneId = _Skeleton.getBoneIdByName(std::string(boneName));
	if (boneId == -1) return;
	if (!Scene) return;
	// choose good fx depending on the kind of damage
	NL3D::UInstance instance;
	switch(attack.DamageType)
	{
		case DMGTYPE::BLUNT:    instance = Scene->createInstance("mel_impactblunt.ps"); break;
		case DMGTYPE::SLASHING: instance = Scene->createInstance("mel_impactslashing.ps"); break;
		case DMGTYPE::PIERCING: instance = Scene->createInstance("mel_impactpiercing.ps"); break;
		default:
			return; // other types not supported
		break;
	}
	if (instance.empty()) return;
	UParticleSystemInstance impact;
	impact.cast (instance);
	if (impact.empty())
	{
		Scene->deleteInstance(instance);
		return;
	}
	// the 2 first user params of the fx are used to modulate intensity
	static const float intensityUP[5][2] =
	{
		{ 0.f,  0.f},
		{ 0.f,  0.5f},
		{ 0.5f, 0.5f},
		{ 0.5f, 1.f},
		{ 1.f,  1.f}
	};
	impact.setUserParam(0, intensityUP[attack.PhysicalImpactIntensity - 1][0]);
	impact.setUserParam(1, intensityUP[attack.PhysicalImpactIntensity - 1][1]);
	impact.setUserParam(2, (attack.HitType == HITTYPE::CriticalHit || attack.HitType == HITTYPE::CriticalHitResidual) ? 1.f : 0.f);
	impact.setUserParam(3, (attack.HitType == HITTYPE::HitResidual || attack.HitType == HITTYPE::CriticalHitResidual) ? 1.f : 0.f);
	//
	_Skeleton.stickObject(impact, boneId);
	// delegate managment of the impact to the fx manager
	FXMngr.fx2remove(impact);
}// meleeImpact //


//-----------------------------------------------
// magicImpact :
// Play the magic impact on the entity
// \param type : type of the impact (host/good/neutral).
// \param intensity : intensity of the impact.
//-----------------------------------------------
void CCharacterCL::magicImpact(uint type, uint intensity)	// virtual
{
	// --- FX --- //
	// Choose the FX.
	string impact;
	switch(type)
	{
	// Resist
	case 0:
		impact = "Sp_Resist_Lev";
		break;
	// Good
	case 1:
		impact = "Sp_Bien_Cure_Lev";
		break;
	// Neutral
	case 2:
		impact = "Sp_Neutre_Protect_Lev";
		break;
	// Bad
	case 3:
		impact = "Sp_Host_Hurt_Lev";
		break;
	default:
		nlwarning("CH:magicImpact:%d: Unknown type '%d'.", _Slot, type);
		return;
	}
	// Intensity
	switch(intensity)
	{
	// Too weak
	case INTENSITY_TYPE::IMPACT_NONE:
		return;

	case INTENSITY_TYPE::IMPACT_INSIGNIFICANT:
		impact += "1.ps";
		break;
	case INTENSITY_TYPE::IMPACT_VERY_WEAK:
		impact += "2.ps";
		break;
	case INTENSITY_TYPE::IMPACT_WEAK:
		impact += "3.ps";
		break;
	case INTENSITY_TYPE::IMPACT_AVERAGE:
		impact += "4.ps";
		break;
	case INTENSITY_TYPE::IMPACT_STRONG:
		impact += "5.ps";
		break;

	// Unknown
	default:
		nlwarning("CH:magicImpact:%d: Unknown intensity '%d'.", _Slot, intensity);
	}
	// Create the FX
	if(!impact.empty())
	{
		NL3D::UInstance resistFX = Scene->createInstance(impact);
		if(!resistFX.empty())
			resistFX.setPos(pos());
	}
}// resist //


//-----------------------------------------------
// getMaxSpeed :
// Return the basic max speed for the entity in meter per sec
//-----------------------------------------------
double CCharacterCL::getMaxSpeed()	const // virtual
{
	return _Sheet->MaxSpeed;
}// getMaxSpeed //


//-----------------------------------------------
// mode :
// Method called to change the mode (Combat/Mount/etc.).
//-----------------------------------------------
bool CCharacterCL::mode(MBEHAV::EMode m)
{
	// DEBUG INFOS
	if(VerboseAnimSelection && _Slot == UserEntity->selection())
	{
		nlinfo("CH::mode:%d: m'%s(%d)', _ModeWanted'%s(%d)', _Mode'%s(%d)'", _Slot,
			MBEHAV::modeToString(m          ).c_str(), m,
			MBEHAV::modeToString(_ModeWanted).c_str(), _ModeWanted,
			MBEHAV::modeToString(_Mode      ).c_str(), _Mode);
	}
	// Is the mode wanted valid ?
	if(m == MBEHAV::UNKNOWN_MODE || m >= MBEHAV::NUMBER_OF_MODES)
	{
		nlwarning("CH::mode:%d: Invalid Mode Wanted '%s(%d)' -> keep '%s(%d)'.",
			_Slot, MBEHAV::modeToString(m).c_str(), m, MBEHAV::modeToString(_Mode).c_str(), _Mode);
		return false;
	}
	// Set the mode wanted.
	_ModeWanted = m;
	if(_CurrentState == 0)
		_Mode = _ModeWanted;
	return true;
}// mode //


//-----------------------------------------------
// applyStage :
// Apply stage modifications.
// \todo GUIGUI ; ameliorer gestion mode.
//-----------------------------------------------
bool CCharacterCL::applyStage(CStage &stage)
{
	bool stageDone = true;

	// If the Stage has a position, backup the position and the stage time.
	if(stage.getPos(_OldPos))
	{
		// Backup the time
		_OldPosTime = stage.time();
		// Remove the property.
		stage.removeProperty(PROPERTY_POSX);
		stage.removeProperty(PROPERTY_POSY);
		stage.removeProperty(PROPERTY_POSZ);
	}

	// Apply orientation.
	pair<bool, sint64> resultTeta = stage.property(PROPERTY_ORIENTATION);
	if(resultTeta.first)
	{
		C64BitsParts parts;
		parts.i64[0] = resultTeta.second;
		float angleZ = parts.f[0];
		// server forces the entity orientation even if it cannot turn
		front(CVector((float)cos(angleZ), (float)sin(angleZ), 0.f), true, true, true);

		_TargetAngle = (float)angleZ;
		// Remove the property.
		stage.removeProperty(PROPERTY_ORIENTATION);
	}

	// Apply Mode.
	pair<bool, sint64> resultMode = stage.property(PROPERTY_MODE);
	if(resultMode.first)
	{
		// Get the mode from stage.
		C64BitsParts parts;
		parts.i64[0] = resultMode.second;
		uint8 mo = parts.u8[0];
		// If the mode wanted is not the same, change the mode wanted.
		if(mo != _ModeWanted)
		{
			if(mode((MBEHAV::EMode)mo))
			{
				//stageDone = false;
				if(_Mode != _ModeWanted)
					stageDone = false;
				else
					stage.removeProperty(PROPERTY_MODE);
			}
			else
				stage.removeProperty(PROPERTY_MODE);
		}
		// If the mode wanted is not the same as the current mode -> Stage not done.
		else if(_Mode != _ModeWanted)
			stageDone = false;
		// Property applied -> Remove the property form stage.
		else
			stage.removeProperty(PROPERTY_MODE);
	}

	// Apply Behaviour.
	pair<bool, sint64> resultBehaviour = stage.property(PROPERTY_BEHAVIOUR);
	if(resultBehaviour.first)
	{
		CBehaviourContext bc;
		bc.Behav     = CBehaviour(resultBehaviour.second);
		bc.BehavTime = stage.time();
		// See if there's a list of target associated with that behaviour (for multitarget spells)
		uint64 spellTarget[4];
		uint numTargets = 0;
		for(uint k = 0; k < 4; ++k)
		{
			pair<bool, sint64> stProp = stage.property(PROPERTY_TARGET_LIST_0 + k);
			if (!stProp.first) break;
			spellTarget[k] = (uint64) stProp.second;
			++ numTargets;
			stage.removeProperty(PROPERTY_TARGET_LIST_0 + k);
		}

		if (numTargets > 0)
		{
			// get the list of targets from the visual properties
			bc.Targets.unpack(spellTarget, numTargets);
		}
		// Compute the beheviour.

		applyBehaviour(bc);
		// Remove the property.
		stage.removeProperty(PROPERTY_BEHAVIOUR);
	}

	// Apply the target.
	pair<bool, sint64> resultTarget = stage.property(PROPERTY_TARGET_ID);
	if(resultTarget.first)
	{
		// Change the entity target.
		targetSlot((CLFECOMMON::TCLEntityId)resultTarget.second);
		// Remove the property.
		stage.removeProperty(PROPERTY_TARGET_ID);
	}

	// The Mount
	pair<bool, sint64> resultParent = stage.property(CLFECOMMON::PROPERTY_ENTITY_MOUNTED_ID);
	if(resultParent.first)
	{
		_Mount = (CLFECOMMON::TCLEntityId)resultParent.second;

		// Remove the property.
		stage.removeProperty(CLFECOMMON::PROPERTY_ENTITY_MOUNTED_ID);
	}

	// The Rider
	pair<bool, sint64> resultRider = stage.property(CLFECOMMON::PROPERTY_RIDER_ENTITY_ID);
	if(resultRider.first)
	{
		_Rider = (CLFECOMMON::TCLEntityId)resultRider.second;

		// Remove the property.
		stage.removeProperty(CLFECOMMON::PROPERTY_RIDER_ENTITY_ID);
	}

	// visual fxs : links and auras
	pair<bool, sint64> resultVisualFX = stage.property(CLFECOMMON::PROPERTY_VISUAL_FX);
	if (resultVisualFX.first)
	{
		applyVisualFX(resultVisualFX.second);
		stage.removeProperty(CLFECOMMON::PROPERTY_VISUAL_FX);
	}


	return stageDone;
}// applyStage //

//-----------------------------------------------
// applyCurrentStage :
// Apply The Current Stage (first stage).
//-----------------------------------------------
bool CCharacterCL::applyCurrentStage()
{
	bool bRet = true;

	CStageSet::TStageSet::iterator it = _Stages._StageSet.begin();
	if(it != _Stages._StageSet.end())
	{
		// Apply the Stage and remove it if stage done.
		if(applyStage((*it).second))
			_Stages._StageSet.erase(it);
		else
			bRet = false;
	}
	else
		nlwarning("CCharacterCL::applyCurrentStage: there is no stage.");

	// Update information from remaining stages.
	updateStages();

	return bRet;
}// applyCurrentStage //


//-----------------------------------------------
// applyAllStagesToFirstPos :
// Apply all stages to the first stage with a position.
//-----------------------------------------------
void CCharacterCL::applyAllStagesToFirstPos()
{
	CVectorD stagePos;
	CStageSet::TStageSet::iterator it = _Stages._StageSet.begin();
	while(it != _Stages._StageSet.end() && !(*it).second.getPos(stagePos))
	{
		// Apply the Stage.
		if(!applyStage((*it).second))
		{
			updateStages();
			return;
		}

		// Backup the iterator to remove
		CStageSet::TStageSet::iterator itTmp = it;
		// Next Stage.
		++it;
		// Remove the stage done.
		_Stages._StageSet.erase(itTmp);
	}

	// Apply the stage with the position.
	if(it != _Stages._StageSet.end())
	{
		// Apply the Stage.
		if(applyStage((*it).second))
			// Remove the stage done.
			_Stages._StageSet.erase(it);
	}
	else
		nlwarning("CH:applyAllStagesToFirstPos:%d: There is no stage with a position.", _Slot);

	// Upate information from remaining stages.
	updateStages();
}// applyAllStagesToFirstPos //


//-----------------------------------------------
// playToEndAnim :
// Play the time step for the loop and truncate to End Anim if Time Step too big.
//-----------------------------------------------
ADD_METHOD(void CCharacterCL::playToEndAnim(const double &startTimeOffset, double &length))
	// Average Speed
	double speedToDest = speed();
	// Blend Walk/Run
	if(ClientCfg.BlendForward && (animState(MOVE) == CAnimationStateSheet::Walk))
	{
		uint animWalkId = animId(MOVE);
		uint animRunId  = animId(MOVE_BLEND_OUT);
		double animWalkSpeed = EAM->getAnimationAverageSpeed(animWalkId)*getSheetScale()*_CustomScalePos*_CharacterScalePos;
		double animRunSpeed  = EAM->getAnimationAverageSpeed(animRunId)*getSheetScale()*_CustomScalePos*_CharacterScalePos;
		if(animWalkSpeed<=animRunSpeed)
		{
			double startTimeOffRun = animOffset(MOVE_BLEND_OUT);
			double animWalkLength = EAM->getAnimationLength(animWalkId);
			double animRunLength  = EAM->getAnimationLength(animRunId);
			// Current Speed <= Walk Speed, so use the walk animation only.
			if(speed() <= animWalkSpeed)
			{
				runFactor(0.0);
				double speedFactor = speed()/animWalkSpeed;
				double animTimeOffWalk = animOffset(MOVE) + length*speedFactor;
				if(animTimeOffWalk > animWalkLength)
				{
					animOffset(MOVE,           animWalkLength);
					animOffset(MOVE_BLEND_OUT, animRunLength);
					length = (animWalkLength - startTimeOffset) / speedFactor;
				}
				// Adjust Time Offset for the Run Channel
				else
				{
					animOffset(MOVE,           animTimeOffWalk);
					animOffset(MOVE_BLEND_OUT, animRunLength*(animTimeOffWalk/animWalkLength));
				}
			}
			// Current Speed >= Run Speed, so use the run animation only.
			else if(speed() >= animRunSpeed)
			{
				runFactor(1.0);
				double speedFactor = speed()/animRunSpeed;
				double animTimeOffRun = animOffset(MOVE_BLEND_OUT) + length*speedFactor;
				if(animTimeOffRun > animRunLength)
				{
					animOffset(MOVE,           animWalkLength);
					animOffset(MOVE_BLEND_OUT, animRunLength);
					length = (animRunLength - startTimeOffRun) / speedFactor;
				}
				// Adjust Time Offset for the Walk Channel
				else
				{
					animOffset(MOVE,           animWalkLength*(animTimeOffRun/animRunLength));
					animOffset(MOVE_BLEND_OUT, animTimeOffRun);
				}
			}
			// Current Speed > Walk Speed & < Run Speed, so mix Walk and Run animation.
			else
			{
				double t1 = animRunSpeed-animWalkSpeed;
				double t2 =      speed()-animWalkSpeed;
				runFactor(t2/t1);
				double mixLength = runFactor()*animRunLength + (1.0-runFactor())*animWalkLength;
				double animTimeOffWalk = animOffset(MOVE) + animWalkLength/mixLength*length;
				if(animTimeOffWalk > animWalkLength)
				{
					animOffset(MOVE,           animWalkLength);
					animOffset(MOVE_BLEND_OUT, animRunLength);
					length = (animWalkLength - startTimeOffset) / (animWalkLength/mixLength);
				}
				else
				{
					animOffset(MOVE,           animTimeOffWalk);
					animOffset(MOVE_BLEND_OUT, animRunLength*animTimeOffWalk/animWalkLength);	// Same percentage in the animation than the Walk one.
				}
			}
			return;
		}
		//else
			//nlwarning("playToEndAnim:%d: animWalkSpeed > animRunSpeed", _Slot);
	}
	// No Mix between Walk and Run.
	runFactor(0.0);
	// Speed Factor
	double speedFactor = computeSpeedFactor(speedToDest);
	// Compute the desired new time offset.
	double animTimeOffMove = animOffset(MOVE) + length * speedFactor;
	// Truncate animation time offset if it over-runs end of animation and change the loopTimeOffset too.
	double animationLength = EAM->getAnimationLength(animId(MOVE));
	if(animTimeOffMove > animationLength)
	{
		animOffset(MOVE, animationLength);
		length = (animationLength - startTimeOffset) / speedFactor;
	}
	else
		animOffset(MOVE, animTimeOffMove);
}// playToEndAnim //

//-----------------------------------------------
// updateStages :
// Call this method to give a time for each stage, compute distance to destination and some more information.
// \todo GUIGUI : clean up
//-----------------------------------------------
void CCharacterCL::updateStages()
{
	H_AUTO ( RZ_Client_Entity_CL_updateStages );

	_FirstPos			= INVALID_POS;	// No First Position
	_FirstTime			= INVALID_TIME;	//- No First Position
	dist2FirstPos(INVALID_DIST);		// No First Position
	_DestPos			= INVALID_POS;	// No Destination
	_DestTime			= INVALID_TIME;	// No Destination
	dist2Dest(INVALID_DIST);			// No Destination
	CVectorD posTmp		= pos();
	_IsThereAMode		= false;
	_ImportantStepTime= 0.0;


	// ***** update predicted interval: if a new pos B is found after a pos A, then the interval B-A is known!
	CStageSet::TStageSet::iterator it = _Stages._StageSet.begin();
	CStageSet::TStageSet::iterator itPosPrec= _Stages._StageSet.end();
	bool	somePosFoundEarly= false;
	while(it != _Stages._StageSet.end())
	{
		// if this stage has a position
		if(it->second.isPresent(PROPERTY_POSITION))
		{
			somePosFoundEarly= true;
			// then it's cool we can set the new accurate interval to the prec stage which has a pos
			if(itPosPrec!=_Stages._StageSet.end())
			{
				uint dgc= it->first - itPosPrec->first;
				itPosPrec->second.predictedInterval(dgc);
			}
			// bkup
			itPosPrec= it;
		}
		it++;
	}


	// ***** Compute the current LCT Impact for this character
	// NB: used only in mode CClientConfig::StageUsePosOnlyLCT
	sint32	charLCTI;
	// If disabled, full LCT impact
	if(_StartDecreaseLCTImpact==0)
		charLCTI= 256;
	else
	{
		const	sint32	decreaseTick= 20;	// 2 seconds
		// blend according to the start of decrease
		sint32	dt= NetMngr.getCurrentServerTick() - _StartDecreaseLCTImpact;
		if(dt<=0)
			charLCTI= 256;
		else if(dt>=decreaseTick)
			charLCTI= 0;
		else
			charLCTI= ((decreaseTick-dt)*256)/decreaseTick;
		// hence, at end of blend, charLCTI is 0
	}


	// ***** Compute Stages to give them a time and get some information from those stages.
	// yoyo: use any stage with no LCT, until it is to be played AFTER a position
	bool	stageForceLCTFound= false;
	CStageSet::TStageSet::iterator itTmp;
	it = _Stages._StageSet.begin();
	while(it != _Stages._StageSet.end())
	{
		CStage &stage = (*it).second;

		// *** retrieve position in stage if any
		CVectorD	posInStage;
		bool		hasPos= stage.getPos(posInStage);
		// check the first pos is correct
		if(hasPos && dist2Dest()==INVALID_DIST)
		{
			// Compute the distance to the first position
			double distToFirst   = (CVectorD(posInStage.x, posInStage.y, 0.0) - CVectorD(          posTmp.x,           posTmp.y, 0.0)).norm();
			double distToLimiter = (CVectorD(posInStage.x, posInStage.y, 0.0) - CVectorD(_PositionLimiter.x, _PositionLimiter.y, 0.0)).norm();
			// Check if the first pos is Not the same as the current entity pos
			if((distToFirst   < ClientCfg.DestThreshold)
			|| (distToLimiter <=  ClientCfg.PositionLimiterRadius))
			{
				// The FIRST POSITION is the SAME as the CURRENT entity POSITION -> REMOVE POSITION in the stage
				stage.removeProperty(CLFECOMMON::PROPERTY_POSX);
				stage.removeProperty(CLFECOMMON::PROPERTY_POSY);
				stage.removeProperty(CLFECOMMON::PROPERTY_POSZ);
				hasPos= false;
				//
				if(VerboseAnimSelection && _Slot == UserEntity->selection())
					nlinfo("CH:updateStages:%d: Bad First, distToFirst(%f), ClientCfg.DestThreshold(%f), distToLimiter(%f), ClientCfg.PositionLimiterRadius(%f)", _Slot,
					distToFirst, ClientCfg.DestThreshold, distToLimiter, ClientCfg.PositionLimiterRadius);
			}
		}

		// stage has pos? => force LCT for it and after
		stageForceLCTFound= stageForceLCTFound || hasPos;


		// *** Compute the estimated Time for the Stage.
		// Compute difference in Game Cycle Between the current Game Cycle and the current Stage.
		sint32 t;
		if(ClientCfg.StageLCTUsage==CClientConfig::StageUseAllLCT)
			t= (*it).first - NetMngr.getCurrentClientTick();
		else if(ClientCfg.StageLCTUsage==CClientConfig::StageUseNoLCT)
			t= (*it).first - NetMngr.getCurrentServerTick();
		else
		{
			// Update LCTImpact for the stage
			if(stageForceLCTFound)
			{
				// Force full impact for stage after or including a POS
				stage.setLCTImpact(256);
			}
			else
			{
				/* minimize the LCT impact with the current char one
					Hence, if the stage had a lct impact lowered, but LCT decrease was canceled,
					the stage will keep its LCT impact
				*/
				stage.setLCTImpact(min(stage.getLCTImpact(), charLCTI));
			}

			sint32	lcti= stage.getLCTImpact();

			// if full impact
			if(lcti>=256)
				t= (*it).first - NetMngr.getCurrentClientTick();
			// if no impact
			else if(lcti<=0)
				t= (*it).first - NetMngr.getCurrentServerTick();
			// else blend
			else
			{
				sint32	twlct= (*it).first - NetMngr.getCurrentClientTick();
				sint32	twolct= (*it).first - NetMngr.getCurrentServerTick();
				t= (twlct*lcti + twolct*(256-lcti))>>8;
			}
		}
		// Compute the estimated Time for the Stage.
		stage.time( (double)(NetMngr.getMachineTimeAtTick() + t*NetMngr.getMsPerTick())/1000.0 );


		// *** Important step is used for "Panic mode" animation acceleration. skip the first stage
		if(_ImportantStepTime==0.0 && it!=_Stages._StageSet.begin())
		{
			// Important steps are ones that takes times (pos, orientation, mode, animation etc....)
			if(	stage.isPresent(PROPERTY_POSITION) ||
				stage.isPresent(PROPERTY_MODE) ||
				stage.isPresent(PROPERTY_ORIENTATION) ||
				stage.isPresent(PROPERTY_ENTITY_MOUNTED_ID) ||
				stage.isPresent(PROPERTY_RIDER_ENTITY_ID) ||
				stage.isPresent(PROPERTY_BEHAVIOUR))
				_ImportantStepTime= stage.time();
		}


		// *** Compute dist2dest (until a mode) if has pos
		if((_IsThereAMode==false) && hasPos)
		{
			// Set the destination pos and time.
			_DestPos= posInStage;
			_DestTime = stage.time() + (double)(stage.predictedInterval()*NetMngr.getMsPerTick())/1000.0;
			// Update First Pos.
			if(dist2Dest() == INVALID_DIST)
			{
				_FirstPos = _DestPos;
				_FirstTime = stage.time();
				// Compute the distance to the first position
				double distToFirst   = (CVectorD(_DestPos.x, _DestPos.y, 0.0) - CVectorD(posTmp.x,posTmp.y, 0.0)).norm();
				// Set the Distance to the Destination as the distance to the first position.
				dist2Dest(distToFirst);
				// Set the distance to First Stage.
				dist2FirstPos(distToFirst);
			}
			// Increase distance to destination.
			else
				dist2Dest(dist2Dest() + (CVectorD(_DestPos.x, _DestPos.y, 0.0) - CVectorD(posTmp.x, posTmp.y, 0.0)).norm());
			// Backup the last pos.
			posTmp = _DestPos;
		}
		// Stop if there is a mode in the stage.
		if(stage.isPresent(CLFECOMMON::PROPERTY_MODE))
			_IsThereAMode = true;


		// *** NEXT STAGE
		itTmp = it;
		++it;
		// REMOVE EMPTY STAGE (because only position and the same as the current one).
		if(stage.empty())
			_Stages._StageSet.erase(itTmp);
	}

	// If there is no mode in queue, mode wanted is the current mode
	// It must usually be the theorical one except for some mode used only by the client like SWIM
	if(!_IsThereAMode)
		_ModeWanted = _Mode;

	// ***** update _StartDecreaseLCTImpact
	// If a stage that force LCT has been found in the list
	if(stageForceLCTFound)
		// Decrease of LCT is disabled
		_StartDecreaseLCTImpact= 0;
	else if(_StartDecreaseLCTImpact==0)
		// Start to decrease LCT
		_StartDecreaseLCTImpact= NetMngr.getCurrentServerTick();


	// ***** compute _RunStartTimeNoPop (see _RunStartTimeNoPop)
	_RunStartTimeNoPop= INVALID_TIME;
	// only if have some pos in the queue
	if(somePosFoundEarly)
	{
		double	d2fp = 0.0;
		double	fpTime= INVALID_TIME;
		// if the first pos is computed, use it
		if(_FirstTime!=INVALID_TIME)
		{
			d2fp= dist2FirstPos();
			fpTime= _FirstTime;
		}
		// else try to compute the first pos, WIHTOUT regarding if there is a mode or not
		// (because even mode anim can be accelerated....)
		else
		{
			it = _Stages._StageSet.begin();
			while(it != _Stages._StageSet.end())
			{
				CStage &stage = (*it).second;
				CVectorD	firstPos;
				if(stage.getPos(firstPos))
				{
					fpTime = stage.time() + (double)(stage.predictedInterval()*NetMngr.getMsPerTick())/1000.0;
					d2fp= CVectorD(firstPos.x-pos().x, firstPos.y-pos().y, 0.0).norm();
					break;
				}
				it++;
			}
		}

		// with d2fp, fpTime, and maxSpeed, we can estimate the moment where the run should start
		if(fpTime!=INVALID_TIME)
		{
			float	maxSpeed= (float)getMaxSpeed();
			if(maxSpeed>0)
			{
				// compute at which time the first move should begin so it doesn't have to accelerate
				_RunStartTimeNoPop= fpTime - d2fp/maxSpeed;
			}
		}
	}

}// updateStages //

//-----------------------------------------------
// beginImpact :
// Return if the impact must be played.
// \param anim : pointer on the current animation (MUST NOT BE NULL).
// \param currentTime : current time in the animation.
// \param triggerName : name of the trigger to check.
// \param isActive : read (and can change) the state.
// \param timeFactor : when to activate the impact if there is no track (value has to be between 0 and 1 to be valid).
// \return bool : true if the trigger is valid.
// \warning This method does not check if the animation is Null.
//-----------------------------------------------
ADD_METHOD(bool CCharacterCL::beginImpact(NL3D::UAnimation *anim, NL3D::TAnimationTime currentTime, const std::string &triggerName, bool &isActive, float timeFactor))
	// Is the impact already activeated.
	if(isActive)
		return false;

	// Try to find the impact trigger in the animation.
	UTrack *Track = anim->getTrackByName(triggerName.c_str());
	// No track -> just check with 2/3 animation
	if(Track)
	{
		if(Track->interpolate(currentTime, isActive))
			return isActive;
		else
			nlwarning("CH:beginImpact:%d: Wrong type asked.", _Slot);
	}

	// No Track or pb with it so try with the animation length.
	float length = (float)(anim->getEndTime()-anim->getBeginTime());
	isActive = (animOffset(MOVE) >= length*timeFactor);
	return isActive;
}// beginImpact //

//-----------------------------------------------
// animEventsProcessing :
// Manage Events that could be created by the animation (like sound).
// \param startTime : time to start processing events from the current animation.
// \param stopTime : time to stop processing events from the current animation.
// \todo GUIGUI : Optimize FXs launch when we would have time
//-----------------------------------------------
void CCharacterCL::animEventsProcessing(double startTime, double stopTime)
{
	if (_CurrentState == 0)
		return;

	// \todo Vianney : temp le temps de savoir comment on joue les son pour le propre joueur
	// No sound for the player.
	if(_Slot != 0 || _Mode != MBEHAV::NORMAL)
	{
		// Retreive the surface material
		uint32 matId= getGroundType();
		// Set the material id var
		_SoundContext.Args[0] = matId;
		if(_Sheet)
		{
			// Set the sound family var
			_SoundContext.Args[2] = _Sheet->SoundFamily;
			// Set the sound variation var
			_SoundContext.Args[3] = _Sheet->SoundVariation;
		}
		else
		{
			// Set the sound family var
			_SoundContext.Args[2] = 0;
			// Set the sound variation var
			_SoundContext.Args[3] = 0;
		}
		// Sound Process.
		CSoundAnimManager* sndMngr = CSoundAnimManager::instance();
		if(sndMngr && (_SoundId[MOVE] != CSoundAnimationNoId))
		{
			_SoundContext.Position = pos();
			// Look for the cluster(s) containing this character...
			std::vector<NL3D::CCluster*>	clusters;
			if (!_Instance.empty())
			{
				// single meshed
				_Instance.getLastParentClusters(clusters);
			}
			else if (!_Skeleton.empty())
			{
				// Skel meshed
				_Skeleton.getLastParentClusters(clusters);
			}
			CCluster *pcluster = 0;
			// use the first cluster if at leat one available
			if (!clusters.empty())
				pcluster = clusters.front();
			sndMngr->playAnimation(_SoundId[MOVE], (float) startTime, (float) stopTime, pcluster, _SoundContext);
		}
	}

}// animEventsProcessing //

//-----------------------------------------------
// updatePreCollision :
// Method called each frame to manage the entity.
// \param time : current time of the frame.
// \parem target : pointer on the current entity target.
//-----------------------------------------------
void CCharacterCL::updatePreCollision(const TTime &currentTimeInMs, CEntityCL *target)	// virtual
{
	H_AUTO ( RZ_Client_Entity_CL_Update_Pre_Collision );
	// Set the Last frame PACS Pos.
	if(_Primitive)
		_Primitive->getGlobalPosition(_LastFramePACSPos, dynamicWI);
	// Set the previous position before changing the current one.
	_LastFramePos = _Position;

	// Turn towards the target when in COMBAT_FLOAT mode.
	if(_Mode == MBEHAV::COMBAT_FLOAT)
	{
		H_AUTO ( RZ_Client_Entity_CL_Update_Combat )

		// Check there is a valid target and it's not the entity itself.
		if(targetSlot() != CLFECOMMON::INVALID_SLOT
		&& targetSlot() != slot()
		&& target)
			// Set the new entity direction
			front(target->pos() - pos(), true, false);
	}

	// Update Position if not a child & displayable.
	if(parent() == CLFECOMMON::INVALID_SLOT && _Displayable)
	{
		H_AUTO ( RZ_Client_Entity_CL_Update_Pos )
		updatePos(currentTimeInMs, target);
	}
}// updatePreCollision //

//-----------------------------------------------
// updateFX :
// Apply track on fxs
// Check if some FX should be removed.
//-----------------------------------------------
inline void CCharacterCL::updateFX()
{
	updateAttachedFX();
}// updateFX //


//-----------------------------------------------
// updateAttachedFX :
// Apply track on animated fxs
// Remove those that should be removed
//-----------------------------------------------
void CCharacterCL::updateAttachedFX()
{
	// build align matrix
	CMatrix alignMatrix;
	buildAlignMatrix(alignMatrix);

	std::list<CAttachedFX::CBuildInfo>::iterator itAttachedFxToStart = _AttachedFXListToStart.begin();
	while(itAttachedFxToStart != _AttachedFXListToStart.end())
	{
		if ((*itAttachedFxToStart).DelayBeforeStart < (float)(TimeInSec - (*itAttachedFxToStart).StartTime))
		{
			uint index = (*itAttachedFxToStart).MaxNumAnimCount;
			(*itAttachedFxToStart).MaxNumAnimCount = 0;
			CAttachedFX::TSmartPtr fx = new CAttachedFX;
			fx->create(*this, (*itAttachedFxToStart), CAttachedFX::CTargeterInfo());
			if (!fx->FX.empty())
			{
				_AuraFX[index] = fx;
			}
			itAttachedFxToStart = _AttachedFXListToStart.erase(itAttachedFxToStart);
		}
		else
		{
			++itAttachedFxToStart;
		}
	}

	// update tracks & pos for anim attachedfxs
	std::list<CAttachedFX::TSmartPtr>::iterator itAttachedFx = _AttachedFXListForCurrentAnim.begin();
	while(itAttachedFx != _AttachedFXListForCurrentAnim.end())
	{
		nlassert(*itAttachedFx);
		CAttachedFX &attachedFX = **itAttachedFx;
		attachedFX.update(*this, alignMatrix);
		if (!attachedFX.FX.empty()) attachedFX.FX.setUserMatrix(alignMatrix);
		++itAttachedFx;
	}

	// Try to remove animation FXs still not removed.
	itAttachedFx = _AttachedFXListToRemove.begin();
	while(itAttachedFx != _AttachedFXListToRemove.end())
	{
		// If the FX is not present or valid -> remove the FX.
		bool mustDelete = false;
		CAttachedFX &attachedFX = **itAttachedFx;
		if (attachedFX.SpawnTime != TimeInSec)
		{
			if(attachedFX.FX.empty() || !attachedFX.FX.isSystemPresent() || !attachedFX.FX.isValid())
			{
				mustDelete = true;
			}
		}
		if (attachedFX.TimeOutDate != 0)
		{
			if (TimeInSec >= attachedFX.TimeOutDate)
			{
				mustDelete = true;
			}
		}
		if (mustDelete)
		{
			// Remove from the list.
			itAttachedFx = _AttachedFXListToRemove.erase(itAttachedFx);
		}
		else
		{
			attachedFX.update(*this, alignMatrix);
			if (!attachedFX.FX.empty()) attachedFX.FX.setUserMatrix(alignMatrix);
			++itAttachedFx;
		}
	}

	// update the aura fx
	for(uint k = 0; k < MaxNumAura; ++k)
	{
		if (_AuraFX[k])
		{
			if (_AuraFX[k]->TimeOutDate != 0.f) // we use that flag to mark the aura as 'shutting down'
			{
				if (TimeInSec >= _AuraFX[k]->TimeOutDate)
				{
					_AuraFX[k] = NULL;
				}
				else
				{
					float lifeRatio = (float) ((_AuraFX[k]->TimeOutDate - TimeInSec) / AURA_SHUTDOWN_TIME);
					if (!_AuraFX[k]->FX.empty()) _AuraFX[k]->FX.setUserParam(0, 1.f - lifeRatio);
				}
			}
			if (_AuraFX[k]) // not deleted yet ?
			{
				// update position & orientation
				_AuraFX[k]->update(*this, alignMatrix);
			}
		}
	}

	// update the link fx
	if (_LinkFX)
	{
		_LinkFX->update(*this, alignMatrix);
	}
	if (_StaticFX)
	{
		_StaticFX->FX->update(*this, alignMatrix);
	}
}




//-----------------------------------------------
// updateVisible :
//-----------------------------------------------
void CCharacterCL::updateVisible (const TTime &currentTimeInMs, CEntityCL *target)
{
	// Changes the skeleton state
	if(!_Skeleton.empty())
	{
		_Skeleton.show();
	}
	// Changes the instance position.
	else if(!_Instance.empty())
	{
		_Instance.show();
	}

	// Snap the entity to the ground.
	{
		H_AUTO ( RZ_Client_Entity_CL_Update_Snap_To_Ground )
		snapToGround();
	}

	// Apply the new entity position to the visual of the entity (apply x and z movement due to animation).
	if(parent() == CLFECOMMON::INVALID_SLOT)
	{
		H_AUTO ( RZ_Client_Entity_CL_Update_Display )
		updateDisplay();
	}

	// Change the cluster of the entity.
	{
		H_AUTO ( RZ_Client_Entity_CL_Update_Cluster )
		updateCluster();
	}

	// Update the LodCharacter Animation.
	if(_LodCharacterAnimEnabled)
	{
		H_AUTO ( RZ_Client_Entity_CL_Update_Pos_Lod_Animation )

		// set this value to the skeleton
		if(skeleton())
			skeleton()->setLodCharacterAnimTime(_LodCharacterAnimTimeOffset);
	}

	// Update FX
	{
		H_AUTO ( RZ_Client_Entity_CL_Update_FX )
		updateFX();
	}

	// Update Modifiers
	if(!_HPModifiers.empty())
	{
		HPMD mod;
		mod.CHPModifier::operator= (*_HPModifiers.begin());
		mod.Time = TimeInSec + mod.DeltaT;
		_HPDisplayed.push_back(mod);
		_HPModifiers.erase(_HPModifiers.begin());
	}

	// Parent
	CEntityCL::updateVisible(currentTimeInMs, target);
}// updateVisible //

//-----------------------------------------------
// updateSomeClipped :
//-----------------------------------------------
void CCharacterCL::updateSomeClipped (const TTime &currentTimeInMs, CEntityCL *target)
{
	// Snap the entity to the ground.
	{
		H_AUTO ( RZ_Client_Entity_CL_Update_Snap_To_Ground )
		snapToGround();
	}

	// Changes the skeleton position.
	if(!_Skeleton.empty())
	{
		_Skeleton.setPos(pos());
		_Skeleton.hide();
	}
	// Changes the instance position.
	else if(!_Instance.empty())
	{
		_Instance.setPos(pos());
		_Instance.hide();
	}

	if(!ClientCfg.Light)
	{
		// Update texture Async Loading
		updateAsyncTexture();
		// Update lod Texture
		updateLodTexture();

		// Update FX
		{
			H_AUTO ( RZ_Client_Entity_CL_Update_FX )
			updateFX();
		}
	}

	// Remove Modifiers.
	_HPModifiers.clear();
	_HPDisplayed.clear();

	// Parent
	CEntityCL::updateSomeClipped(currentTimeInMs, target);
}// updateSomeClipped //

//-----------------------------------------------
// updateClipped :
//-----------------------------------------------
void CCharacterCL::updateClipped (const TTime &currentTimeInMs, CEntityCL *target)
{
	// hide the scene interface
	if (_InSceneUserInterface)
	{
		if (_InSceneUserInterface->getActive())
			_InSceneUserInterface->setActive (false);
	}
	if (_CurrentBubble)
	{
		if (_CurrentBubble->getActive())
			_CurrentBubble->setActive (false);
	}

	// parent
	CEntityCL::updateClipped(currentTimeInMs, target);
}// updateClipped //

//-----------------------------------------------
// updateVisiblePostPos :
// Update the entity after all positions done.
//-----------------------------------------------
void CCharacterCL::updateVisiblePostPos(const NLMISC::TTime &currentTimeInMs, CEntityCL *target)	// virtual
{
	// Stuff to do only when alive.
	if(!isDead())
	{
		// Update the head direction.
		{
			H_AUTO ( RZ_Client_Entity_CL_Update_Head_Direction )
				updateHeadDirection(target);
		}
		// Update Blink.
		{
			H_AUTO ( RZ_Client_Entity_CL_Update_Blink )
				updateBlink(currentTimeInMs);
		}
	}

	// Update in scene interface
	if(_InSceneUserInterface || _CurrentBubble)
	{
		// Draw the entity Name if asked or under the cursor.
		bool showIS = mustShowInsceneInterface( (!_Sheet) || (_Sheet->DisplayOSD) );
		bool showBubble = true;

		// Don't show bubble if lod
		if (!_Skeleton.empty() && _Skeleton.isDisplayedAsLodCharacter())
		{
			showBubble = false;
		}

		// If the name of the character is unknown, no user info
		if (_EntityName.empty() && _Title.empty())
			showIS = false;

		// if mounted : don't display name
		if( _Rider != CLFECOMMON::INVALID_SLOT)
		{
			showIS = false;
		}


		// User Info
		if (_InSceneUserInterface)
		{
			// Activate
			_InSceneUserInterface->setActive (showIS);

			if (showIS)
			{
				// Update dynamic data
				_InSceneUserInterface->updateDynamicData ();

				NLMISC::CVectorD pos;
				if (getNamePos(pos))
				{
					// Check the pos validity
					if((isValidDouble(pos.x) && isValidDouble(pos.y) && isValidDouble(pos.z)) == false)
					{
						nlwarning("CH:updateVisiblePostPos:%d: invalid pos %f %f %f", _Slot, pos.x, pos.y, pos.z);
						nlstop;
					}
					_InSceneUserInterface->Position = pos;
				}
				else
				{
					pos = (box().getMin() + box().getMax())/2;
					pos.z = box().getMax().z;
					nlassert(isValidDouble(pos.x) && isValidDouble(pos.y) && isValidDouble(pos.z));
					_InSceneUserInterface->Position = pos;
				}
			}
		}

		// Bubble ?
		if (_CurrentBubble)
		{
			showBubble &= _CurrentBubble->canBeShown();

			// Activate
			if (_CurrentBubble->getActive() != showBubble)
				_CurrentBubble->setActive (showBubble);

			if (showBubble)
			{
				// Offset X
				sint offsetX = 0;
				if (_InSceneUserInterface)
					offsetX = - 10 -  (_InSceneUserInterface->getWReal() / 2);
				_CurrentBubble->setOffsetX (offsetX);

				NLMISC::CVectorD pos;
				if (!getNamePos(pos))
				{
					pos = (box().getMin() + box().getMax())/2;
					pos.z = box().getMax().z;
				}
				nlassert(isValidDouble(pos.x) && isValidDouble(pos.y) && isValidDouble(pos.z));
				_CurrentBubble->Position = pos;
			}
		}
	}

	// parent
	CEntityCL::updateVisiblePostPos(currentTimeInMs, target);
}// updateVisiblePostPos //


//-----------------------------------------------
// updatePostCollision :
// Method called each frame to manage the entity.
// \param time : current time of the frame.
// \parem target : pointer on the current entity target.
//-----------------------------------------------
void CCharacterCL::updatePostCollision(const TTime &/* currentTimeInMs */, CEntityCL * /* target */)	// virtual
{
	H_AUTO ( RZ_Client_Entity_CL_Update_Post_Collision )

	// Finalize PACS position
	{
		H_AUTO ( RZ_Client_Entity_CL_Update_Finalize_Move )
		pacsFinalizeMove();
		// \todo GUIGUI : fait rapidement pour voir les autres se baigner pour la video, faire mieux.

		// changed : Malkav , also do this for mektoub (as they can swim)
		if(PACS && _Primitive
			&& (isPlayer() || isNPC()
				|| (_Sheet && (_Sheet->Race == EGSPD::CPeople::MektoubMount || _Sheet->Race == EGSPD::CPeople::MektoubPacker))
				)
			)
		{
			// Is in water ?
			if(GR)
			{
				UGlobalPosition gPos;
				_Primitive->getGlobalPosition(gPos, dynamicWI);
				float waterHeight;
				if(GR->isWaterPosition(gPos, waterHeight))
				{
					if(isSwimming()==false)
					{
						if(isDead())
						{
							_Mode = MBEHAV::SWIM_DEATH;
						}
						else if (isRiding())
						{
							_Mode = MBEHAV::MOUNT_SWIM;

							// also change mounted entity mode
							if (_Mount != CLFECOMMON::INVALID_SLOT)
							{
								CCharacterCL *mount = dynamic_cast<CCharacterCL *>(EntitiesMngr.entity(_Mount));
								if(mount)
								{
									// Set the mount.
									mount->setMode(MBEHAV::MOUNT_SWIM);
									mount->computeAutomaton();
									mount->computeAnimSet();
									mount->setAnim(CAnimationStateSheet::Idle);
								}
							}
						}
						else
						{
							_Mode = MBEHAV::SWIM;
						}

						// Compute the current automaton
						computeAutomaton();
						// Update the animation set according to the mode.
						computeAnimSet();
						// Animset changed -> update current animation
						setAnim(CAnimationStateSheet::Idle);
					}
				}
				else
				{
					if(isSwimming())
					{
						if(isDead())
						{
							_Mode = MBEHAV::DEATH;
						}
						else if (isRiding())
						{
							_Mode = MBEHAV::MOUNT_NORMAL;
							// also change mounted entity mode
							if (_Mount != CLFECOMMON::INVALID_SLOT)
							{
								CCharacterCL *mount = dynamic_cast<CCharacterCL *>(EntitiesMngr.entity(_Mount));
								if(mount)
								{
									// Set the mount.
									mount->setMode(MBEHAV::MOUNT_NORMAL);
									mount->computeAutomaton();
									mount->computeAnimSet();
									mount->setAnim(CAnimationStateSheet::Idle);
								}
							}
						}
						else
						{
							_Mode = MBEHAV::NORMAL;
						}

						// Compute the current automaton
						computeAutomaton();
						// Update the animation set according to the mode.
						computeAnimSet();
						// Animset changed -> update current animation
						setAnim(CAnimationStateSheet::Idle);
					}
				}
			}
		}
	}
}// updatePostCollision //


//-----------------------------------------------
// getTheMove :
//-----------------------------------------------
double CCharacterCL::getTheMove(double loopTimeStep, double oldMovingTimeOffset, double oldMovingTimeOffsetRun) const
{
	double move;
	if(_CurrentState)
	{
		// A Real Move State
		if(_CurrentState->Move)
		{
			// Get the covered distance from the animation.
			move = getTheMove(loopTimeStep, oldMovingTimeOffset, MOVE);
			if(runFactor() > 0.0)
			{
				// Blend the 2 move (Walk & Run).
				move = move*(1.0-runFactor()) + getTheMove(loopTimeStep, oldMovingTimeOffsetRun, MOVE_BLEND_OUT)*runFactor();
				// The move must be significant.
				if((move>0.0) && (move<ClientCfg.SignificantDist))
					move = ClientCfg.SignificantDist;
			}
		}
		// Slide
		else if(_CurrentState->Slide)
		{
			move = speed() * loopTimeStep;
			// The move must be significant.
			if((move>0.0) && (move<ClientCfg.SignificantDist))
				move = ClientCfg.SignificantDist;
		}
		else
			move = 0.0;
	}
	else
	{
		move = speed() * loopTimeStep;
		// The move must be significant.
		if((move>0.0) && (move<ClientCfg.SignificantDist))
			move = ClientCfg.SignificantDist;
	}
	// Check the move is significant.
	CHECK(!((move>0.0) && (move<ClientCfg.SignificantDist)));
	// Return the move done by the entity since last time.
	return move;
}// getTheMove //
//-----------------------------------------------
// getTheMove :
//-----------------------------------------------
double CCharacterCL::getTheMove(double loopTimeStep, double oldMovingTimeOffset, TAnimationType channel) const
{
	double move;
	// Compute a linear motion when the animation is missing.
	if(animIndex(channel) == CAnimation::UnknownAnim)
	{
		double offsetT = _DestTime - _LastFrameTime;
		if(offsetT <= 0.0)
		{
			// \todo GUIGUI : in this case, 'loopTimeStep' should not decrease so FIX IT.
			move = dist2Dest();
		}
		else
		{
			move = dist2Dest() * (loopTimeStep / offsetT);
			// The move must be significant.
			if((move>0.0) && (move<ClientCfg.SignificantDist))
				move = ClientCfg.SignificantDist;
		}
	}
	// Get the motion done by the animation.
	else
		move = computeMotion(oldMovingTimeOffset, channel);

	CHECK(!(move>0.0 && move<ClientCfg.SignificantDist));
	return move;
}// getTheMove //

//-----------------------------------------------
// updatePosCombatFloat :
//-----------------------------------------------
void CCharacterCL::updatePosCombatFloat(double /* frameTimeRemaining */, CEntityCL *target)	// virtual
{
	H_AUTO_USE ( RZ_Client_Character_CL_Update_Pos_Combat_Float )

	// The target is valid
	if(target)
	{
		// Get the position where the attacker should go to attack his target according to the attack angle.
		CVectorD dirToTarget = target->pos() - pos();
		dirToTarget.z = 0.0;
		if(ClientCfg.Local
		|| ((dirToTarget != CVectorD::Null)
		&& fabs(target->pos().x-target->lastFramePos().x)>0.01
		&& fabs(target->pos().y-target->lastFramePos().y)>0.01))
		{
			double angToTarget = atan2(dirToTarget.y, dirToTarget.x);
			_DestPos = target->getAttackerPos(angToTarget, attackRadius() + ClientCfg.AttackDist);
		}
		else
			_DestPos = target->getAttackerPos(_TargetAngle, attackRadius() + ClientCfg.AttackDist);
		// Compute the distance to destination.
		CVectorD vectToDest = _DestPos - pos();
		vectToDest.z = 0.0;
		// Distance to destination is big enough.
		if(vectToDest.norm() > ClientCfg.DestThreshold)
		{
			dist2Dest(vectToDest.norm());
			// Compute the time to reach the destination at the max speed.
			double lengthOfTimeToDest = 0.0; // 0 = No Speed Limit
			_FirstPos	= _DestPos;
			_DestTime	= _LastFrameTime + lengthOfTimeToDest + ClientCfg.ChaseReactionTime;
			_FirstTime	= _DestTime;
/*
			// The time remaining will be enough to reach the destination
			if(frameTimeRemaining >= lengthOfTimeToDest)
			{
				_FirstPos	= _DestPos;
				_DestTime	= _LastFrameTime + lengthOfTimeToDest + ClientCfg.ChaseReactionTime;
				_FirstTime	= _DestTime;
			}
			// The time remaining is not enough to reach the destination at max speed -> compute a first pos possible to reach.
			else
			{
				_FirstPos	= pos() + vectToDest*frameTimeRemaining/lengthOfTimeToDest;
				_DestTime	= _LastFrameTime + lengthOfTimeToDest + ClientCfg.ChaseReactionTime;
				_FirstTime	= _LastFrameTime + frameTimeRemaining + ClientCfg.ChaseReactionTime;
			}
*/
			// Compute the distance to the first position.
			CVectorD tmp2computeDist2FirstPos = _FirstPos-pos();
			tmp2computeDist2FirstPos.z = 0.0;
			dist2FirstPos(tmp2computeDist2FirstPos.norm());

			updatePosCombatFloatChanged(target);
		}
		// Destination is too close (will consider to be at destination.
		else
		{
			_FirstPos		= _DestPos		= pos();
			dist2Dest(0.0);
			dist2FirstPos(0.0);
			_FirstTime		= _DestTime		= _LastFrameTime;
		}
	}
	// The target is not allocated.
	else
	{
		_FirstPos		= _DestPos		= pos();
		dist2Dest(0.0);
		dist2FirstPos(0.0);
		_FirstTime		= _DestTime		= _LastFrameTime;
	}
}// updatePosCombatFloat //

//-----------------------------------------------
// updatePos :
// Upadte the player position
// \param time : Time for the position of the entity after the motion.
// \param target : pointer on the current target.
// \todo GUIGUI : compute it when receiving a new stage instead of every frame (should be faster).
// \todo GUIGUI: recompute distance to destination even if the Stage not reached.
//-----------------------------------------------
ADD_METHOD(void CCharacterCL::updatePos(const TTime &currentTimeInMs, CEntityCL *target))
	_OldAutomaton = _CurrentAutomaton;
	// Compute the Time Step.
	double frameTimeRemaining = computeTimeStep(((double)currentTimeInMs)*0.001);
	// Update the LodCharacter Animation.
	if(_LodCharacterAnimEnabled)
	{
		H_AUTO ( RZ_Client_Entity_CL_Update_Pos_Lod_Animation );
		// \todo GUIGUI : replace 'getSpeedFactor' by the correct speed factor !!
		// update lod anim time. multiply by speed factor of the most important slot.
		_LodCharacterAnimTimeOffset += DT * _PlayList->getSpeedFactor(_LodCharacterMasterAnimSlot);
	}
	// BLEND
	if(_PlayList)
	{
		H_AUTO ( RZ_Client_Entity_CL_Update_Pos_Set_Play_List );
		// \todo GUIGUI : do something better for the blend (mounts there).
		if(isRiding() || ClientCfg.BlendFrameNumber == 0 || _BlendRemaining <= 0)
		{
			_BlendRemaining = 0;
			_PlayList->setAnimation(ACTION, UPlayList::empty);
			_PlayList->setWeight(ACTION, 0.0f);
			if(runFactor() < 0.5 || (_CurrentAnimSet[MOVE_BLEND_OUT]==0))
			{
				if(_CurrentAnimSet[MOVE])
				{
					_CurrentAnimSet[ACTION] = _CurrentAnimSet      [MOVE];
					animState (ACTION, animState (MOVE));
					animIndex (ACTION, animIndex (MOVE));			// This also call "animId" and set it.
					animOffset(ACTION, animOffset(MOVE));
				}
				else
				{
					_CurrentAnimSet[ACTION] = 0;
					animState (ACTION, CAnimationStateSheet::UnknownState);
					animIndex (ACTION, CAnimation::UnknownAnim);	// This also call "animId" and set it.
					animOffset(ACTION, 0.0);
				}
			}
			else
			{
				_CurrentAnimSet[ACTION] = _CurrentAnimSet      [MOVE_BLEND_OUT];
				animState (ACTION, animState (MOVE_BLEND_OUT));
				animIndex (ACTION, animIndex (MOVE_BLEND_OUT));	// This also call "animId" and set it.
				animOffset(ACTION, animOffset(MOVE_BLEND_OUT));
			}
			_AnimReversed[ACTION] = false;
		}
		else
		{
			double animLength = EAM->getAnimationLength(animId(ACTION));
			// Check Anim length
			if(animOffset(ACTION)+frameTimeRemaining > animLength)
				animOffset(ACTION, animLength);
			else
				animOffset(ACTION, animOffset(ACTION)+frameTimeRemaining);
			// Compute weight step.
			float w = (float)_BlendRemaining/(float)(ClientCfg.BlendFrameNumber+1);
			// Set Old Anim Weight.
			_PlayList->setWeight(ACTION, w);
			// Set New Anim Weight.
			_PlayList->setWeight(MOVE, 1.f-w);
		}
	}
	uint antiFreezeCounter = 0;
	// While the time Step is not Null.
	while(frameTimeRemaining > 0)
	{
		H_AUTO ( RZ_Client_Entity_CL_Update_Pos_WhileStep );

		//--------------------//
		//--------------------//
		// ANTI-FREEZE SYSTEM //
		// If too many loop, display some infos
		if(antiFreezeCounter > 50)
		{
/*
			nlwarning("CH:updatePos:antiFreeze:%d: frameTimeRemaining '%f'",  _Slot, frameTimeRemaining);
			nlwarning("CH:updatePos:antiFreeze:%d: Automaton '%s'",           _Slot, _CurrentAutomaton.c_str());
			nlwarning("CH:updatePos:antiFreeze:%d: _IsThereAMode '%s'",       _Slot, _IsThereAMode?"true":"false");
			nlwarning("CH:updatePos:antiFreeze:%d: dist2Dest '%f'",           _Slot, dist2Dest());
			nlwarning("CH:updatePos:antiFreeze:%d: Mode '%s(%d)'",            _Slot, modeToString(_Mode).c_str(), _Mode);
			nlwarning("CH:updatePos:antiFreeze:%d: Mode Wanted '%s(%d)'",     _Slot, modeToString(_ModeWanted).c_str(), _ModeWanted);
			nlwarning("CH:updatePos:antiFreeze:%d: Anim State Move '%s(%d)'", _Slot, CAnimationState::getAnimationStateName(animState(MOVE)).c_str(), animState(MOVE));
*/
			// Once too many more time reached, leave the method.
			if(antiFreezeCounter > 60)
				break;
		}
		// Update antiFreezeCounter.
		++antiFreezeCounter;
		// ANTI-FREEZE SYSTEM //
		//--------------------//
		//--------------------//
		// \todo GUIGUI : improve dist2first and dist2dest
		// Update Stages
		updateStages();
		// \todo GUIGUI : Bug with _TargetAngle in fight float, we overwrite here angle sent by the server ?
		// If the entity is too far (orientation not received yet), set the front vector as the moving direction.
		CVectorD distToUser = pos()-UserEntity->pos();
		distToUser.z = 0.0;
		if(distToUser.norm()*1000.0 > CLFECOMMON::THRESHOLD_ORIENTATION*0.9)
		{
			if(_FirstPos != INVALID_POS)
			{
				CVectorD dirToFirstP = _FirstPos-pos();
				dirToFirstP.z = 0.0;
				if(dirToFirstP != CVectorD::Null)
				{
					front(dirToFirstP.normed(), false, false);
					_TargetAngle = atan2(front().y, front().x);
				}
			}
		}
		// Mode Combat Float :
		if(!_IsThereAMode && (_Mode == MBEHAV::COMBAT_FLOAT))
		{
			// Update the position in combat float.
			updatePosCombatFloat(frameTimeRemaining, target);
		}
		// Compute the average speed to the destination.
		// double spd = 
		computeSpeed();


		bool stageReach = false;
		bool allToFirstPos = false;
		// Compute time to Stage or full Time Step if Stage too far.
		double loopTimeStep = frameTimeRemaining;
		double buLoopTimeStep = 0.0;
		double checkLoopTimeStep = loopTimeStep;
		// Update the animation used according to the speed/end anim/etc..
		updateAnimationState();
		// Backup the old time offset.
		double oldMovingTimeOffset    = animOffset(MOVE);
		double oldMovingTimeOffsetRun = animOffset(MOVE_BLEND_OUT);
		// WARNING -> Unknown Animation Selected.
		// Play the time step for the loop and truncate to End Anim if Time Step too big.
		if((_CurrentState != 0) && (animIndex(MOVE) != CAnimation::UnknownAnim))
			playToEndAnim(oldMovingTimeOffset, loopTimeStep);
		/////////////////
		// -- CHECK -- //
		if(loopTimeStep > checkLoopTimeStep)
		{
			nlwarning("CH:updtPos:%d: loopTimeStep(%f) > checkLoopTimeStep(%f).", _Slot, loopTimeStep, checkLoopTimeStep);
			if(ClientCfg.Check)
				nlstop;
			loopTimeStep = checkLoopTimeStep;
		}
		checkLoopTimeStep = loopTimeStep;
		// -- END CHECK -- //
		/////////////////////
		// (DEBUG) : Backup the Animation Time Offset after the adjustment with end anim to make some checks.
		double backupAnimTimeOff = animOffset(MOVE);
		//
		bool posInStage = false;
		double stageTime = -1.0;
		if(!_Stages._StageSet.empty())
		{
			H_AUTO ( RZ_Client_Entity_CL_Update_Pos_Move );
			// Get the reference on the current stage.
			CStageSet::TStageSet::iterator it = _Stages._StageSet.begin();
			CStage &stage = (*it).second;
			if(_Mode == MBEHAV::COMBAT_FLOAT && !_IsThereAMode)
				posInStage = false;
			else
				posInStage = stage.isPresent(CLFECOMMON::PROPERTY_POSITION);
			stageTime  = stage.time();
		}
		// dist2FirstPos() should not be Null if the destination is not Null (because of the code in updateStage).
		if(dist2FirstPos() > 0.0)
		{
			H_AUTO ( RZ_Client_Entity_CL_Update_Pos_dist2FirstPos_gt_0 );

			// Get the covered distance from the animation.
			double move = getTheMove(loopTimeStep, oldMovingTimeOffset, oldMovingTimeOffsetRun);
			// The move is big enough to reach the first step with motion.
			if(move >= dist2FirstPos())	// dist2FirstPos() > 0 -> move > 0.
			{
				double percent = dist2FirstPos() / move;
				// Adjust loopTimeStep
				loopTimeStep *= percent;
				if(loopTimeStep > checkLoopTimeStep)	// prevent bugs because of the double's precision
					loopTimeStep = checkLoopTimeStep;
				if(loopTimeStep < 0.0)
					loopTimeStep = 0.0;
				// Update Animation Time Offset (move greater than the dist to next stage; update animation time to get them equal).
				animOffset(MOVE,           oldMovingTimeOffset    + (animOffset(MOVE)          -oldMovingTimeOffset   )*percent);
				animOffset(MOVE_BLEND_OUT, oldMovingTimeOffsetRun + (animOffset(MOVE_BLEND_OUT)-oldMovingTimeOffsetRun)*percent);
				// \todo GUIGUI : check if the following line is necessary
				buLoopTimeStep = loopTimeStep;
				// First Position Reached
				pos(_FirstPos);
				dist2FirstPos(0.0);	// Current entity position is now the same as the First position so dis is Null.
				// Complete the Stage.
				if(_Mode != MBEHAV::COMBAT_FLOAT || _IsThereAMode)
				{
					if(posInStage)
						stageReach = true;
					else
						allToFirstPos = true;
				}
			}
			// Even if the movement is not enough to reach the first position, move the entity to this position.
			else if(move > 0.0)
			{
				// Compute the vector to the first stage with a position.
				CVectorD vectToFirstPos = _FirstPos - pos();
				vectToFirstPos.z = 0.0f;
				// Update entity position.
				if(vectToFirstPos != CVectorD::Null)
					pos(pos() + vectToFirstPos*(move/dist2FirstPos()));
			}
			// Else : There is no move.
		}
		else
		{
			CHECK(posInStage==false && dist2Dest()<=0.0);
		}

		// If there is no position in the next stage and the stage should be done already.
		if(!_Stages._StageSet.empty() && !posInStage && !stageReach && !allToFirstPos && ((_LastFrameTime+loopTimeStep) >= stageTime))
		{
			// Backup 'loopTimeStep' just in case of the stage could not be done.
			buLoopTimeStep = loopTimeStep;
			// Adjust loopTimeStep
			loopTimeStep = stageTime - _LastFrameTime;
			if(loopTimeStep > checkLoopTimeStep)	// prevent bugs because of the double's precision
				loopTimeStep = checkLoopTimeStep;
			if(loopTimeStep < 0.0)
				loopTimeStep = 0.0;
			//
			// \todo GUIGUI : adjust timeOffset, because we stopped the loop before
			//
			// Stage complete.
			stageReach = true;
		}
		/////////////////
		// -- CHECK -- //
		// Check the Animation Time Offset is not became greater than the old.
		if(animOffset(MOVE) > backupAnimTimeOff)
		{
			nlwarning("CH:updtPos:%d: backupAnimTimeOff(%f) < AnimationsTimeOffset(%f) animLen(%f) -> animOffset(MOVE) = backupAnimTimeOff",
				_Slot, backupAnimTimeOff, animOffset(MOVE), EAM->getAnimationLength(animId(MOVE)));
			if(ClientCfg.Check)
				nlstop;
			animOffset(MOVE, backupAnimTimeOff);
		}
		// Check loopTimeStep is not < 0;
		if(loopTimeStep < 0.0)
		{
			nlwarning("CH:updtPos:%d: loopTimeStep(%f) < 0 -> loopTimeStep=0.0.", _Slot, loopTimeStep);
			if(ClientCfg.Check)
				nlstop;
			loopTimeStep = 0.0;
		}
		// time spent could not be bigger than the time remaining
		if(loopTimeStep > frameTimeRemaining)
		{
			nlwarning("CH:updtPos:%d: loopTimeStep(%f) > frameTimeRemaining(%f) -> loopTimeStep=frameTimeRemaining.", _Slot, loopTimeStep, frameTimeRemaining);
			if(ClientCfg.Check)
				nlstop;
			loopTimeStep = frameTimeRemaining;
		}
		// -- END CHECK -- //
		/////////////////////
		// Manage Events that could be created by the animation (like sound).
		{
			H_AUTO ( RZ_Client_Entity_CL_Update_Pos_Anim_Event )
			animEventsProcessing(oldMovingTimeOffset, animOffset(MOVE));
		}
		// Apply all stages until the first stage with a pos.
		if(allToFirstPos)
		{
			H_AUTO ( RZ_Client_Entity_CL_Update_Pos_Apply_All_Stage_To_First_Pos );
			applyAllStagesToFirstPos();
		}
		// Stage is complete, apply modifications.
		else if(stageReach)
		{
			H_AUTO ( RZ_Client_Entity_CL_Update_Pos_Apply_Current_Stage );
			if(!applyCurrentStage())
				loopTimeStep = buLoopTimeStep;
		}
		// Compute the remaining Time Step.
		frameTimeRemaining -= loopTimeStep;
		// Update the last Time.
		_LastFrameTime += loopTimeStep;
	}// while(frameTimeRemaining > 0) //

	////////////////////////////////
	// UPDATE THE ENTITY POSITION //
	// Set the new position into PACS.
	{
		H_AUTO_USE ( RZ_Client_Entity_CL_Update_Pos_Pacs );
		pacsMove(pos());
	}

	/// (DEBUG) ///
	// Check frameTimeRemaining is perfectly equal to 0.
	if(frameTimeRemaining < 0.0)
		nlwarning("CCharacterCL::updatePos : frameTimeRemaining(%f) < 0 ! This should never happen.", frameTimeRemaining);
	/// (END DEBUG) ///

	// Update the children display.
	{
		H_AUTO ( RZ_Client_Entity_CL_Update_Pos_Children );
		std::list<CEntityCL *>::iterator itTmp, it = _Children.begin();
		while(it != _Children.end())
		{
			itTmp = it;
			// Next Child (done before just in case child is detached during his processFrame).
			it++;

			if(*itTmp)
			{
				CCharacterCL *child = dynamic_cast<CCharacterCL *>(*itTmp);
				if(child)
				{
					if ( ! ClientCfg.Light )
					{
						// Update the animation offset for the child.
						double animLength = EAM->getAnimationLength(animId(MOVE));
						if(animLength > 0.0)
						{
							double factor = animOffset(MOVE) / animLength;
							if(factor > 1.0)
								factor = 1.0;
							double childTimeOffset = factor*EAM->getAnimationLength(child->animId(MOVE));
							child->animOffset(MOVE, childTimeOffset);
						}
						else
							child->animOffset(MOVE, 0.0);
						child->processFrame(currentTimeInMs);
					}
					child->pacsMove(pos());	// Move the child at the same position than the parent.
				}
				else
					nlwarning("Character '%d': Child is not a 'CCharacterCL'.", _Slot);
			}
			else
				nlwarning("Character '%d': Child not allocated.", _Slot);
		}
	}
}// updatePos //

//-----------------------------------------------
// updateVisiblePostRender :
// Update the entity after the render like for the head offset.
//-----------------------------------------------
void CCharacterCL::updateVisiblePostRender()	// virtual
{
	// Compute the headoffset
	if(_HeadBoneId != -1 && !_Skeleton.empty())
	{
		if(_Skeleton.getLastClippedState() && _Skeleton.isBoneComputed(_HeadBoneId))
		{
			UBone headBone=_Skeleton.getBone(_HeadBoneId);
			const CMatrix &headMat = headBone.getLastWorldMatrixComputed();
			_HeadOffset = headMat.getPos()-pos();
			_HeadOffsetComputed= true;
		}
	}
}// updateVisiblePostRender //

//-----------------------------------------------

void CCharacterCL::updateAllPostRender()
{
}

//-----------------------------------------------
// processFrame :
//-----------------------------------------------
void CCharacterCL::processFrame(const TTime &currentTimeInMs)
{
	// Prepare stages and update information from them.
	updateStages();

	// Compute the time remaining until frame completely processed.
	double timeRemaining = computeTimeStep(((double)currentTimeInMs)*0.001);

	// Compute the time spent between 2 frames.
	while(timeRemaining > 0.0)
	{
		// Time already processed until now.
		double timeProcessed = timeRemaining;

		// Process Stages.
		if(!_Stages._StageSet.empty())
		{
			// Get the reference on the current stage.
			CStageSet::TStageSet::iterator it = _Stages._StageSet.begin();
			CStage &stage = (*it).second;

			// Check if the stage should be done already.
			if((_LastFrameTime+timeProcessed) >= stage.time())
			{
				// Stage Done during the Frame.
				if(stage.time() > _LastFrameTime)
					timeProcessed = stage.time() - _LastFrameTime;
				// This Stage should have been done already before last frame
				else
					timeProcessed = 0.0;

				// Process the stage.
				processStage(stage);

				// Stage complete.
				_Stages._StageSet.erase(it);
			}
		}

		// Compute the remaining Time Step.
		timeRemaining -= timeProcessed;
		// Update the last Time.
		_LastFrameTime += timeProcessed;
	}

	// Just to be sure, Last frame time = current time once all is done.
	_LastFrameTime = ((double)currentTimeInMs)*0.001;
}// processFrame //

//-----------------------------------------------
// processStage :
// Process the stage.
//-----------------------------------------------
void CCharacterCL::processStage(CStage &stage)
{
	// Apply Mode (if there is a mode, there is a position too).
	pair<bool, sint64> resultMode = stage.property(PROPERTY_MODE);
	if(resultMode.first)
	{
		uint8 mo = *(uint8 *)(&resultMode.second);
		MBEHAV::EMode mode = (MBEHAV::EMode)mo;
		if(mode != _Mode)
		{
			// release the old mode.
			if ( (_Mode == MBEHAV::MOUNT_NORMAL || _Mode == MBEHAV::MOUNT_SWIM)
				&& (mode != MBEHAV::MOUNT_NORMAL && mode != MBEHAV::MOUNT_SWIM)
				)
			{
				// Unlink the mount and the rider.
				parent(CLFECOMMON::INVALID_SLOT);
				_Mount = CLFECOMMON::INVALID_SLOT;
				_Rider = CLFECOMMON::INVALID_SLOT;

				// Restore collisions.
				if(_Primitive)
				{
					// \todo GUIGUI : do that without dynamic cast
					if(dynamic_cast<CPlayerCL *>(this))
						_Primitive->setOcclusionMask(MaskColPlayer);
					else
						_Primitive->setOcclusionMask(MaskColNpc);
				}

				// Get stage position.
				if(stage.getPos(_OldPos))
				{
					// Backup the time
					_OldPosTime = stage.time();
					// Unseat the entity at the position given in the stage.
					pacsMove(_OldPos);
				}
				else
					nlwarning("CH:processStage:%d: The stage should have a position with the mode.", _Slot);
			}

			// Set the new mode.
			_Mode				= mode;
			_ModeWanted			= mode;
			// Compute the automaton
			computeAutomaton();
			computeAnimSet();
			setAnim(CAnimationStateSheet::Idle);
		}
	}
	// Not a mode -> so search for a position.
}// processStage //


//-----------------------------------------------
// updateBlink :
// Update the player blink state
//-----------------------------------------------
void CCharacterCL::updateBlink(const TTime &currentTimeInMs)
{
	// Only for homine
	GSGENDER::EGender gender = getGender();
	if ((gender == GSGENDER::male) || (gender == GSGENDER::female))
	{
		float blend;

		// Some parameters
		static const double blinkTime = 100.f;
		static const double minBlinkLength = 500.f;
		static const double maxBlinkLength = 5000.f;

		// Next blink time is valid ?
		bool validTime = (_NextBlinkTime + blinkTime >= currentTimeInMs) && (_NextBlinkTime <= (currentTimeInMs + maxBlinkLength));

		// Blink end ?
		bool blinkEnd = (currentTimeInMs >= _NextBlinkTime + blinkTime);

		// Blink is finished or next blink time is invalid ?
		if ( blinkEnd || !validTime )
		{
			blend = 0;

			// Compute next time
			_NextBlinkTime = (TTime)(((double)rand () / (double)RAND_MAX) * (maxBlinkLength - minBlinkLength) + minBlinkLength + (double)currentTimeInMs);
		}
		else
		{
			// Blink time ?
			if (currentTimeInMs >= _NextBlinkTime)
			{
				blend = 100.f;
			}
			else
			{
				// Do nothing
				return;
			}
		}

		// Get the face
		SInstanceCL *face = getFace ();

		// Set the blend shape
		if(face && !face->Current.empty())
			face->Current.setBlendShapeFactor ("visage_100", blend, true);
	}
}// updateBlink //


//-----------------------------------------------
// getFace :
// Update eyes blink. For the moment, called by updatePos.
//-----------------------------------------------
CEntityCL::SInstanceCL *CCharacterCL::getFace ()
{
	// Implemented in CPlayerCL
	return idx2Inst(_FaceIdx);
}


//---------------------------------------------------
// updateDisplay :
// Get the entity position and set all visual stuff with it.
// \todo GUIGUI : put this method 'virtual' to have a different code for the user (no playlist).
// \todo GUIGUI : manage the parent better.
//---------------------------------------------------
ADD_METHOD(void CCharacterCL::updateDisplay(CEntityCL *parent))
	// Animable ?
	if(_PlayList)
	{
		// Reverse the animation if needed.
		const double animOffsetMOV = _AnimReversed[MOVE]           ? EAM->getAnimationLength(animId(MOVE))           - animOffset(MOVE)          : animOffset(MOVE);
		const double animOffsetACT = _AnimReversed[ACTION]         ? EAM->getAnimationLength(animId(ACTION))         - animOffset(ACTION)        : animOffset(ACTION);
		const double animOffsetBLE = _AnimReversed[MOVE_BLEND_OUT] ? EAM->getAnimationLength(animId(MOVE_BLEND_OUT)) - animOffset(MOVE_BLEND_OUT): animOffset(MOVE_BLEND_OUT);
		// Update Speed Factor
		_PlayList->setTimeOrigin(MOVE,           TimeInSec-animOffsetMOV);
		_PlayList->setTimeOrigin(ACTION,         TimeInSec-animOffsetACT);
		_PlayList->setTimeOrigin(MOVE_BLEND_OUT, TimeInSec-animOffsetBLE);
		float weight;
		if(_BlendRemaining)
			weight = _PlayList->getLocalWeight(MOVE, TimeInSec);
		else
			weight = 1.0f;
		_PlayList->setWeight(MOVE,           weight*(float)(1.0-runFactor()));
		_PlayList->setWeight(MOVE_BLEND_OUT, weight*(float)runFactor());
		// If the animation exist update the display.
		if(animIndex(MOVE) != CAnimation::UnknownAnim)
		{
			// POSITION //
			// Get the 3D position for the current time in the animation (Vector Null if animation has no move).
			CVector currentAnimPos;
			if(!EAM->interpolate(animId(MOVE), animOffsetMOV, currentAnimPos))
				currentAnimPos = CVector::Null;
			else
			{
				// If the current animation state is a move, do not take the Y move in the animation because it's the code that compute the move.
				if(_CurrentState && _CurrentState->Move)
				{
					CVector currentAnimPosStart;
					if(!EAM->interpolate(animId(MOVE), 0.0, currentAnimPosStart))
						currentAnimPosStart = CVector::Null;
					if(_CurrentState->XFactor) currentAnimPos.x = currentAnimPosStart.x;
					if(_CurrentState->YFactor) currentAnimPos.y = currentAnimPosStart.y;
					if(_CurrentState->ZFactor) currentAnimPos.z = currentAnimPosStart.z;
				}
				// Scale the animation with the Character Scale Pos if the animation need it.
				{
					bool applyCharacterScalePosFactor = true;
					// \todo GUIGUI : faire cette histoire de emote beaucoup mieux, C NULL.
					const CAnimationState *animStatePtr;
					// If the current animation is an emote, get the right animation state.
					if(animState(MOVE) == CAnimationStateSheet::Emote)
						animStatePtr = _CurrentAnimSet[MOVE]->getAnimationState(_SubStateKey);
					else
						animStatePtr = _CurrentAnimSet[MOVE]->getAnimationState(animState(MOVE));
					if(animStatePtr)
					{
						const CAnimation *anim = animStatePtr->getAnimation(animIndex(MOVE));
						if(anim)
							applyCharacterScalePosFactor = anim->applyCharacterScalePosFactor();
					}
					// scale it.
					if(applyCharacterScalePosFactor)
						currentAnimPos *= _CharacterScalePos;
				}
				// Scale according to the gabarit (choose at the character creation).
				currentAnimPos *= _CustomScalePos;
			}
			// Blend Walk/Run
			if(runFactor() > 0.0)
			{
				CVector currentAnimPosRun;
				if(!EAM->interpolate(animId(MOVE_BLEND_OUT), animOffsetBLE, currentAnimPosRun))
					currentAnimPosRun = CVector::Null;
				else
				{
					// If the current animation state is a move, do not take the Y move in the animation because it's the code that compute the move.
					if(_CurrentState && _CurrentState->Move)
					{
						CVector currentAnimPosStart;
						if(!EAM->interpolate(animId(MOVE_BLEND_OUT), 0.0, currentAnimPosStart))
							currentAnimPosStart = CVector::Null;
						if(_CurrentState->XFactor) currentAnimPosRun.x = currentAnimPosStart.x;
						if(_CurrentState->YFactor) currentAnimPosRun.y = currentAnimPosStart.y;
						if(_CurrentState->ZFactor) currentAnimPosRun.z = currentAnimPosStart.z;
					}
					// Scale it by the CharacterScalePos, if needed, according to the animation.
					bool applyCharacterScalePosFactor = true;
					const CAnimationState *animStatePtr = _CurrentAnimSet[MOVE_BLEND_OUT]->getAnimationState(animState(MOVE_BLEND_OUT));
					if(animStatePtr)
					{
						const CAnimation *anim = animStatePtr->getAnimation(animIndex(MOVE_BLEND_OUT));
						if(anim)
							applyCharacterScalePosFactor = anim->applyCharacterScalePosFactor();
					}
					// scale it.
					if(applyCharacterScalePosFactor)
						currentAnimPosRun *= _CharacterScalePos;
					// Scale according to the gabarit.
					currentAnimPosRun *= _CustomScalePos;
				}

				currentAnimPos = currentAnimPos*(float)(1.0-runFactor()) + currentAnimPosRun*(float)runFactor();
			}
			// ROTATION //
			// Get the rotation for the current time in the animation (Rotation Null if animation has no rotation).
			CQuat currentAnimRot;
			if(!EAM->interpolate(animId(MOVE), animOffsetMOV, currentAnimRot))
				currentAnimRot = CQuat::Identity;
			else
			{
				// If the animation is a rotation -> Do just a part of the animation.
				if(parent==0 && _CurrentState && _CurrentState->Rotation && _RotationFactor!=-1.0)
				{
					// Get the Rotation at the beginning of the animation.
					CQuat currentAnimRotStart;
					if(!EAM->interpolate(_PlayList->getAnimation(MOVE), 0.0, currentAnimRotStart))
						currentAnimRotStart = CQuat::Identity;

					double animLength = EAM->getAnimationLength(animId(MOVE));

					// Get the Rotation at the beginning of the animation.
					CQuat currentAnimRotEnd;
					if(!EAM->interpolate(_PlayList->getAnimation(MOVE), animLength, currentAnimRotEnd))
						currentAnimRotEnd = CQuat::Identity;

					// Get the angle done by the animation from the beginning
					CQuat rotStartTmp = currentAnimRotStart;
					rotStartTmp.invert();
					CQuat rotTmp =  rotStartTmp * currentAnimRot;
					float ang = rotTmp.getAngle();

					currentAnimRot = applyRotationFactor(currentAnimRot, (float)_RotationFactor, currentAnimRotStart, currentAnimRotEnd, (float)(animOffsetMOV/animLength));

					// Get the angle done once scaled.
					rotTmp =  rotStartTmp * currentAnimRot;
					CMatrix rotMat;
					rotMat.identity();
					rotMat.rotateZ(_CurrentState->RotFactor*(ang-rotTmp.getAngle()));

					// Apply the scaled rotation to the position.
					currentAnimPos = rotMat*currentAnimPos;
//// OLD ////
/*
					// Get the Rotation at the beginning of the animation.
					CQuat currentAnimRotStart;
					if(!EAM->interpolate(_PlayList->getAnimation(MOVE), 0.0, currentAnimRotStart))
						currentAnimRotStart = CQuat::Identity;

					// Find the closest quat.
//					currentAnimRotStart.makeClosest(currentAnimRot);

					// Get the angle done by the animation from the beginning
					CQuat rotStartTmp = currentAnimRotStart;
					rotStartTmp.invert();
					CQuat rotTmp =  rotStartTmp * currentAnimRot;
					float ang = rotTmp.getAngle();

					// Get the Rotation scaled.
					currentAnimRot = CQuat::slerp(currentAnimRotStart, currentAnimRot, (float)_RotationFactor);

					// Get the angle done once scaled.
					rotTmp =  rotStartTmp * currentAnimRot;
					CMatrix rotMat;
					rotMat.identity();
					rotMat.rotateZ(_CurrentState->RotFactor*(ang-rotTmp.getAngle()));

					// Apply the scaled rotation to the position.
					currentAnimPos = rotMat*currentAnimPos;
*/
//// FIN OLD ////
				}
			}
			// Blend Walk/Run
			if(runFactor() > 0.0)
			{
				// Get the rotation for the current time in the animation (Rotation Null if animation has no rotation).
				CQuat currentAnimRotRun;
				if(!EAM->interpolate(animId(MOVE_BLEND_OUT), animOffsetBLE, currentAnimRotRun))
					currentAnimRotRun = CQuat::Identity;
				currentAnimRotRun.makeClosest(currentAnimRot);
				currentAnimRot = CQuat::slerp(currentAnimRot, currentAnimRotRun, (float)runFactor());
			}

			// Animation Matrix
			CMatrix AnimMatrixRot;
			AnimMatrixRot.identity();
			AnimMatrixRot.setRot(currentAnimRot);

			// Rotation 180 degrees Matrix
			CMatrix rot180;
			rot180.identity();
			if(parent == 0)
				rot180.rotateZ((float)Pi);

			// Logical entity Matrix.
			CMatrix current;
			if(parent == 0)
				current = _DirMatrix;
			else
				current.identity();

			// Convert the anim position in a world position.
			currentAnimPos = (current*rot180)*currentAnimPos;

			rot180 *= AnimMatrixRot;
			current *= rot180;


			// Get the rotation for the current time in the animation (Rotation Null if animation has no rotation).
			if(ClientCfg.BlendFrameNumber && _BlendRemaining > 0)
			{
				CQuat tmpQuat;
				_OldRotQuat.makeClosest(current.getRot());
				tmpQuat = CQuat::slerp(current.getRot(), _OldRotQuat, ((float)_BlendRemaining/(float)(ClientCfg.BlendFrameNumber+1)));
				current.setRot(tmpQuat);
				// 1 more frame played.
				_BlendRemaining--;
			}


			// Compute the position for the instance.
			CVectorD tmpPos;
			if(parent == 0)
			{
				tmpPos = pos();
				tmpPos += currentAnimPos;
			}
			// If the entity is on a mount, just adjust the position with the animation.
			else
				tmpPos = currentAnimPos;
			// Set the skeleton position and rotation.
			if(!_Skeleton.empty())
			{
				_Skeleton.setRotQuat(current.getRot());
				_Skeleton.setPos(tmpPos);
			}
			// Only Instances with no skeleton (objects).
			else if(!_Instances.empty() && !_Instances[0].Current.empty())
			{
				_Instances[0].Current.setRotQuat(current.getRot());
				_Instances[0].Current.setPos(tmpPos);
			}
			// Set the instance position and rotation.
			else if(!_Instance.empty())
			{
				_Instance.setRotQuat(current.getRot());
				_Instance.setPos(tmpPos);
			}
			else
			{
				static bool once = false;

				if (!once)
				{
					nlwarning("CH::updtDisp:%d: no instance nor skeleton. Sheet Id '%d(%s)'.", _Slot, _SheetId.asInt(), _SheetId.toString().c_str());
					once = true;
				}
			}
		}
		// Else Keep the lastest correct display.
		else
		{
			H_AUTO ( RZ_Client_Entity_CL_Update_Display_Unknown_Anim )

			// Rotation 90 degrees Matrix
			CMatrix rot90;
			rot90.identity();
			if(parent == 0)
				rot90.rotateZ((float)(Pi/2.0));

			// Logical entity Matrix.
			CMatrix current;
			if(parent == 0)
				current = _DirMatrix;
			//			else
			//				current.identity();

			current *= rot90;

			// Changes the skeleton position.
			if(!_Skeleton.empty())
			{
				_Skeleton.setRotQuat(current.getRot());
				if(parent == 0)
					_Skeleton.setPos(pos());
//				else
//					_Skeleton.setPos(currentAnimPos);
			}
			// Only Instances with no skeleton (objects).
			else if(!_Instances.empty() && !_Instances[0].Current.empty())
			{
				_Instances[0].Current.setRotQuat(current.getRot());
				if(parent == 0)
					_Instances[0].Current.setPos(pos());
			}
		}
	}
	else
	{
		// Changes the skeleton position.
		if(!_Skeleton.empty())
		{
			_Skeleton.setPos(pos());
		}
		// Only Instances with no skeleton (objects).
		else if(!_Instances.empty() && !_Instances[0].Current.empty())
		{
			// Logical entity Matrix.
			CMatrix current;
			if(parent == 0)
				current = _DirMatrix;

			_Instances[0].Current.setRotQuat(current.getRot());
			_Instances[0].Current.setPos(pos());
		}
		// Changes the instance position.
		else if(!_Instance.empty())
		{
			_Instance.setPos(pos());
		}
	}

	if(!ClientCfg.Light)
	{
		// update texture Async Loading
		updateAsyncTexture();
		// update lod Texture
		updateLodTexture();

	}

	// Update the children display.
	std::list<CEntityCL *>::iterator it = _Children.begin();
	while(it != _Children.end())
	{
		// Update the display for the child
		(*it)->updateDisplay(this);
		// Next Child.
		++it;
	}
}// updateDisplay //


//---------------------------------------------------
// getHeadPos :
// Method to get the position of the head (in the world).
// \param headPos: will be set with the head position if succeed.
// \return 'true' if the param has been updated.
// \warning this method do NOT check if there is a skeleton.
//---------------------------------------------------
bool CCharacterCL::getHeadPos(NLMISC::CVector &headPos)
{
	// if never computed (eg: clipped or lod)
	if(!_HeadOffsetComputed)
	{
		// force compute the bone
		if(_HeadBoneId != -1 && !_Skeleton.empty())
		{
			_Skeleton.forceComputeBone(_HeadBoneId);
			UBone headBone=_Skeleton.getBone(_HeadBoneId);
			const CMatrix &headMat = headBone.getLastWorldMatrixComputed();
			_HeadOffset = headMat.getPos()-pos();
		}
		_HeadOffsetComputed= true;
	}

	// return the pos with the last head offset computed
	headPos = pos()+_HeadOffset;

	return true;
}// getHeadPos //

//---------------------------------------------------
// updateHeadDirection :
// Update the head Direction.
//---------------------------------------------------
void CCharacterCL::updateHeadDirection(CEntityCL *target)
{
	// Does the entity got a target to track with the head ?
	// No head targeting if the target slot is the same as the entity slot
	if(_TargetSlot!=CLFECOMMON::INVALID_SLOT && _TargetSlot!=_Slot)
	{
		// Is the target allocated.
		if(target != 0)
		{
			// Do not orientate the head to the target if too far.
			CVectorD vectDist = target->pos() - pos();
			if((fabs(vectDist.x) + fabs(vectDist.y)) <= ClientCfg.MaxHeadTargetDist && vectDist != CVectorD::Null)
			{
				// Do not orientate the head to the target if behind.
				vectDist.normalize();
				if(fabs(angleBetween2Vect(dir(), vectDist)) < Pi/3.0)
				{
					CVector targetheadPos;
					if(target->getHeadPos(targetheadPos))
					{
						_TargetAnimCtrl.Mode = CTargetAnimCtrl::TargetMode;
						_TargetAnimCtrl.WorldTarget = targetheadPos;
						return;
					}
				}
			}
		}
	}

	_TargetAnimCtrl.Mode = CTargetAnimCtrl::DirectionMode;
	CMatrix frontMat;
	frontMat.setRot(CVector::I, front(), CVector::K, true);
	frontMat.normalize(CMatrix::YZX);
	_TargetAnimCtrl.CurrentWorldDirection = frontMat.getRot();
}// updateHeadDirection //


//---------------------------------------------------
// displayName :
// Display the entity name.
//---------------------------------------------------
void CCharacterCL::displayName()
{
	// There is no Context -> Cannot display a name.
	if(TextContext == 0)
		return;

	NLMISC::CVector namePos;
	// There is a skeleton.
	if(!_Skeleton.empty() && !ClientCfg.Light)
	{
		// Only if the skeleton is visible.
		if(!isVisible())
			return;
		// Do not display the name in LoD.
		if(_Skeleton.isDisplayedAsLodCharacter())
			return;
		// If the entity was not displayed last frame (clipped) -> do not display the name.
		if(!_Skeleton.getLastClippedState())
			return;

		// Is there a Bone for the Name ?
		if(_NameBoneId != -1)
			namePos = _Skeleton.getBone(_NameBoneId).getLastWorldMatrixComputed().getPos();
		// No Bone for the name -> Draw it at a default position.
		else
			namePos = pos() + CVector(0.f, 0.f, 2.0f);
	}
	// If there is no skeleton -> compute a position for the name.
	else
	{
		namePos = pos() + CVector(0.f, 0.f, 2.0f);
	}

	// Create the matrix and set the orientation according to the camera.
	CMatrix matrix;
	matrix.identity();
	matrix.setRot(MainCam.getRotQuat());
	matrix.setPos(namePos);

	CVector distPos = MainCam.getPos()-pos();
	float scale = distPos.norm();

	// don't display too far names
	if (ClientCfg.Light && scale > 20)
		return;

	if(scale <= 1.0f)
		scale = 1.0f;
	else if(scale > ClientCfg.ConstNameSizeDist)
		scale = ClientCfg.ConstNameSizeDist;
	// Too Far to display a name.
	else if(scale > ClientCfg.MaxNameDist)
		return;
	// Compute the final scale.
	matrix.scale(ClientCfg.NameScale*scale);

	// Draw the name.
	drawName(matrix);
}// displayName //

//---------------------------------------------------
// drawName :
// Draw the name.
//---------------------------------------------------
void CCharacterCL::drawName(const NLMISC::CMatrix &mat)	// virtual
{
	const ucstring &ucname = getEntityName();
	if(!getEntityName().empty())
	{
		// If there is no extended name, just display the name
		if(_NameEx.empty())
			TextContext->render3D(mat, ucname);
		// If there is an extended name, display the extended name at the name place and the name above.
		else
		{
			// Display the Extended Name at right place.
			TextContext->render3D(mat, _NameEx);
			// Compute the position for the Name.
			CMatrix mat2;
			mat2.identity();
			mat2.setRot(MainCam.getRotQuat());
			CVector v = mat.getPos()+mat.getK().normed()*ClientCfg.NamePos*mat.getScaleUniform();
			mat2.setPos(v);
			mat2.scale(mat.getScaleUniform());
			// Diaplay the name.
			TextContext->render3D(mat2, ucname);
		}
	}
	// Name from Sheet
	else
	{
		if(_Sheet != 0)
		{
			const ucstring name(STRING_MANAGER::CStringManagerClient::getCreatureLocalizedName(_Sheet->Id));
			if (name.find(ucstring("<NotExist:")) != 0)
				TextContext->render3D(mat, name);
		}
	}
}// drawName //


//---------------------------------------------------
// displayModifiers :
// Display the Hp Bar
//---------------------------------------------------
void CCharacterCL::displayModifiers()	// virtual
{
	// if none, no op
	if(	_HPDisplayed.empty())
		return;

	// **** get the name pos
	NLMISC::CVectorD namePos;
	if(!getNamePos(namePos))
		namePos = pos() + CVector(0.f, 0.f, 2.0f);
	// remove but keep the Z to the ground
	float	currentDeltaZ= float(namePos.z - pos().z);
	CVector	 groundPos= namePos;
	groundPos.z-= currentDeltaZ;


	// **** compute the scale
	float	dist = (MainCam.getPos()-pos()).norm();
	float	scale= 1.f;
	if(dist > ClientCfg.MaxNameDist)
		return;
	if ( dist < ClientCfg.ConstNameSizeDist )
		scale = 1.0f;
	else
		scale = ClientCfg.ConstNameSizeDist / dist;


	// **** Display HP modifiers.
	CInterfaceManager	*pIM= CInterfaceManager::getInstance();
	std::list<HPMD>::iterator itTmp;
	std::list<HPMD>::iterator it = _HPDisplayed.begin();
	while(it != _HPDisplayed.end())
	{
		HPMD &mod = *it;
		//
		const	float totalDuration= 3.f;
		const	float noFadeDuration= 1.f;
		const	float fadeDuration= totalDuration-noFadeDuration;
		if(TimeInSec > (mod.Time+totalDuration))
		{
			itTmp = it;
			++it;
			_HPDisplayed.erase(itTmp);
		}
		else if (TimeInSec >= mod.Time)
		{
			ucstring hpModifier;
			if (mod.Text.empty())
				hpModifier = ucstring(toString("%d", mod.Value));
			else
				hpModifier = mod.Text;
			double t = TimeInSec-mod.Time;
			// for character, keep the deltaZ the first time it is displayed, and apply the same each frame
			// (avoid Z movement of the flying text because of animation)
			if(mod.DeltaZ==-FLT_MAX)
				mod.DeltaZ= currentDeltaZ;
			// Compute the position for the Modifier.
			float	dynT= sqrtf((float)t/totalDuration);		// a sqrt just so it looks much more "jumpy"
			CVector		pos= groundPos + CVector(0.0f, 0.0f, mod.DeltaZ + dynT*1.f);
			// fade
			if(t<noFadeDuration)
				mod.Color.A= 255;
			else
				mod.Color.A= 255-(uint8)((t-noFadeDuration)*255.0/fadeDuration);

			// Display the hp modifier. display with a X offset according if user or not, for more readability
			sint	deltaX= -pIM->FlyingTextManager.getOffsetXForCharacter();
			if(UserEntity && UserEntity->slot()==slot())
				deltaX*= -1;
			pIM->FlyingTextManager.addFlyingText(&mod, hpModifier, pos, mod.Color, scale, deltaX);

			// Next
			++it;
		}
		else
		{
			// Next
			++it;
		}
	}
}// displayModifiers //


//---------------------------------------------------
// drawPath :
// Draw Pathes
//---------------------------------------------------
void CCharacterCL::drawPath()	// virtual
{
	// Pivot
	CLineColor line;
	CVector pl0 = pos();
	CVector pl1 = pos()+CVector(0.f, 0.f, 2.f);
	line = CLine(pl0, pl1);
	line.Color0 = CRGBA(150,0,255);
	line.Color1 = CRGBA(150,0,255);
	Driver->drawLine(line, GenericMat);

	line = CLine(_PositionLimiter, _PositionLimiter+CVector(0.f, 0.f, 2.f));
	line.Color0 = CRGBA(255,64,128);
	line.Color1 = CRGBA(255,64,128);
	Driver->drawLine(line, GenericMat);

	CVector p0 = pos();
	p0.z += 1.f;

	// Draw Front
	line = CLine(p0, p0+front());
	line.Color0 = CRGBA(0,255,0);
	line.Color1 = CRGBA(0,255,0);
	Driver->drawLine(line, GenericMat);

	// Draw Direction
	line = CLine(p0, p0+dir());
	line.Color0 = CRGBA(255,255,0);
	line.Color1 = CRGBA(255,255,0);
	Driver->drawLine(line, GenericMat);

	// Go to the First Stage.
	CStageSet::TStageSet::iterator it = _Stages._StageSet.begin();
	// Compute the distance over all Stages.
	while(it != _Stages._StageSet.end())
	{
		// Compute Distance.
		CVectorD stagePos;
		if((*it).second.getPos(stagePos))
		{
			CVector p1 = stagePos;
			CVector p2 = p0;
			p2.z = (float)stagePos.z;
			p2 = p2 + (stagePos-p2).normed();

			getCollisionEntity()->snapToGround(p1);
			p1.z += 0.05f;
			getCollisionEntity()->snapToGround(p2);
			p2.z += 0.03f;

			line = CLine(p0, p2);
			line.Color0 = CRGBA(0,0,255);
			line.Color1 = CRGBA(0,0,255);
			Driver->drawLine(line, GenericMat);

			p1.z += 0.03f;
			line = CLine(p0, p1);
			line.Color0 = CRGBA(255,0,0);
			line.Color1 = CRGBA(255,0,0);
			Driver->drawLine(line, GenericMat);

			p0 = p1;
		}

		// Next Stage.
		++it;
	}
}// drawPath //


//---------------------------------------------------
// drawBox :
// Draw the selection Box.
//---------------------------------------------------
void CCharacterCL::drawBox()	// virtual
{
	if(!ClientCfg.Light)
		::drawBox(_Aabbox.getMin(), _Aabbox.getMax(), CRGBA(0,250,0));

	// Draw the PACS box (adjust the color according to the PACS valid or not).
	NLMISC::CAABBox PACSBox = _Aabbox;
	CVector halfSize = PACSBox.getHalfSize();
	halfSize.x = 0; halfSize.y = 0;
	PACSBox.setCenter(_FinalPacsPos+halfSize);
	UGlobalPosition gPos;
	if(_Primitive)
		_Primitive->getGlobalPosition(gPos, dynamicWI);
	::drawBox(PACSBox.getMin(), PACSBox.getMax(), ((gPos.InstanceId == -1) && (T1%1000)>500)?CRGBA(255,0,0):CRGBA(0,250,250));

	if(!ClientCfg.Light)
	{
		::drawBox(selectBox().getMin(), selectBox().getMax(), CRGBA(250,250,0));
		// Draw the clip Sphere
		CVector clipPos = _Aabbox.getCenter();
		clipPos.z+= _ClipDeltaZ - _Aabbox.getHalfSize().z;	// _ClipDeltaZ is relative to pos on ground
		::drawSphere(clipPos, _ClipRadius, CRGBA(0,0,250));
	}
}// drawBox //

//---------------------------------------------------
// selectBox :
// Return the selection box.
//---------------------------------------------------
const NLMISC::CAABBox &CCharacterCL::selectBox()	// virtual
{
	// recompute the selection box?
	if(_LastSelectBoxComputeTime<T1)
	{
		_LastSelectBoxComputeTime=T1;
		bool	found= false;

		// if skeleton, compute aabox from precise skeleton method
		if(!_Skeleton.empty())
		{
			// Don't compute if in LOD form (else flick because sometimes valid because of shadow animation)
			if(!_Skeleton.isDisplayedAsLodCharacter() &&
				_Skeleton.computeRenderedBBoxWithBoneSphere(_SelectBox))
				found= true;
		}
		// else compute from static bot object
		else
		{
			UInstance	inst;
			// try with _Instances array first
			if(!_Instances.empty())
				inst= _Instances[0].Current;
			// Fallback to _Instance (??)
			if(inst.empty())
				inst= _Instance;

			// if static instance found
			if(!inst.empty())
			{
				CAABBox		bbox;
				inst.getShapeAABBox(bbox);
				// if supported (ie bbox not null)
				if(bbox.getHalfSize()!=CVector::Null)
				{
					// Transform bbox to world
					_SelectBox= CAABBox::transformAABBox(inst.getLastWorldMatrixComputed(), bbox);
					found= true;
				}
			}
		}

		// if not found, fallback to default bbox
		if(!found)
			_SelectBox = _Aabbox;
	}

	// Return the selection box.
	return _SelectBox;
}// selectBox //


//---------------------------------------------------
// updateAttachedFXListForSlotRemoved :
//---------------------------------------------------
void CCharacterCL::updateAttachedFXListForSlotRemoved(std::list<CAttachedFX::TSmartPtr> &fxList, const CLFECOMMON::TCLEntityId &slotRemoved)
{
	std::list<CAttachedFX::TSmartPtr>::iterator it = fxList.begin();
	while (it != fxList.end())
	{
		std::list<CAttachedFX::TSmartPtr>::iterator tmpIt = it;
		++ it;
		if ((*tmpIt)->StickMode &&
			((*tmpIt)->StickMode == CFXStickMode::OrientedTowardTargeter ||
			 (*tmpIt)->StickMode == CFXStickMode::UserBoneOrientedTowardTargeter ||
			 (*tmpIt)->StickMode == CFXStickMode::UserBoneRay
			)
		   )
		{
			if ((*tmpIt)->TargeterInfo.Slot == slotRemoved)
			{
				fxList.erase(tmpIt);
			}
		}
	}
}

//---------------------------------------------------
// slotRemoved :
// To Inform about an entity removed (to remove from selection for example).
// This will remove the entity from the target.
// \param slot : Slot of the entity that will be removed.
//---------------------------------------------------
void CCharacterCL::slotRemoved(const CLFECOMMON::TCLEntityId &slotRemoved)
{
	// If the target is the entity that will be removed -> no target
	if(_TargetSlot == slotRemoved)
		_TargetSlot = CLFECOMMON::INVALID_SLOT;
	// invalidate targeter slots in anim fxs
	updateAttachedFXListForSlotRemoved(_AttachedFXListForCurrentAnim, slotRemoved);
	updateAttachedFXListForSlotRemoved(_AttachedFXListToRemove, slotRemoved);
}// slotRemoved //

//---------------------------------------------------
// nbStage :
// Return number of stage remaining.
//---------------------------------------------------
uint CCharacterCL::nbStage()
{
	return (uint)_Stages._StageSet.size();
}// nbStage //


//---------------------------------------------------
// attackRadius :
// Method to return the attack radius of an entity (take the scale into account).
//---------------------------------------------------
double CCharacterCL::attackRadius() const
{
	return _Sheet->DistToFront * getScale();
}// attackRadius //

//---------------------------------------------------
// getAttackerPos :
// Return the position the attacker should have to combat according to the attack angle.
// \param ang : 0 = the front, >0 and <Pi = left side, <0 and >-Pi = right side.
// \todo : GUIGUI precalculate entity matrix
//---------------------------------------------------
CVectorD CCharacterCL::getAttackerPos(double ang, double dist) const
{
	// Compute the local angle
	ang = computeShortestAngle(atan2(front().y, front().x), ang);
	ang += Pi;
	if(ang > Pi)
		ang -= 2*Pi;

	// Compute the local position.
	CVectorD p;
	float distToSide, distToFront, distToBack;
	bool useComplexShape = false;
	if (useComplexShape) // Keep this code for when AIS become complex shape aware
	{
		distToSide = _Sheet->DistToSide;
		distToFront = _Sheet->DistToFront;
		distToBack = _Sheet->DistToBack;
	}
	else // use round shape here
	{
		distToSide = _Sheet->ColRadius;
		distToFront = _Sheet->ColRadius;
		distToBack = _Sheet->ColRadius;
	}
	p.x = getScale()*distToSide*sin(-ang) + dist*sin(-ang);	// or: pos.x = _Sheet->DistToSide*cos(ang) + dist*cos(ang); but 0 should be right side.
	p.y = dist*cos(ang);
	if(fabs(ang) <= Pi/2.0)
		p.y += getScale()*distToFront * cos(ang);
	else
		p.y += getScale()*distToBack  * cos(ang);
	p.z = 0.0;


	// Compute the world position.
	// Create the target matrix.
	CVector vj = front();
	vj.z = 0;
	CVector vk(0,0,1);
	CVector vi = vj^vk;
	CMatrix bodyBase;
	bodyBase.setRot(vi,vj,vk,true);
	bodyBase.setPos(pos());

	// Get the destination in the world.
	return bodyBase * p;
}// getAttackerPos //

//---------------------------------------------------
// isPlacedToFight :
// Return true if the opponent is well placed.
//---------------------------------------------------
bool CCharacterCL::isPlacedToFight(const NLMISC::CVectorD &posAtk, const NLMISC::CVector &dirAtk, double attackerRadius) const	// virtual
{
	NLMISC::CVectorD vDist = pos()-posAtk;
	if(vDist != NLMISC::CVectorD::Null)
	{
		// Attacker Distance
		const double distToAttacker = vDist.norm();
		// Get the Ideal Position
		vDist.normalize();
		CVectorD rightPos = getAttackerPos(atan2(vDist.y, vDist.x), attackerRadius);
		// Vector from the Ideal Position
		NLMISC::CVectorD vDist2 = pos()-rightPos;
		// Check the Distance.
		if(distToAttacker <= vDist2.norm()+ClientCfg.FightAreaSize)
		{
			// Check the orientation.
			NLMISC::CVector vAng = dirAtk;
			vAng.z = 0.0f;
			vDist.z = 0.0;
			return (fabs(angleBetween2Vect(vAng, vDist)) <=  NLMISC::Pi/3.0);
		}
	}
	// User is on the target, do not check dist or angle
	else
		return true;
	// Something wrong
	return false;
//	NLMISC::CVectorD vDist = pos()-posAtk;
//	const double dist = vDist.norm();
//	double radius;
//	// Get current entity radius
//	if(_Primitive)
//		radius = _Primitive->getRadius();
//	else
//		radius = 0.0;
//	// Attack is possible if not too close or too far.
//	if(dist>=radius && dist<=(radius+ClientCfg.FightAreaSize))
//	{
//		// Check Angle
//		NLMISC::CVector vAng = dirAtk;
//		vAng.z = 0.0f;
//		vDist.z = 0.0;
//		return (fabs(angleBetween2Vect(vAng, vDist)) <=  NLMISC::Pi/3.0);
//	}
//	return false;
}// isPlacedToFight //


//---------------------------------------------------
// \param pos : result given in this variable. Only valid if return 'true'.
// \return bool : 'true' if the 'pos' has been filled.
//---------------------------------------------------
bool CCharacterCL::getNamePos(CVectorD &pos) // virtual
{
	// If there is no skeleton -> cannot display the name.
	if(_Skeleton.empty())
		return false;

	// If the entity was not displayed last frame (clipped) -> do not display the name.
	if(!_Skeleton.getLastClippedState())
		return false;

	if(_NameBoneId == -1)
		return false;

	// Take x and y in pos() else we a have a frame late.
	pos.x = this->pos().x;
	pos.y = this->pos().y;

	float namePosZ;
	if (ClientCfg.StaticNameHeight)
		namePosZ = getNamePosZ();
	else
		namePosZ = 0.f;

	// use bone position if no name position is given
	if (namePosZ == 0.f)
	{
		// if displayed as lod, the NameId bone may not be computed
		float skeletonZ = _Skeleton.getLastWorldMatrixComputed().getPos().z;
		if(_Skeleton.isDisplayedAsLodCharacter())
		{
			// if never computed
			if(_NameCLodDeltaZ==NameCLodDeltaZNotComputed)
			{
				_Skeleton.forceComputeBone(_NameBoneId);
				float	boneZ= _Skeleton.getBone(_NameBoneId).getLastWorldMatrixComputed().getPos().z;
				_NameCLodDeltaZ= boneZ - skeletonZ;
			}
			pos.z= skeletonZ + _NameCLodDeltaZ;
		}
		else
		{
			float	boneZ= _Skeleton.getBone(_NameBoneId).getLastWorldMatrixComputed().getPos().z;
			pos.z = boneZ;
			// update delta Z, for when enter in CLod form
			_NameCLodDeltaZ= boneZ - skeletonZ;
		}

		// reset name pos history
		if (_NamePosHistory.isInitialized())
		{
			_NamePosHistory.LastNamePosZ = 0.f;
			_NamePosHistory.LastBonePosZ = 0.f;
		}

		return true;
	}

	const float baseZ = float( this->pos().z );

	// if displayed as lod, skip smooth transition stuff
	if (_Skeleton.isDisplayedAsLodCharacter())
	{
		pos.z = baseZ + namePosZ;

		// reset name pos history
		if (_NamePosHistory.isInitialized())
		{
			_NamePosHistory.LastNamePosZ = 0.f;
			_NamePosHistory.LastBonePosZ = 0.f;
		}

		return true;
	}

	const float boneZ = _Skeleton.getBone(_NameBoneId).getLastWorldMatrixComputed().getPos().z;

	float deltaNamePosZ;
	float deltaBonePosZ;
	if (_NamePosHistory.isInitialized())
	{
		deltaNamePosZ = namePosZ - _NamePosHistory.LastNamePosZ;
		deltaBonePosZ = (boneZ - baseZ) - _NamePosHistory.LastBonePosZ;
	}
	else
	{
		deltaNamePosZ = 0.f;
		deltaBonePosZ = 0.f;
	}

	if (deltaNamePosZ != 0.f)
	{
		// generate a smooth transition following the bone movement
		if (deltaBonePosZ != 0.f && (deltaBonePosZ > 0.f) == (deltaNamePosZ > 0.f))
		{
			namePosZ = _NamePosHistory.LastNamePosZ + deltaBonePosZ;
		}
		else
		{
			const float defaultSpeed = 1.f; // in meters per sec.
			float deltaZ = defaultSpeed * DT;
			if (deltaNamePosZ < 0.f)
				deltaZ = -deltaZ;

			if ( fabs(deltaZ) < fabs(deltaNamePosZ) )
				namePosZ = _NamePosHistory.LastNamePosZ + deltaZ;
		}
	}

	pos.z = baseZ + namePosZ;

	// update history
	_NamePosHistory.LastNamePosZ = namePosZ;
	_NamePosHistory.LastBonePosZ = boneZ - baseZ;

	return true;
}// getNamePos //

//---------------------------------------------------
// Return name position on Z axis defined in sheet
//---------------------------------------------------
float CCharacterCL::getNamePosZ() const
{
	if (!_Sheet)
		return 0.f;

	float namePosZ;
	switch (_ModeWanted)
	{
	case MBEHAV::DEATH:
	case MBEHAV::SIT:
	case MBEHAV::REST:
		namePosZ = _Sheet->NamePosZLow;
		break;

	case MBEHAV::MOUNT_NORMAL:
	case MBEHAV::MOUNT_SWIM:
		namePosZ = _Sheet->NamePosZHigh;
		break;

	default:
		namePosZ = _Sheet->NamePosZNormal;
		break;
	}

	if (namePosZ == 0.f)
		namePosZ = _Sheet->NamePosZNormal;

	return namePosZ * getScale();
}// getNamePosZ //

//---------------------------------------------------
// \param pos : result given in this variable. Only valid if return 'true'.
// \return bool : 'true' if the 'pos' has been filled.
//---------------------------------------------------
bool CCharacterCL::getChestPos(CVectorD &pos) const	// virtual
{
	// If there is no skeleton -> cannot display the Chest.
	if(_Skeleton.empty())
		return false;

	// If the entity was not displayed last frame (clipped) -> do not display the Chest.
	if(!_Skeleton.getLastClippedState())
		return false;

	if(_ChestBoneId == -1)
		return false;

	// Take x and y in pos() else we a have a frame late.
	pos.x = this->pos().x;
	pos.y = this->pos().y;
	pos.z = _Skeleton.getBone(_ChestBoneId).getLastWorldMatrixComputed().getPos().z;
	return true;
}// getChestPos //


//---------------------------------------------------
// getSheetScale :
// Return the entity sheet scale. (return 1.0 if there is any problem).
//---------------------------------------------------
float CCharacterCL::getSheetScale() const	// virtual
{
	if(!_Sheet)
		return 1.f;
	else
		return _Sheet->Scale;

} // getSheetScale //


//---------------------------------------------------
// getColRadius :
// Return the entity collision radius. (return 0.5 if there is any problem).
//---------------------------------------------------
float CCharacterCL::getSheetColRadius() const 
{
	if(!_Sheet) 
		return 0.5f;
	else
		return _Sheet->ColRadius;
}
	

//---------------------------------------------------
// getScale :
// Return the entity scale. (return 1.0 if there is any problem).
//---------------------------------------------------
float CCharacterCL::getScale() const	// virtual
{
	switch( _OwnerPeople )
	{
		case MOUNT_PEOPLE::Fyros : return getSheetScale() * ClientCfg.FyrosScale * _CustomScale;
		case MOUNT_PEOPLE::Matis : return getSheetScale() * ClientCfg.MatisScale * _CustomScale;
		case MOUNT_PEOPLE::Tryker : return getSheetScale() * ClientCfg.TrykerScale * _CustomScale;
		case MOUNT_PEOPLE::Zorai : return getSheetScale() * ClientCfg.ZoraiScale * _CustomScale;
		default:
			return getSheetScale() * _CustomScale;
	}
}// getScale //





///////////
// DEBUG //
///////////
//---------------------------------------------------
// currentAnimationName :
// Return the current animation name.
//---------------------------------------------------
const std::string &CCharacterCL::currentAnimationName() const
{
	if(_PlayList)
	{
		uint idCurrentAnimation = _PlayList->getAnimation(MOVE);
		if(idCurrentAnimation != UPlayList::empty)
			if(EAM && EAM->getAnimationSet())
				return EAM->getAnimationSet()->getAnimationName(idCurrentAnimation);
	}

	// No animation yet.
	return CCharacterCL::_EmptyString;
}// currentAnimationName //

//---------------------------------------------------
// currentAnimationSetName :
// Return the current animation set name.
//---------------------------------------------------
std::string CCharacterCL::currentAnimationSetName(TAnimationType animType) const
{
	if( animType < animTypeCount )
	{
		if( uint(animType) < _CurrentAnimSet.size() )
		{
			if( _CurrentAnimSet[animType] )
			{
				return _CurrentAnimSet[animType]->getSheetName();
			}
		}
	}
	return CCharacterCL::_EmptyString;
}// currentAnimationSetName //

/////////////
// PRIVATE //
//---------------------------------------------------
// shapeFromItem :
// Return the shape pointer from tha item and according to the character gender.
// \param itemSheet : reference on the item sheet.
// \return string & : reference on the shape name.
//---------------------------------------------------
std::string CCharacterCL::shapeFromItem(const CItemSheet &itemSheet) const
{
	if(_Gender == GSGENDER::female && !itemSheet.getShapeFemale().empty())
		return itemSheet.getShapeFemale();
	else
		return itemSheet.getShape();
}// shapeFromItem //


//---------------------------------------------------
// createItemInstance :
// Create the instance from an item
//---------------------------------------------------
uint32 CCharacterCL::createItemInstance(const CItemSheet &itemSheet, uint32 instIdx, SLOTTYPE::EVisualSlot visualSlot, const string &bindBone, sint8 texture, sint color)
{
	uint32 idx = CEntityCL::BadIndex;
	// Get the right shape according to the gender of the character.
	const string &shape = shapeFromItem(itemSheet);

	// Check the shape.
	if(!shape.empty())
	{
		// Check the item need a shape.
		if(shape != "none.shape")
		{
			UInstance	instance;
			// Get the instance
			idx = addColoredInstance(shape, bindBone, texture, instIdx, color);
			SInstanceCL *pInst = idx2Inst(idx);
			nlassert( (pInst == NULL) || (pInst != NULL && !pInst->Loading.empty()) );
			if (pInst != NULL)
				instance = pInst->Loading;
			// Check the shape creation has been is well done.
			if(!instance.empty())
			{
				// Create the FX associated to the item in a given visual slot.
				_Items[visualSlot].initFXs(visualSlot, instance);
			}
			else
				nlwarning("CH:createItemInstance: cannot create the instance for the shape '%s'.", shape.c_str());
		}
	}
	else
		nlwarning("CH:createItemInstance: the item has no shape.");

	return idx;
}// createItemInstance //


//-----------------------------------------------
// setAlive :
// Method to Flag the character as alive and do everything needed.
//-----------------------------------------------
void CCharacterCL::setAlive()	// virtual
{
}// setAlive //



//---------------------------------------------------
// displayDebug :
// Display Debug Information.
//---------------------------------------------------
ADD_METHOD(void CCharacterCL::displayDebug(float x, float &y, float lineStep))	// virtual
	CInterfaceManager *IM = CInterfaceManager::getInstance ();

	CEntityCL::displayDebug(x, y, lineStep);
	// Mode Wanted
	// Display the Target Mode.
	TextContext->printfAt(x, y, "Mode Wanted: %d(%s)", (sint)_ModeWanted, MBEHAV::modeToString(_ModeWanted).c_str());
	y += lineStep;
	// Stage Remaining
	TextContext->printfAt(x, y, "Stages remaining: %d", _Stages._StageSet.size());
	y += lineStep;
	// Current Automaton
	TextContext->printfAt(x, y, "Automaton: %s", _CurrentAutomaton.c_str());
	y += lineStep;
	// Current Speed
	TextContext->printfAt(x, y, "Speed: %f (_DestTime(%f) - _LastFrameTime(%f)) = %f", speed(), _DestTime, _LastFrameTime, _DestTime-_LastFrameTime);
	y += lineStep;
	// Display the Run Factor.
	TextContext->printfAt(x, y, "(Walk)Run Factor: %f", runFactor());
	y += lineStep;
	// Display the current animation name(id)(offset)(nbloop) for channel MOVE.
	TextContext->printfAt(x, y, "Current Animation: %s(%u)(%lf)(%u loops)", animId(MOVE)==std::numeric_limits<uint>::max()?"[NONE]":currentAnimationName().c_str(), animId(MOVE), animOffset(MOVE), _NbLoopAnim);
	y += lineStep;
	// First Pos
	if(_First_Pos)
		TextContext->printfAt(x, y, "No Position Received", _First_Pos);
	else
		TextContext->printfAt(x, y, "At least 1 Position Received", _First_Pos);
	y += lineStep;
	// Primitive Ptr
	TextContext->printfAt(x, y, "Prim Ptr: %p", _Primitive);
	y += lineStep;
	// Primitive Position
	if(_Primitive)
	{
		CVectorD primFinalPos = _Primitive->getFinalPosition(dynamicWI);
		TextContext->printfAt(x, y, "Prim Pos: %f %f %f", primFinalPos.x, primFinalPos.y, primFinalPos.z);
		y += lineStep;
	}
	// Skeleton Ptr, Animset Ptr and Current State Ptr
	TextContext->printfAt(x, y, "Skel Ptr: %p - AnimSet Ptr: %p - State Ptr: %p", &_Skeleton, _CurrentAnimSet[MOVE], _CurrentState);
	y += lineStep;
	// Display the target mount and rider.
	TextContext->printfAt(x, y, "Mount: %3u(Theoretical: %3u) Rider: %3u(Theoretical: %3u)", mount(), _TheoreticalMount, rider(), _TheoreticalRider);
	y += lineStep;
	// VPA
	sint64 prop = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:Entities:E"+toString("%d", _Slot)+":P"+toString("%d", CLFECOMMON::PROPERTY_VPA))->getValue64();
	if(isPlayer() || isUser())
	{
		SPropVisualA visualA = *(SPropVisualA *)(&prop);
		TextContext->printfAt(x, y, "VPA: %" NL_I64 "X : Chest(%d,%d) Legs(%d,%d) Arms(%d,%d) Hat(%d,%d) RH(%d) LH(%d)", prop,
			(uint)visualA.PropertySubData.JacketModel,	(uint)visualA.PropertySubData.JacketColor,
			(uint)visualA.PropertySubData.TrouserModel,	(uint)visualA.PropertySubData.TrouserColor,
			(uint)visualA.PropertySubData.ArmModel,		(uint)visualA.PropertySubData.ArmColor,
			(uint)visualA.PropertySubData.HatModel,		(uint)visualA.PropertySubData.HatColor,
			(uint)visualA.PropertySubData.WeaponRightHand,
			(uint)visualA.PropertySubData.WeaponLeftHand);
	}
	else
		TextContext->printfAt(x, y, "VPA: %" NL_I64 "X", prop);
	y += lineStep;
	// VPB
	prop = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:Entities:E"+toString("%d", _Slot)+":P"+toString("%d", CLFECOMMON::PROPERTY_VPB))->getValue64();
	if(isPlayer() || isUser())
	{
		SPropVisualB visualB = *(SPropVisualB *)(&prop);
		TextContext->printfAt(x, y, "VPB: %" NL_I64 "X : Hands(%d,%d) Feet(%d,%d).", prop,
			(uint)visualB.PropertySubData.HandsModel,	(uint)visualB.PropertySubData.HandsColor,
			(uint)visualB.PropertySubData.FeetModel,	(uint)visualB.PropertySubData.FeetColor);
	}
	else
		TextContext->printfAt(x, y, "VPB: %" NL_I64 "X", prop);
	y += lineStep;
	// VPC
	prop = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:Entities:E"+toString("%d", _Slot)+":P"+toString("%d", CLFECOMMON::PROPERTY_VPC))->getValue64();
	if(isPlayer() || isUser())
	{
		SPropVisualC visualC = *(SPropVisualC *)(&prop);
		TextContext->printfAt(x, y, "VPC: %" NL_I64 "X : EyesColor(%d) Tattoo(%d).", prop, visualC.PropertySubData.EyesColor, visualC.PropertySubData.Tattoo);
	}
	else
		TextContext->printfAt(x, y, "VPC: %" NL_I64 "X", prop);
	y += lineStep;
}// displayDebug //



//-----------------------------------------------
// displayDebugPropertyStages
//-----------------------------------------------
void CCharacterCL::displayDebugPropertyStages(float x, float &y, float lineStep)
{
	CStageSet::TStageSet::iterator	it= _Stages._StageSet.begin();
	for(;it!=_Stages._StageSet.end();it++)
	{
		CStage &stage= it->second;
		uint32	gc= it->first % 100;
		// build the string of props present in this stage
		string	strProps;
		for(uint i=0;i<CLFECOMMON::NB_VISUAL_PROPERTIES;i++)
		{
			if(i!=CLFECOMMON::PROPERTY_POSY && i!=CLFECOMMON::PROPERTY_POSZ && stage.isPresent(i))
				strProps+= string(CLFECOMMON::getPropShortText(i)) + " ";
		}
		TextContext->printfAt(x, y, "%02d %s", gc, strProps.c_str());
		y += lineStep;
	}
}


//---------------------------------------------------
// readWrite :
// Read/Write Variables from/to the stream.
//---------------------------------------------------
void CCharacterCL::readWrite(NLMISC::IStream &f)
{
	CEntityCL::readWrite(f);

	// PUBLIC

	// PROTECTED
	f.serial(_Stages);
//	std::vector<CAnimation::TAnimId>			_Animations;
//	std::vector<NLSOUND::TSoundAnimId>			_SoundId;
//	NLSOUND::CSoundContext						_SoundContext;
//	std::vector<double>							_AnimationsTimeOffset;
//	std::vector<CAnimationState::TAnimStateId>	_AnimationsStateKey;
//	const CAnimationSet							*_CurrentAnimSet;
	f.serial(_LastFrameTime);
	f.serial(_LodCharacterAnimEnabled);
	f.serial(_LodCharacterAnimTimeOffset);
//	uint										_LodCharacterMasterAnimSlot;
	f.serial(_CharacterScalePos);
	f.serial(_FirstPos);
	f.serial(_FirstTime);
	f.serial(_DistToFirst);
	f.serial(_DestPos);
	f.serial(_DestTime);
	f.serial(_DistToDest);
	f.serial(_OldPos);
	f.serial(_OldPosTime);
//	GSGENDER::EGender							_Gender;
//	sint										_NameBoneId;
//	NL3D::UTransform							_NameTransform;
//	std::vector<CItemSheet *>					_Items;
	f.serial(_HeadIdx);
	f.serial(_FaceIdx);
//	sint	_HeadBoneId;
	f.serial(_RotationFactor);
	f.serial(_DirEndAnim);
	f.serial(_RotAngle);
	f.serial(_CurrentAutomaton);
//	const CAutomatonStateSheet					*_CurrentState;
//	MBEHAV::EMode								_ModeWanted;
//	sint										_BlendRemaining;
	f.serial(_OldAutomaton);
	f.serial(_OldRotQuat);
	f.serial(_CustomScalePos);
//	TTime										_NextBlinkTime;
	f.serial(_NbLoopAnim);
//	std::vector<CFXStruct *>					_FXs;
//	std::list<UParticleSystemInstance>			_CurrentAnimFXList;
//	std::list<UParticleSystemInstance>			_RemoveAnimFXList;
//	NL3D::UParticleSystemInstance				_CurrentAnimFX;
	f.serial(_RightFXActivated);
	f.serial(_LeftFXActivated);
//	sint										_IndexRightFX;
//	sint										_IndexLeftFX;
	f.serial(_Mount);
	f.serial(_Rider);
	f.serial(_IsThereAMode);
	f.serial(_HairColor);
	f.serial(_EyesColor);
	f.serial(_HairIndex);
	f.serial(_LookRdy);
	f.serial(_Speed);
	f.serial(_RunFactor);

	// PRIVATE
//	uint32						_RHandInstIdx;
//	uint32						_LHandInstIdx;
}// readWrite //

//---------------------------------------------------
// load :
// To call after a read from a stream to re-initialize the entity.
//---------------------------------------------------
void CCharacterCL::load()	// virtual
{
	CInterfaceManager *IM = CInterfaceManager::getInstance ();

	// If the entity should be in the world already
	if(_First_Pos == false)
	{
		// Insert the primitive into the world.
		if(_Primitive)
			_Primitive->insertInWorldImage(dynamicWI);
		// Insert the entity into PACS
		pacsPos(pos());
	}

	if(_LookRdy)
	{
		_LookRdy = false;
		// Visual properties A
		_HeadIdx = CEntityCL::BadIndex;
		sint64 prop = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:Entities:E"+toString("%d", _Slot)+":P"+toString("%d", CLFECOMMON::PROPERTY_VPA))->getValue64();
		updateVisualPropertyVpa(0, prop);
	}
}// load //

//---------------------------------------------------
// buildPlaylist :
//---------------------------------------------------
void CCharacterCL::buildPlaylist()
{
	computeAnimSet();
	// Release the old animation playlist.
	if(_PlayList)
	{
		EAM->deletePlayList(_PlayList);
		_PlayList = 0;
	}
	// Create the new animation playlist.
	_PlayList = EAM->createPlayList();
	if(!_PlayList)
	{
		nlwarning("Cannot create a playlist for the entity.");
		return;
	}
	// Register the skeleton to the playlist.
	_PlayList->registerTransform(_Skeleton);
	// Animation should not move alone.
	uint posChannel = EAM->getAnimationSet()->getChannelIdByName("pos");
	if(posChannel != NL3D::UAnimationSet::NotFound)
		_PlayList->enableChannel(posChannel, false);
	else
		nlwarning("Channel 'pos' not found.");
	// Animation should not rotate alone.
	uint rotquatChannel = EAM->getAnimationSet()->getChannelIdByName("rotquat");
	if(rotquatChannel != NL3D::UAnimationSet::NotFound)
		_PlayList->enableChannel(rotquatChannel, false);
	else
		nlwarning("Channel 'rotquat' not found.");
	// Initialize the new playlist.
	// MOVE Channel
	_PlayList->setSpeedFactor	(MOVE, 1.f);
	_PlayList->setWrapMode		(MOVE, NL3D::UPlayList::Clamp);
	// ACTION Channel
	_PlayList->setAnimation     (ACTION, NL3D::UPlayList::empty);
	_PlayList->setSpeedFactor	(ACTION, 1.f);
	_PlayList->setWrapMode		(ACTION, NL3D::UPlayList::Clamp);
	// Compute the current animation state.
	_CurrentState = EAM->mState(_CurrentAutomaton, animState(MOVE));
	if(_CurrentState == 0)
	{
		_PlayList->setAnimation(MOVE, NL3D::UPlayList::empty);
		return;
	}
	// Get the right animation state and choose an animation.
	{
		// Get the animation state
		const CAnimationState *animationState = 0;
		if(animState(MOVE) == CAnimationStateSheet::Emote)
			animationState = _CurrentAnimSet[MOVE]->getAnimationState(_SubStateKey);
		else
			animationState = _CurrentAnimSet[MOVE]->getAnimationState(animState(MOVE));
		if(animationState)
		{
			// Choose the animation
			animIndex(MOVE, animationState->chooseAnim(_AnimJobSpecialisation, people(), getGender(), 0.0));
			// Should the objects in hands be displayed ?
			_ObjectsVisible = animationState->areObjectsVisible();
		}
	}
	// Set animation
	_PlayList->setAnimation(MOVE, animId(MOVE));
}// buildPlaylist //

//--------------//
// ENTITY INFOS //
//--------------//
//-----------------------------------------------
// getSpeed :
// Return the entity speed
//-----------------------------------------------
double CCharacterCL::getSpeed() const	// virtual
{
	return speed();
}// getSpeed //

//-----------------------------------------------
// dist2FirstPos :
// Set the Distance from the current entity position to the First Position.
//-----------------------------------------------
void CCharacterCL::dist2FirstPos(double d2FP)
{
	CHECK((d2FP == INVALID_DIST) || (d2FP == 0.0) || (d2FP >= ClientCfg.DestThreshold));
	_DistToFirst = d2FP;
}// dist2FirstPos //
//-----------------------------------------------
// dist2FirstPos :
// Return the Distance from the current entity position to the First Position.
//-----------------------------------------------
double CCharacterCL::dist2FirstPos() const
{
	CHECK((_DistToFirst == INVALID_DIST) || (_DistToFirst == 0.0) || (_DistToFirst >= ClientCfg.DestThreshold));
	return _DistToFirst;
}// dist2FirstPos //

//-----------------------------------------------
// dist2Dest :
// Set the Distance from the current entity position to the Destination.
//-----------------------------------------------
void CCharacterCL::dist2Dest(double d2D)
{
	CHECK((d2D == INVALID_DIST) || (d2D == 0.0) || (d2D >= ClientCfg.DestThreshold));
	_DistToDest = d2D;
}// dist2Dest //

//-----------------------------------------------
// dist2Dest :
// Return the Distance from the current entity position to the Destination.
//-----------------------------------------------
double CCharacterCL::dist2Dest() const
{
	CHECK((_DistToDest == INVALID_DIST) || (_DistToDest == 0.0) || (_DistToDest >= ClientCfg.DestThreshold));
	return _DistToDest;
}// dist2Dest //

//-----------------------------------------------
// speed :
// Set the Entity Current Speed.
//-----------------------------------------------
void CCharacterCL::speed(double s)
{
	CHECK((s == -1.0) || (s == 0.0) || ((s >= 0.001) && (s <= 1000.0)));
	_Speed = s;
}// speed //

//-----------------------------------------------
// speed :
// Return the Entity Current Speed.
//-----------------------------------------------
double CCharacterCL::speed() const	// virtual
{
	CHECK((_Speed == -1.0) || (_Speed == 0.0) || ((_Speed >= 0.001) && (_Speed <= 1000.0)));
	return _Speed;
}// getSpeed //

//-----------------------------------------------
// Build the in scene interface
//-----------------------------------------------
void CCharacterCL::buildInSceneInterface ()
{
	// Delete previous interface
	releaseInSceneInterfaces();

	_InSceneUserInterface = CGroupInSceneUserInfo::build (this);

	// parent
	CEntityCL::buildInSceneInterface();
}

//-----------------------------------------------

void CCharacterCL::setBubble (CGroupInSceneBubble *bubble)
{
	if (_CurrentBubble != NULL)
	{
		CGroupInSceneBubble	*old = _CurrentBubble;
		_CurrentBubble = NULL;
		old->unlink();
	}
	nlassert (_CurrentBubble == NULL);
	_CurrentBubble = bubble;
}

//-----------------------------------------------

//-----------------------------------------------
// runFactor :
// Set the Factor between Walk & Run
//-----------------------------------------------
void CCharacterCL::runFactor(double factor)
{
	CHECK((factor >= 0.0) && (factor <= 1.0));
	CHECK((factor == 0.0) || (animState(MOVE) == CAnimationStateSheet::Walk));
	_RunFactor = factor;
}// runFactor //

//-----------------------------------------------
// runFactor :
// Get the Factor between Walk & Run
//-----------------------------------------------
double CCharacterCL::runFactor() const
{
	CHECK((_RunFactor >= 0.0) && (_RunFactor <= 1.0));
	CHECK((_RunFactor == 0.0) || (animState(MOVE) == CAnimationStateSheet::Walk));
	return _RunFactor;
}// runFactor //

//-----------------------------------------------
// animOffset :
// Set the animation time offset for an animation channel.
//-----------------------------------------------
void CCharacterCL::animOffset(TAnimationType channel, double timeOffset)
{
	if(ClientCfg.Light)
		return;
	// Check the channel
	CHECK((uint)channel < _AnimOffset.size());
	// Check Animation Time Offset is greater or equal to 0.
	CHECK(timeOffset >= 0.0);
	// Check the animation time offset is not greater to the animation length.
	CHECK(timeOffset <= EAM->getAnimationLength(animId(channel)));
	// Set the Value
	_AnimOffset[channel] = timeOffset;
}// animOffset //

//-----------------------------------------------
// animOffset :
// Return the animation time offset for an animation channel.
//-----------------------------------------------
double CCharacterCL::animOffset(TAnimationType channel) const
{
	if(ClientCfg.Light)
		return 0.0;
	// Check the channel
	CHECK((uint)channel < _AnimOffset.size());
	// Check Animation Time Offset is greater or equal to 0.
	CHECK(_AnimOffset[channel] >= 0.0);
	// Check the animation time offset is not greater to the animation length.
	CHECK(_AnimOffset[channel] <= EAM->getAnimationLength(animId(channel)));
	// Return the Value
	return _AnimOffset[channel];
}// animOffset //

//---------------------------------------------------
// animationStateKey :
// Set the animation state key.
// \todo GUIGUI : a remplacer par animState directement.
//---------------------------------------------------
bool CCharacterCL::animationStateKey(TAnimationType channel, TAnimStateId value)
{
	// Is the new key valid ?
	if(value == CAnimationStateSheet::UnknownState)
	{
		nlwarning("CH::animationStateKey: Char '%d': new state key is Null.", _Slot);
		return false;
	}
	// Set the new key.
	animState(channel, value);
	// Debug Animation for the selection
	if(VerboseAnimSelection && _Slot == UserEntity->selection())
		nlinfo("CH:animationStateKey:%d: state '%s'.", _Slot, CAnimationState::getAnimationStateName(value).c_str());
	//
	return true;
}// animationStateKey //

//-----------------------------------------------
// animState :
// Set the Animation 'State' for an animation channel.
//-----------------------------------------------
void CCharacterCL::animState(TAnimationType channel, TAnimStateId state)
{
	// Check the channel
	CHECK((uint)channel < _AnimState.size());
	// Set the new State
	_AnimState[channel] = state;
	// Reset the Run Factor when the state change.
	runFactor(0.0);
}// animState //

//-----------------------------------------------
// animState :
// Get the Animation 'State' for an animation channel.
//-----------------------------------------------
TAnimStateId CCharacterCL::animState(TAnimationType channel) const
{
	// Check the channel
	CHECK((uint)channel < _AnimState.size());
	// Return the Animation State
	return _AnimState[channel];
}// animState //

//-----------------------------------------------
// animIndex :
// Set the Animation 'Index' in the 'State' for an animation channel.
//-----------------------------------------------
void CCharacterCL::animIndex(TAnimationType channel, CAnimation::TAnimId index)
{
	// Check the channel
	CHECK((uint)channel < _AnimState.size());
	// Set the animation index in the state
	_AnimIndex[channel] = index;
	// Set the animation Id
	// If the current animation Index is not a valid one, return empty
	if(_AnimIndex[channel] == CAnimation::UnknownAnim)
		animId(channel, NL3D::UPlayList::empty);
	else
	{
		// Check the AnimSet needed to get the animation Id.
		CHECK(_CurrentAnimSet[channel] != NULL);
		// Get the Pointer on the animation state, if Null, return empty
		const CAnimationState *animStatePtr = _CurrentAnimSet[channel]->getAnimationState( (animState(channel)==CAnimationStateSheet::Emote)?_SubStateKey:animState(channel));
		if(animStatePtr == 0)
			animId(channel, NL3D::UPlayList::empty);
		else
		{
			// Get the Animation Pointer, if Null, return Empty
			const CAnimation *anim = animStatePtr->getAnimation(animIndex(channel));
			if(anim == 0)
				animId(channel, NL3D::UPlayList::empty);
			// Return The Animation ID
			else
				animId(channel, anim->id());
		}
	}
}// animIndex //

//-----------------------------------------------
// animIndex :
// Get the Animation 'Index' in the 'State' for an animation channel.
//-----------------------------------------------
CAnimation::TAnimId CCharacterCL::animIndex(TAnimationType channel) const
{
	// Check the channel
	CHECK((uint)channel < _AnimState.size());
	// Return the Animation Index in the State
	return _AnimIndex[channel];
}//animIndex //

//-----------------------------------------------
// animId :
// Set the Animation 'Id' among all the animations for an animation channel.
//-----------------------------------------------
void CCharacterCL::animId(TAnimationType channel, uint id)
{
	// Check the channel
	CHECK((uint)channel < _AnimId.size());
	// Set the Id
	_AnimId[channel] = id;
}// animId //

//-----------------------------------------------
// animId :
// Get the Animation 'Id' among all the animations for an animation channel.
//-----------------------------------------------
uint CCharacterCL::animId(TAnimationType channel) const
{
	// Check the channel
	CHECK((uint)channel < _AnimId.size());
	// Get the Id
	return _AnimId[channel];
}// animId //



//-----------------------------------------------
// Align the given FX so that it is oriented like that entity
//-----------------------------------------------
void CCharacterCL::alignFX(UParticleSystemInstance instance, float scale /* = 1.f */, const NLMISC::CVector &localOffset /*= NLMISC::CVector::Null*/) const
{
	// copy matrix from parent
	CMatrix fxMatrix;
	fxMatrix.identity();
	buildAlignMatrix(fxMatrix);
	alignFX(instance, fxMatrix, scale, localOffset);
}


void CCharacterCL::alignFX(UParticleSystemInstance instance, const CMatrix &matrix, float scale /*=1.f*/, const NLMISC::CVector &localOffset /*=NLMISC::CVector::Null*/) const
{
	if(instance.empty())
		return;
	CMatrix fxMatrix = matrix;
	if (scale != 1.f) fxMatrix.scale(scale);
	fxMatrix.setPos(fxMatrix.getPos() + fxMatrix.mulVector(localOffset));
	instance.setTransformMode(NL3D::UTransform::DirectMatrix);
	instance.setMatrix(fxMatrix);
	if(!_Skeleton.empty())
	{
		instance.setClusterSystem(_Skeleton.getClusterSystem());
	}
}


//------------------------------------------------------------
// build a matrix aligned on that entity (includes dir & pos)
//------------------------------------------------------------
void CCharacterCL::buildAlignMatrix(NLMISC::CMatrix &dest) const
{
	// if not in clod, pelvis bone has been computed -> use it to get the current orientation
	// use the dir matrix otherwise
	/*CVector forward;
	if (pelvisBone() != -1 && _Skeleton)
	{
		if (_Skeleton.isBoneComputed(pelvisBone()))
		{
			// the direction is given by the y axis
			NL3D::UBone pelvisBone = _Skeleton.getBone(pelvisBone());
			forward = pelvisBone->getMatrix().getJ();
			forward.z = 0.f; // project onto XY plane
			forward.normalize();
		}
		else
		{
			// must be in clod -> use the direction
			forward = _Front;
		}
	}
	else
	{
		// bone not found, use the direction
		forward = _Front;
	}
	dest.setRot(- forward, forward ^ CVector::K, CVector::K);
	*/
	dest.setRot(CVector::K ^ _Front, - _Front, CVector::K);
	dest.setPos(pos());
}


//-----------------------------------------------
// attachFXInternal
//-----------------------------------------------
void	CCharacterCL::attachFXInternal(const CAttachedFX::TSmartPtr fx, TAttachedFXList targetList)
{
	if (!fx) return;
	switch(targetList)
	{
		case FXListToRemove:
			fx->TimeOutDate += TimeInSec; // in remove list timeout date is absolute
			_AttachedFXListToRemove.push_front(fx);
		break;
		case FXListCurrentAnim:
			_AttachedFXListForCurrentAnim.push_front(fx);
		break;
		case FXListAuto:
		{
			if (fx->AniFX->Sheet)
			{
				switch(fx->AniFX->Sheet->RepeatMode)
				{
					case CAnimationFXSheet::Respawn:
						fx->TimeOutDate += TimeInSec; // in remove list timeout date is absolute
						_AttachedFXListToRemove.push_front(fx);
					break;
					default:
						_AttachedFXListForCurrentAnim.push_front(fx);
					break;
				}
			}
			else
			{
				fx->TimeOutDate += TimeInSec; // in remove list timeout date is absolute
				_AttachedFXListToRemove.push_front(fx);
			}
		}
		break;
		default:
			nlassert(0);
		break;
	}
}

//-----------------------------------------------
// attachFX
//-----------------------------------------------
void	CCharacterCL::attachFX(const CAttachedFX::TSmartPtr fx)
{
	attachFXInternal(fx, FXListToRemove);
}





// ***********************************************************************************************************************
void CCharacterCL::setAuraFX(uint index, const CAnimationFX *sheet)
{
	nlassert(index < MaxNumAura);
	// no-op if same aura
	if (_AuraFX[index] && _AuraFX[index]->AniFX == sheet) return;

	if (sheet == NULL)
	{
		std::list<CAttachedFX::CBuildInfo>::iterator itAttachedFxToStart = _AttachedFXListToStart.begin();
		while(itAttachedFxToStart != _AttachedFXListToStart.end())
		{
			if ((*itAttachedFxToStart).MaxNumAnimCount == index)
				itAttachedFxToStart = _AttachedFXListToStart.erase(itAttachedFxToStart);
			else
				++itAttachedFxToStart;
		}
		// if there's already an aura attached, and if it is not already shutting down
		if (_AuraFX[index] && _AuraFX[index]->TimeOutDate == 0.f)
		{
			_AuraFX[index]->TimeOutDate = TimeInSec + AURA_SHUTDOWN_TIME;
		}
	}
	else
	{
		std::list<CAttachedFX::CBuildInfo>::iterator itAttachedFxToStart = _AttachedFXListToStart.begin();
		while(itAttachedFxToStart != _AttachedFXListToStart.end())
		{
			if ((*itAttachedFxToStart).MaxNumAnimCount == index)
				return;
		}
		// remove previous aura
		_AuraFX[index] = NULL;
		CAttachedFX::CBuildInfo bi;
		bi.Sheet = sheet;
		bi.TimeOut =  0.f;

		if (sheet->Sheet->PSName == "misc_caravan_teleportout.ps")
		{
			bi.MaxNumAnimCount = index;
			bi.StartTime = TimeInSec;
			bi.DelayBeforeStart = 12.5f;
			_AttachedFXListToStart.push_front(bi);
		}
		else if (sheet->Sheet->PSName == "misc_kami_teleportout.ps")
		{
			bi.MaxNumAnimCount = index;
			bi.StartTime = TimeInSec;
			bi.DelayBeforeStart = 11.5f;
			_AttachedFXListToStart.push_front(bi);
		}
		else 
		{
			CAttachedFX::TSmartPtr fx = new CAttachedFX;
			fx->create(*this, bi, CAttachedFX::CTargeterInfo());
			if (!fx->FX.empty())
			{
				_AuraFX[index] = fx;
			}
		}
	}
}

// ***********************************************************************************************************************
void CCharacterCL::setLinkFX(const CAnimationFX *fx, const CAnimationFX *dispell)
{
	// no-op if same link
	if (_LinkFX && _LinkFX->AniFX == fx) return;
	if (_LinkFX)
	{
		if (dispell)
		{
			CAttachedFX::TSmartPtr fx = new CAttachedFX;
			CAttachedFX::CBuildInfo bi;
			bi.Sheet = dispell;
			fx->create(*this, bi, CAttachedFX::CTargeterInfo());
			attachFX(fx);
		}
	}
	_LinkFX = NULL;
	if (!fx) return;
	CAttachedFX::TSmartPtr linkFX = new CAttachedFX;
	CAttachedFX::CBuildInfo bi;
	bi.Sheet = fx;
	linkFX->create(*this, bi, CAttachedFX::CTargeterInfo());
	if (!linkFX->FX.empty())
	{
		_LinkFX = linkFX;
	}
}



// ***********************************************************************************************************************
void CCharacterCL::startItemAttackFXs(bool activateTrails, uint intensity)
{
	uint numItems = (uint)_Items.size();
	forceEvalAnim(); // force to eval bones at least once when fx are created
	for(uint k = 0; k < numItems; ++k)
	{
		_Items[k].startAttackFX(_Skeleton, intensity, (SLOTTYPE::EVisualSlot) k, activateTrails);
	}
}

// ***********************************************************************************************************************
void CCharacterCL::stopItemAttackFXs()
{
	uint numItems = (uint)_Items.size();
	for(uint k = 0; k < numItems; ++k)
	{
		if (_Items[k].Sheet)
		{
			_Items[k].stopAttackFX();
		}
	}
}


//-----------------------------------------------
// isNeutral :
//-----------------------------------------------
bool CCharacterCL::isNeutral() const
{
	return !isEnemy();
}

//-----------------------------------------------
// isFriend :
//-----------------------------------------------
bool CCharacterCL::isFriend () const
{
	return !isEnemy();
}

//-----------------------------------------------
// isEnemy :
//-----------------------------------------------
bool CCharacterCL::isEnemy () const
{
	// Suppose enemy if attackable
	if( properties().attackable() )
	{
		return true;
	}

	return isAnOutpostEnemy();
}


//-----------------------------------------------
// isAlly :
//-----------------------------------------------
bool CCharacterCL::isAlly () const
{
	return this->isAnOutpostAlly();
}


//-----------------------------------------------
// applyVisualFX
//-----------------------------------------------
void CCharacterCL::applyVisualFX(sint64 prop)
{
	CVisualFX vfx;
	vfx.unpack(prop);
	const CAnimationFX *auraFX = NULL;
	if (vfx.Aura != 0)
	{
		auraFX = CAttackListManager::getInstance().getAuras().getFX(vfx.Aura);
	}
	setAuraFX(0, auraFX);
	const CAnimationFX *auraReceiptFX = NULL;
	if (vfx.AuraReceipt)
	{
		auraReceiptFX = CAttackListManager::getInstance().getAuras().getFX(0);
	}
	setAuraFX(1, auraReceiptFX);
	const CAnimationFX *linkFX = NULL;
	if (vfx.Link != 0)
	{
		linkFX = CAttackListManager::getInstance().getLinks().getFX(vfx.Link);
	}
	const CAnimationFX *dispellFX = NULL;
	dispellFX = CAttackListManager::getInstance().getLinks().getFX(0);
	setLinkFX(linkFX, dispellFX);
}

// *********************************************************************************************
const char *CCharacterCL::getBoneNameFromBodyPart(BODY::TBodyPart part, BODY::TSide side) const
{
	if (!_Sheet) return CEntityCL::getBoneNameFromBodyPart(part, side);
	return _Sheet->BodyToBone.getBoneName(part, side);
}


// *********************************************************************************************
const CItemSheet *CCharacterCL::getRightHandItemSheet() const
{
	if (_RHandInstIdx == CEntityCL::BadIndex) return NULL;
	return _Items[_RHandInstIdx].Sheet;
}

// *********************************************************************************************
const CItemSheet *CCharacterCL::getLeftHandItemSheet() const
{
	if (_LHandInstIdx == CEntityCL::BadIndex) return NULL;
	return _Items[_LHandInstIdx].Sheet;
}

// ***************************************************************************
void	CCharacterCL::resetAllSoundAnimId()
{
	for(uint i=0;i<_SoundId.size();i++)
	{
		_SoundId[i]= CSoundAnimationNoId;
	}
}


/////////////////////////////
// CCharacterCL::CWornItem //
/////////////////////////////


// ***********************************************************************************************************************
void CCharacterCL::CWornItem::startAttackFX(NL3D::USkeleton skeleton, uint intensity, SLOTTYPE::EVisualSlot visualSlot, bool activateTrail)
{
	if (intensity < 1 || intensity > 5) return;
	// activate trail
	if (activateTrail && !Trail.empty())
	{
		Trail.start();
	}
	// create the attack fx
	if (Sheet)
	{
		const CItemFXSheet &fxSheet = Sheet->FX;
		std::string shapeName = fxSheet.getAttackFX();
		if (!shapeName.empty())
		{
			const char *stickPoint = NULL;
			if(!skeleton.empty())
			{
				switch(visualSlot)
				{
					case SLOTTYPE::RIGHT_HAND_SLOT:
						if( Sheet->ItemType != ITEM_TYPE::MAGICIAN_STAFF )
							stickPoint = "box_arme";
					break;
					case SLOTTYPE::LEFT_HAND_SLOT:
						if(Sheet && Sheet->getAnimSet()=="s")
							stickPoint = "Box_bouclier";
						else
							stickPoint = "box_arme_gauche";
					break;
					default:
					break;
				}
			}
			if (stickPoint)
			{
				sint boneId = skeleton.getBoneIdByName(std::string(stickPoint));
				if (boneId != -1)
				{
					NL3D::UInstance instance = Scene->createInstance(shapeName);
					if (!instance.empty())
					{
						instance.show();
						if (skeleton.getVisibility() == UTransform::Hide)
						{
							// force to compute the bone at least once
							skeleton.forceComputeBone(boneId);
						}
						UParticleSystemInstance atk;
						atk.cast (instance);
						if (!atk.empty())
						{
							// set the user params
							static const float up[5][4] =
							{
								{ 0.f, 0.f, 0.f, 0.f},
								{ 1.f, 0.f, 0.f, 0.f},
								{ 1.f, 1.f, 0.f, 0.f},
								{ 1.f, 1.f, 1.f, 0.f},
								{ 1.f, 1.f, 1.f, 1.f}
							};
							for(uint k = 0; k < 4; ++k)
							{
								atk.setUserParam(k, up[intensity - 1][k]);
							}
							atk.setTransformMode(UTransform::RotEuler);
							atk.setPos(fxSheet.AttackFXOffset);
							const float degreeToRad = (float) Pi / 180.f;
							atk.setRotEuler(fxSheet.AttackFXRot.x * degreeToRad, fxSheet.AttackFXRot.y * degreeToRad, fxSheet.AttackFXRot.z * degreeToRad);
							skeleton.stickObject(atk, boneId);
							// delegate mng of this object lifetime to the fx manager
							FXMngr.fx2remove(atk);
						}
						else
						{
							Scene->deleteInstance(atk);
						}
					}
				}
			}
		}
	}
}

// ***********************************************************************************************************************
void CCharacterCL::CWornItem::stopAttackFX()
{
	if (!Trail.empty()) Trail.stop();
}

// ***********************************************************************************************************************
void CCharacterCL::CWornItem::initFXs(SLOTTYPE::EVisualSlot /* visualSlot */, NL3D::UInstance parent)
{
	releaseFXs();
	if (!Sheet) return;
	// create trail fx
	const CItemFXSheet &sheet = Sheet->FX;
	std::string shapeName = sheet.getTrail();
	if (!shapeName.empty())
	{
		Trail = Scene->createInstance(shapeName);
		if (Trail.empty())
		{
			nlwarning("Cannot create instance %s", shapeName.c_str());
			return;
		}
		// Initialize the remanence. Must substract the object matrix since parent(parent)
		CMatrix mat = parent.getMatrix();
		mat.invert();
		mat *= Trail.getMatrix();
		Trail.setTransformMode(UTransformable::DirectMatrix);
		Trail.setMatrix(mat);
		// Initialize instance.
		Trail.parent(parent);
	}
}

// ***********************************************************************************************************************
void CCharacterCL::CWornItem::enableAdvantageFX(NL3D::UInstance parent)
{
	if (!Sheet) return;

	bool enabled = Sheet->HasFx;

	if ((enabled && !AdvantageFX.empty()) || (!enabled && AdvantageFX.empty()))
		return; // state did not change
	if (!enabled)
	{
		// well, it is unlikely that player will loses its ability to master an item after he gained it, but manage the case anyway.
		if (!AdvantageFX.removeByID(NELID("STOP")) && !AdvantageFX.removeByID(NELID("main")))
		{
			AdvantageFX.activateEmitters(false);
		}
		FXMngr.fx2remove(AdvantageFX);
		AdvantageFX = NULL;
	}
	else
	{
		std::string shapeName = Sheet->FX.getAdvantageFX();
		if (!shapeName.empty())
		{
			NL3D::UInstance fx = Scene->createInstance(shapeName);
			if (fx.empty()) return;
			AdvantageFX.cast (fx);
			if (AdvantageFX.empty())
			{
				Scene->deleteInstance(fx);
				return;
			}
			CMatrix mat = parent.getMatrix();
			mat.invert();
			mat *= AdvantageFX.getMatrix();
			AdvantageFX.setTransformMode(UTransformable::DirectMatrix);
			AdvantageFX.setMatrix(mat);
			AdvantageFX.parent(parent);
		}
	}
}

// ***********************************************************************************************************************
void CCharacterCL::CWornItem::releaseFXs()
{
	if (Scene)
	{
		if (!Trail.empty())
			Scene->deleteInstance(Trail);
		if (!AdvantageFX.empty())
			Scene->deleteInstance(AdvantageFX);
	}
}

// ***********************************************************************************************************************
void CCharacterCL::CWornItem::setTrailSize(uint size)
{
	if (Trail.empty()) return;
	if (!Sheet) return;
	clamp(size, (uint) 0, (uint) 15);
	if (size == 0)
	{
		Trail.setSliceTime(0.f);
	}
	else
	{
		float ratio = (size - 1) / 15.f;
		Trail.setSliceTime(ratio * Sheet->FX.TrailMaxSliceTime + (1.f - ratio) *  Sheet->FX.TrailMinSliceTime);
	}
}


// ***********************************************************************************************************************
const CAttack *CCharacterCL::getAttack(const CAttackIDSheet &id) const
{
	if (!_Sheet) return NULL;
	return getAttack(id, _Sheet->AttackLists);
}

// ***********************************************************************************************************************
const CAttack *CCharacterCL::getAttack(const CAttackIDSheet &id, const std::vector<NLMISC::TSStringId> &attackList) const
{
	for(std::vector<NLMISC::TSStringId>::const_reverse_iterator it = attackList.rbegin(); it != attackList.rend(); ++it)
	{
		const CAttackList *al = CAttackListManager::getInstance().getAttackList(ClientSheetsStrings.get(*it));
		if (al)
		{
			const CAttack *attk = al->getAttackFromID(id);
			if (attk) return attk;
		}
	}
	return NULL;
}


// ***********************************************************************************************************************
void CCharacterCL::initStaticFX()
{
	_StaticFX = NULL;
	if (ClientCfg.Light) return;
	std::string staticFX = _Sheet->getStaticFX();
	if (!staticFX.empty())
	{
		CEntitySheet *sheet = SheetMngr.get(NLMISC::CSheetId(staticFX));
		if (sheet)
		{
			if (sheet->Type == CEntitySheet::ANIMATION_FX)
			{
				CAnimationFXSheet *afs = NLMISC::safe_cast<CAnimationFXSheet *>(sheet);
				_StaticFX = new CStaticFX;
				_StaticFX->AF.init(afs, EAM ? EAM->getAnimationSet() : NULL);
				_StaticFX->FX = new CAttachedFX;
				CAttachedFX::CBuildInfo bi;
				bi.Sheet = &_StaticFX->AF;
				_StaticFX->FX->create(*this, bi, CAttachedFX::CTargeterInfo());
				if (_StaticFX->FX->FX.empty())
				{
					_StaticFX = NULL;
					return;
				}

			}
		}
		else
		{
			nlwarning("Static fx %s not found", staticFX.c_str());
		}
	}
}

// ***************************************************************************
EGSPD::CPeople::TPeople CCharacterCL::people() const
{
	if(_Sheet)
		return _Sheet->Race;
	else
		return EGSPD::CPeople::Unknown;
}

// ***************************************************************************
void CCharacterCL::setPeople(EGSPD::CPeople::TPeople /* people */)
{
}

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

#if !FINAL_VERSION

// temp : begin cast of projectile (start begin anim and loop anim)
NLMISC_COMMAND(beginCast, "Start spell cast", "<spell_id> <strenght> [<mode> <caster slot> <behaviour>]")
{
	if (args.size() < 2) return false;
	if (args.size() > 5) return false;
	uint casterSlot = 0;
	if (args.size() >= 4)
	{
		fromString(args[3], casterSlot);
	}
	CCharacterCL *ch = dynamic_cast<CCharacterCL *>(EntitiesMngr.entity(casterSlot));
	if (!ch) return false;
	CBehaviourContext bc;
	// TODO : the type of missile is contained in the spell id
	if (args.size() >= 5)
	{
		sint missileType;
		fromString(args[4], missileType);
		bc.Behav.Behaviour = (MBEHAV::EBehaviour) (MBEHAV::CAST_OFF + missileType);
	}
	else
	{
		bc.Behav.Behaviour = MBEHAV::CAST_OFF;
	}
	//
	uint16 spellId;
	fromString(args[0], spellId);	// spell id is unused
	bc.Behav.Spell.SpellId = spellId;
	//bc.Behav.Spell.Resist = false;
	uint16 spellIntensity;
	fromString(args[1], spellIntensity);
	bc.Behav.Spell.SpellIntensity = spellIntensity;
	if (args.size() == 3)
	{
		uint16 spellMode;
		fromString(args[2], spellMode);
		bc.Behav.Spell.SpellMode = spellMode;
	}
	else
	{
		bc.Behav.Spell.SpellMode = MAGICFX::Bomb; // 'bomb' is the default
	}
	ch->applyBehaviour(bc);
	return true;
}

// temp : test fail of a cast
NLMISC_COMMAND(failCast, "Simulate failure of a spell cast", "<spell_id> <strenght> [<mode>]")
{
	if (args.size() < 2) return false;
	if (args.size() > 3) return false;
	CCharacterCL *ch = dynamic_cast<CCharacterCL *>(EntitiesMngr.entity(0));
	if (!ch) return false;
	CBehaviourContext bc;
	// TODO : the type of missile is contained in the spell id
	bc.Behav.Behaviour = MBEHAV::CAST_OFF_FAIL;
	//
	uint16 spellId;
	fromString(args[0], spellId);	// spell id is unused
	bc.Behav.Spell.SpellId = spellId;
	//bc.Behav.Spell.Resist = false;
	uint16 spellIntensity;
	fromString(args[1], spellIntensity);
	bc.Behav.Spell.SpellIntensity = spellIntensity;
	if (args.size() == 3)
	{
		uint16 spellMode;
		fromString(args[2], spellMode);
		bc.Behav.Spell.SpellMode = spellMode;
	}
	else
	{
		bc.Behav.Spell.SpellMode = MAGICFX::Bomb; // 'bomb' is the default
	}
	ch->applyBehaviour(bc);
	return true;
}

// temp to test cast of a projectile on another entity
NLMISC_COMMAND(projectile, "Cast a projectile on another entity", "<spellID> <strenght> [<mode> <target entity> <resist> <source entity>]" )
{
	if (args.size() < 2) return false;
	if (args.size() > 6) return false;
	uint8 casterSlot = 0;
	if (args.size() > 5)
	{
		fromString(args[5], casterSlot);
	}
	CCharacterCL *ch = dynamic_cast<CCharacterCL *>(EntitiesMngr.entity(casterSlot));
	if (!ch) return false;
	// create a new behaviour to apply to the user
	CBehaviourContext bc;
	uint16 spellId, spellIntensity;
	fromString(args[0], spellId);
	bc.Behav.Spell.SpellId = spellId;
	fromString(args[1], spellIntensity);
	bc.Behav.Spell.SpellIntensity = spellIntensity;
	// TODO : the type of missile is contained in the spell id
	bc.Behav.Behaviour = MBEHAV::CAST_OFF_SUCCESS;
	//
	if (args.size() > 2)
	{
		uint16 spellMode;
		fromString(args[2], spellMode);
		bc.Behav.Spell.SpellMode = spellMode;
	}
	else
	{
		bc.Behav.Spell.SpellMode = MAGICFX::Bomb; // 'bomb' is the default
	}
	if (args.size() > 3)
	{
		uint targetSlot;
		fromString(args[3], targetSlot);
		if (targetSlot >= CLFECOMMON::INVALID_SLOT) return false;
		CEntityCL *target = EntitiesMngr.entity(targetSlot);
		if (!target) return false;
		double dist = (target->pos() - ch->pos()).norm();
		bool resist = false;
		if (args.size() > 4) fromString(args[4], resist);
		bc.Targets.Targets.push_back(CMultiTarget::CTarget(targetSlot, resist, (uint8) ceilf((float) (dist /  MULTI_TARGET_DISTANCE_UNIT))));
	}
	bc.BehavTime = TimeInSec;
	ch->applyBehaviour(bc);
	return true;
}

NLMISC_COMMAND(mtProjectile, "Cast a projectile on one or several entities", "<caster> <spellID> <strenght> <mode> <target0> [<target n>]*" )
{
	if (args.size() < 5) return false;
	uint8 casterSlot;
	fromString(args[0], casterSlot);
	CCharacterCL *ch = dynamic_cast<CCharacterCL *>(EntitiesMngr.entity(casterSlot));
	if (!ch) return false;
	// create a new behaviour to apply to the user
	CBehaviourContext bc;
	uint16 spellId, spellIntensity, spellMode;

	fromString(args[1], spellId);
	bc.Behav.Spell.SpellId = spellId;

	fromString(args[2], spellIntensity);
	bc.Behav.Spell.SpellIntensity = spellIntensity;

	fromString(args[3], spellMode);
	bc.Behav.Spell.SpellMode = spellMode;
	// get targets and their dist depending on the mode
	switch(bc.Behav.Spell.SpellMode)
	{
		case MAGICFX::Bomb:
		{
			uint mainTargetSlot;
			fromString(args[4], mainTargetSlot);
			if (mainTargetSlot >= CLFECOMMON::INVALID_SLOT) return false;
			CEntityCL *mainTarget = EntitiesMngr.entity(mainTargetSlot);
			if (mainTarget)
			{
				double dist = (mainTarget->pos() - ch->pos()).norm();
				bc.Targets.Targets.push_back(CMultiTarget::CTarget(mainTargetSlot, false, (uint8) ceilf((float) (dist /  MULTI_TARGET_DISTANCE_UNIT))));
				for(sint k = 1; k < (sint) (args.size() - 4); ++k)
				{
					uint secondaryTargetSlot;
					fromString(args[4 + k], secondaryTargetSlot);
					if (secondaryTargetSlot >= CLFECOMMON::INVALID_SLOT) return false;
					CEntityCL *secondaryTarget = EntitiesMngr.entity(secondaryTargetSlot);
					if (secondaryTarget)
					{
						dist = (secondaryTarget->pos() - mainTarget->pos()).norm();
						bc.Targets.Targets.push_back(CMultiTarget::CTarget(secondaryTargetSlot, false, (uint8) ceilf((float) (dist /  MULTI_TARGET_DISTANCE_UNIT))));
					}
				}
			}
		}
		break;
		case MAGICFX::Spray:
		{
			for(sint k = 0; k < (sint) (args.size() - 4); ++k)
			{
				uint targetSlot;
				fromString(args[4 + k], targetSlot);
				if (targetSlot >= CLFECOMMON::INVALID_SLOT) return false;
				CEntityCL *target = EntitiesMngr.entity(targetSlot);
				if (target)
				{
					double dist = (target->pos() - ch->pos()).norm();
					bc.Targets.Targets.push_back(CMultiTarget::CTarget(targetSlot, false, (uint8) ceilf((float) (dist /  MULTI_TARGET_DISTANCE_UNIT))));
				}
			}
		}
		break;
		case MAGICFX::Chain:
		{
			CEntityCL *startSlot = ch;
			for(sint k = 0; k < (sint) (args.size() - 4); ++k)
			{
				uint targetSlot;
				fromString(args[4 + k], targetSlot);
				if (targetSlot >= CLFECOMMON::INVALID_SLOT) return false;
				CEntityCL *target = EntitiesMngr.entity(targetSlot);
				if (target)
				{
					double dist = (target->pos() - startSlot->pos()).norm();
					bc.Targets.Targets.push_back(CMultiTarget::CTarget(targetSlot, false, (uint8) ceilf((float) (dist /  MULTI_TARGET_DISTANCE_UNIT))));
					startSlot = target;
				}
			}
		}
		break;
	}
	bc.BehavTime = TimeInSec;
	// TODO : the type of missile is contained in the spell id
	bc.Behav.Behaviour = MBEHAV::CAST_OFF_SUCCESS;
	//
	ch->applyBehaviour(bc);
	return true;
}

// temp to test cast of multitarget projectile on another entity
NLMISC_COMMAND(aura, "enable / disable aura on an entity", "<slot> <aura>")
{
	if (args.size() != 2) return false;
	uint slot;
	fromString(args[0], slot);
	CCharacterCL *ch = dynamic_cast<CCharacterCL *>(EntitiesMngr.entity(slot));
	if (!ch) return false;
	const CAnimationFX *fx = NULL;
	sint auraIndex;
	fromString(args[1], auraIndex);
	if (auraIndex != -1)
	{
		fx = CAttackListManager::getInstance().getAuras().getFX(auraIndex);
		if (!fx) return false;
	}
	ch->setAuraFX(0, fx);
	return true;
}

NLMISC_COMMAND(link, "enable / disable link on an entity", "<slot> <link>")
{
	if (args.size() != 2) return false;
	uint slot;
	fromString(args[0], slot);
	CCharacterCL *ch = dynamic_cast<CCharacterCL *>(EntitiesMngr.entity(slot));
	if (!ch) return false;
	const CAnimationFX *link = NULL;
	sint linkIndex;
	fromString(args[1], linkIndex);
	if (linkIndex != -1)
	{
		link = CAttackListManager::getInstance().getLinks().getFX(linkIndex + 1);
		if (!link) return false;
	}
	const CAnimationFX *linkBreak = CAttackListManager::getInstance().getLinks().getFX(0);
	if (!linkBreak) return false;
	ch->setLinkFX(link, linkBreak);
	return true;
}

NLMISC_COMMAND(auraReceipt, "enable / disable aura receipt on an entity", "<slot> <aura> <0=on/1=off>")
{
	if (args.size() != 2) return false;
	uint slot;
	fromString(args[0], slot);
	CCharacterCL *ch = dynamic_cast<CCharacterCL *>(EntitiesMngr.entity(slot));
	if (!ch) return false;
	const CAnimationFX *fx = NULL;
	bool enableAura;
	fromString(args[1], enableAura);
	if (enableAura)
	{
		fx = CAttackListManager::getInstance().getAuras().getFX(0); // 0 is special for aura receipt
		if (!fx) return false;
	}
	ch->setAuraFX(1, fx);
	return true;
}

////////////////////////////
// test for melee weapons //
////////////////////////////

// these are helpers (the same can be done with /vp, or altLook)
NLMISC_COMMAND(weapon, "change the weapon in hand", "<slot> <hand> <weapon>")
{
	if (args.size() != 3) return false;
	CInterfaceManager *im = CInterfaceManager::getInstance();
	uint slot;
	fromString(args[0], slot);
	CCDBNodeLeaf *propA = NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:Entities:E%d:P%d", (int) slot, (int) PROPERTY_VPA), false);
	if (!propA) return false;
	sint64 valueA = propA->getValue64();

	CCDBNodeLeaf *propB = NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:Entities:E%d:P%d", (int) slot, (int) PROPERTY_VPB), false);
	if (!propB) return false;
	sint64 valueB = propB->getValue64();

	uint hand;
	fromString(args[1], hand);

	// the VP is dependent of Entity actual type
	if(dynamic_cast<CPlayerCL*>(EntitiesMngr.entity(slot)))
	{
		SPropVisualA vpa = (SPropVisualA &) valueA;
		SPropVisualB vpb = (SPropVisualB &) valueB;
		if (hand == 0)
		{
			uint16 weaponRightHand;
			fromString(args[2], weaponRightHand);
			vpa.PropertySubData.WeaponRightHand = weaponRightHand;
			vpb.PropertySubData.RTrail = 1;
		}
		else
		{
			uint16 weaponLeftHand;
			fromString(args[2], weaponLeftHand);
			vpa.PropertySubData.WeaponLeftHand = weaponLeftHand;
			vpb.PropertySubData.LTrail = 1;
		}
		propA->setValue64((sint64) vpa.PropertyA);
		propB->setValue64((sint64) vpb.PropertyB);
	}
	// CharacterCL: use a SAltLook
	else
	{
		SAltLookProp vpalt = (SAltLookProp&) valueA;
		if (hand == 0)
		{
			uint16 weaponRightHand;
			fromString(args[2], weaponRightHand);
			vpalt.Element.WeaponRightHand = weaponRightHand;
			vpalt.Element.RTrail = 1;
		}
		else
		{
			uint16 weaponLeftHand;
			fromString(args[2], weaponLeftHand);
			vpalt.Element.WeaponLeftHand = weaponLeftHand;
			vpalt.Element.LTrail = 1;
		}
		propA->setValue64((sint64) vpalt.Summary);
	}

	// Force to update property
	EntitiesMngr.updateVisualProperty(0, slot, CLFECOMMON::PROPERTY_VPA);
	EntitiesMngr.updateVisualProperty(0, slot, CLFECOMMON::PROPERTY_VPB);

	// display name of weapon sheet

	return true;
}

NLMISC_COMMAND(advantageFX, "turn on / off the advantage fx for an item in hand", "<slot> <hand> <on = 1/ off = 0>")
{
	if (args.size() != 3) return false;
	CInterfaceManager *im = CInterfaceManager::getInstance();
	uint slot;
	fromString(args[0], slot);

	/*
	CCDBNodeLeaf *prop = NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:Entities:E%d:P%d", (int) slot, (int) PROPERTY_VPA), false);
	if (!prop) return false;
	sint64 value = prop->getValue64();
	uint hand;
	fromString(args[1], hand);
	// the VP is dependent of Entity actual type
	if(dynamic_cast<CPlayerCL*>(EntitiesMngr.entity(slot)))
	{
		SPropVisualA vpa = (SPropVisualA &) value;
		if (hand == 0)
		{
			fromString(args[2], vpa.PropertySubData.RWeaponFX);
		}
		else
		{
			fromString(args[2], vpa.PropertySubData.LWeaponFX);
		}
		prop->setValue64((sint64) vpa.PropertyA);
	}
	// CharacterCL: use a SAltLook
	else
	{
		SAltLookProp vpa = (SAltLookProp&) value;
		if (hand == 0)
		{
			fromString(args[2], vpa.Element.RWeaponFX);
		}
		else
		{
			fromString(args[2], vpa.Element.LWeaponFX);
		}
		prop->setValue64((sint64) vpa.Summary);
	}
	*/

	// Force to update property
	EntitiesMngr.updateVisualProperty(0, slot, CLFECOMMON::PROPERTY_VPA);

	return true;
}

NLMISC_COMMAND(trailLength, "set length of trail for one weapon in hand", "<slot> <hand> <power = 0..15>")
{
	if (args.size() != 3) return false;
	CInterfaceManager *im = CInterfaceManager::getInstance();
	uint slot;
	fromString(args[0], slot);

	CCDBNodeLeaf *propA = NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:Entities:E%d:P%d", (int) slot, (int) PROPERTY_VPA), false);
	if (!propA) return false;
	sint64 valueA = propA->getValue64();

	CCDBNodeLeaf *propB = NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:Entities:E%d:P%d", (int) slot, (int) PROPERTY_VPB), false);
	if (!propB) return false;
	sint64 valueB = propB->getValue64();

	uint hand;
	fromString(args[1], hand);

	// the VP is dependent of Entity actual type
	if(dynamic_cast<CPlayerCL*>(EntitiesMngr.entity(slot)))
	{
		SPropVisualA vpa = (SPropVisualA &) valueA;
		SPropVisualB vpb = (SPropVisualB &) valueB;
		if (hand == 0)
		{
			uint16 rTrail;
			fromString(args[2], rTrail);
			vpb.PropertySubData.RTrail = rTrail;
			propB->setValue64((sint64) vpb.PropertyB);
		}
		else
		{
			uint16 lTrail;
			fromString(args[2], lTrail);
			vpb.PropertySubData.LTrail = lTrail / 2;
			propB->setValue64((sint64) vpb.PropertyB);
		}
	}
	else
	{
		SAltLookProp vpalt = (SAltLookProp &) valueA;
		if (hand == 0)
		{
			uint16 rTrail;
			fromString(args[2], rTrail);
			vpalt.Element.RTrail = rTrail;
		}
		else
		{
			uint16 lTrail;
			fromString(args[2], lTrail);
			vpalt.Element.LTrail = lTrail / 2;
		}
		propA->setValue64((sint64) vpalt.Summary);
	}

	// Force to update property
	EntitiesMngr.updateVisualProperty(0, slot, CLFECOMMON::PROPERTY_VPA);
	EntitiesMngr.updateVisualProperty(0, slot, CLFECOMMON::PROPERTY_VPB);

	return true;
}


// simulate an attack behaviour for the given slot
NLMISC_COMMAND(attack, "simulate an attack", "<slot> <intensity> <hit_type> <localisation> <dmg_type> <damage_shield_power> <damage_shield_id>")
{
	if (args.size() < 2) return false;
	if (args.size() > 7) return false;
	CBehaviourContext bc;
	bc.Behav.Behaviour = MBEHAV::DEFAULT_ATTACK;
	bc.Behav.Combat.ActionDuration = 0;
	uint16 impactIntensity;
	fromString(args[1], impactIntensity);
	bc.Behav.Combat.ImpactIntensity = impactIntensity;
	bc.Behav.Combat.HitType = HITTYPE::Hit;
	bc.Behav.Combat.Localisation = BODY::HHead;
	bc.Behav.Combat2.DamageType = 0;
	if (args.size() > 2)
	{
		uint16 hitType;
		fromString(args[2], hitType);
		bc.Behav.Combat.HitType = hitType + 1;
	}
	if (args.size() > 3)
	{
		uint16 localisation;
		fromString(args[3], localisation);
		bc.Behav.Combat.Localisation = localisation;
	}
	if (args.size() > 4)
	{
		uint16 damageType;
		fromString(args[4], damageType);
		bc.Behav.Combat2.DamageType = damageType;
	}
	uint dsPower = 0;
	uint dsType = 0;
	if (args.size() > 5)
	{
		fromString(args[5], dsPower);
	}
	if (args.size() > 6)
	{
		fromString(args[6], dsType);
	}

	uint slot;
	fromString(args[0], slot);
	CCharacterCL *entity = dynamic_cast<CCharacterCL *>(EntitiesMngr.entity(slot));
	if (!entity) return false;
	// push current slection as main target
	CMultiTarget::CTarget target;
	target.TargetSlot = UserEntity->selection();
	target.Info = dsPower | (dsType << 3);
	bc.Targets.Targets.push_back(target);
	bc.BehavTime = TimeInSec;
	bc.Behav.DeltaHP = -20;
	entity->applyBehaviour(bc);
	return true;
}

// simulate a range attack from the current slor to the current selection
NLMISC_COMMAND(rangeAttack, "simulate a range attack", "<slot> [intensity] [localisation] [range_weapon_type_if_unequipped]")
{
	if (args.size() < 1) return false;
	if (args.size() > 4) return false;
	uint slot;
	fromString(args[0], slot);
	CCharacterCL *entity = dynamic_cast<CCharacterCL *>(EntitiesMngr.entity(slot));
	if (!entity) return false;
	const CItemSheet *weaponSheet = entity->getRightHandItemSheet();
	CBehaviourContext bc;
	if (!weaponSheet || weaponSheet->Family != ITEMFAMILY::RANGE_WEAPON)
	{
		//
		uint16 weaponType = 0;
		if (args.size() > 3)
		{
			fromString(args[3], weaponType);
		}
		bc.Behav.Range.WeaponType = weaponType;
	}
	else
	{
		bc.Behav.Range.WeaponType = weaponSheet->RangeWeapon.RangeWeaponType;
	}
	bc.Behav.Behaviour = MBEHAV::RANGE_ATTACK;
	bc.Behav.Range.ImpactIntensity = 1;
	bc.Behav.Range.Localisation = BODY::HHead;
	bc.BehavTime = TimeInSec;
	if (args.size() > 1)
	{
		uint16 impactIntensity;
		fromString(args[1], impactIntensity);
		bc.Behav.Range.ImpactIntensity = impactIntensity;
	}
	if (args.size() > 2)
	{
		uint16 localisation;
		fromString(args[2], localisation);
		bc.Behav.Range.Localisation = localisation;
	}
	// if not a generic range weapon, add a single target (this is the current selection)
	uint8 targetSlot = UserEntity->targetSlot();
	if (targetSlot >= CLFECOMMON::INVALID_SLOT) return false;
	CEntityCL *target = EntitiesMngr.entity(targetSlot);
	if (!target) return false;
	double dist = (target->pos() - entity->pos()).norm();
	bc.Targets.Targets.push_back(CMultiTarget::CTarget(targetSlot, false, (uint8) ceilf((float) (dist /  MULTI_TARGET_DISTANCE_UNIT))));
	bc.Behav.DeltaHP = -10;
	entity->applyBehaviour(bc);
	return true;
}


// simulate a creature attack
NLMISC_COMMAND(creatureAttack, "simulate a creature attack (2 attaques per creature)", "<casterSlot> <targetSlot> [attk=0/1] [magicIntensity] [physicalIntensity] [localisation] [damageType] [hitType] [resist=1/0]")
{
	if (args.size() < 2) return false;
	if (args.size() > 9) return false;
	CBehaviourContext bc;
	bc.Behav.Behaviour = MBEHAV::CREATURE_ATTACK_0;
	if (args.size() > 2)
	{
		uint attk;
		fromString(args[2], attk);
		bc.Behav.Behaviour = attk == 0 ? MBEHAV::CREATURE_ATTACK_0 : MBEHAV::CREATURE_ATTACK_1;
	}
	uint8 casterSlot;
	fromString(args[0], casterSlot);
	CCharacterCL *caster = dynamic_cast<CCharacterCL *>(EntitiesMngr.entity(casterSlot));
	if (!caster) return false;
	uint8 targetSlot;
	fromString(args[1], targetSlot);
	CCharacterCL *target = dynamic_cast<CCharacterCL *>(EntitiesMngr.entity(targetSlot));
	if (!target) return false;
	double dist = (target->pos() - caster->pos()).norm();
	bool resist = false;
	if (args.size() > 8)
	{
		fromString(args[8], resist);
	}
	bc.Targets.Targets.push_back(CMultiTarget::CTarget(targetSlot, false, (uint8) ceilf((float) (dist /  MULTI_TARGET_DISTANCE_UNIT))));
	bc.Behav.CreatureAttack.ActionDuration = 0;
	uint magicImpactIntensity = 1;
	if (args.size() > 3)
	{
		fromString(args[3], magicImpactIntensity);
	}
	bc.Behav.CreatureAttack.MagicImpactIntensity = magicImpactIntensity;
	uint physicalImpactIntensity = 0;
	if (args.size() > 4)
	{
		fromString(args[4], physicalImpactIntensity);
	}
	bc.Behav.CreatureAttack.ImpactIntensity = physicalImpactIntensity;
	BODY::TBodyPart localisation = BODY::HHead;
	if (args.size() > 5)
	{
		sint tmp;
		fromString(args[5], tmp);
		localisation = (BODY::TBodyPart) tmp;
	}
	bc.Behav.CreatureAttack.Localisation = localisation;
	DMGTYPE::EDamageType dmgType = DMGTYPE::BLUNT;
	if (args.size() > 6)
	{
		sint tmp;
		fromString(args[6], tmp);
		dmgType = (DMGTYPE::EDamageType) tmp;
	}
	bc.Behav.CreatureAttack2.DamageType = dmgType;
	HITTYPE::THitType hitType = HITTYPE::Hit;
	if (args.size() > 7)
	{
		sint tmp;
		fromString(args[7], tmp);
		hitType = (HITTYPE::THitType) tmp;
	}
	bc.Behav.CreatureAttack2.HitType = hitType;
	bc.BehavTime = TimeInSec;
	bc.Behav.DeltaHP = -15;
	caster->applyBehaviour(bc);
	return true;
}

NLMISC_COMMAND(setNamePosZ, "", "<low/high/normal> <value>")
{
	if (args.size() != 2) return false;

	CEntityCL *target = EntitiesMngr.entity(UserEntity->targetSlot());
	if (!target)
		return true;

	float *namePosZ = NULL;
	string sheetName, skelName;
	if (target->Type == CEntityCL::Player)
	{
		CPlayerCL *playerTarget = dynamic_cast<CPlayerCL*>(target);
		if (playerTarget)
		{
			CRaceStatsSheet *sheet = const_cast<CRaceStatsSheet*>(playerTarget->playerSheet());
			if (sheet)
			{
				if (toLower(args[0]) == "low")
					namePosZ = &sheet->GenderInfos[playerTarget->getGender()].NamePosZLow;
				else if (toLower(args[0]) == "normal")
					namePosZ = &sheet->GenderInfos[playerTarget->getGender()].NamePosZNormal;
				else if (toLower(args[0]) == "high")
					namePosZ = &sheet->GenderInfos[playerTarget->getGender()].NamePosZHigh;

				sheetName = sheet->Id.toString();
				skelName = sheet->GenderInfos[playerTarget->getGender()].Skelfilename;
			}
		}
	}
	else
	{
		CCharacterCL *creatureTarget = dynamic_cast<CCharacterCL*>(target);
		if (creatureTarget)
		{
			CCharacterSheet *sheet = const_cast<CCharacterSheet*>(creatureTarget->getSheet());
			if (sheet)
			{
				if (toLower(args[0]) == "low")
					namePosZ = &sheet->NamePosZLow;
				else if (toLower(args[0]) == "normal")
					namePosZ = &sheet->NamePosZNormal;
				else if (toLower(args[0]) == "high")
					namePosZ = &sheet->NamePosZHigh;

				sheetName = sheet->Id.toString();
				skelName = sheet->getSkelFilename();
			}
		}
	}

	if (namePosZ)
	{
		fromString(args[1], *namePosZ);
		nlinfo("NAMEPOSZ: sheet: %s, skel: %s, NamePosZ%s = %g", sheetName.c_str(), skelName.c_str(), args[0].c_str(), *namePosZ);
	}

	return true;
}

NLMISC_COMMAND(setMyNamePosZ, "", "<low/high/normal> <value>")
{
	if (args.size() != 2) return false;

	float *namePosZ = NULL;
	string sheetName, skelName;
	CRaceStatsSheet *sheet = const_cast<CRaceStatsSheet*>(UserEntity->playerSheet());
	if (sheet)
	{
		if (toLower(args[0]) == "low")
			namePosZ = &sheet->GenderInfos[UserEntity->getGender()].NamePosZLow;
		else if (toLower(args[0]) == "normal")
			namePosZ = &sheet->GenderInfos[UserEntity->getGender()].NamePosZNormal;
		else if (toLower(args[0]) == "high")
			namePosZ = &sheet->GenderInfos[UserEntity->getGender()].NamePosZHigh;

		sheetName = sheet->Id.toString();
		skelName = sheet->GenderInfos[UserEntity->getGender()].Skelfilename;
	}

	if (namePosZ)
	{
		fromString(args[1], *namePosZ);
		nlinfo("NAMEPOSZ: sheet: %s, skel: %s, NamePosZ%s = %g", sheetName.c_str(), skelName.c_str(), args[0].c_str(), *namePosZ);
	}

	return true;
}


NLMISC_COMMAND(pvpMode, "modify pvp mode", "[<pvp mode> <state>]")
{
	if (args.size() != 0 && args.size() != 2) return false;

	CInterfaceManager *IM = CInterfaceManager::getInstance();

	CEntityCL *target = EntitiesMngr.entity(UserEntity->targetSlot());
	if (!target)
	{
		IM->displaySystemInfo(toString("<pvpMode> no target"));
		return false;
	}
	if (target->Type != CEntityCL::Player && target->Type != CEntityCL::User)
	{
		IM->displaySystemInfo(toString("<pvpMode> target is not a player"));
		return false;
	}
	CPlayerCL *playerTarget = dynamic_cast<CPlayerCL*>(target);
	if (!playerTarget)
		return false;

	if (args.empty())
	{
		uint16 pvpMode = playerTarget->getPvpMode();
		string str;
		if( pvpMode&PVP_MODE::PvpDuel )
			str+="duel ";
		if( pvpMode&PVP_MODE::PvpChallenge)
			str+="challenge ";
		if( pvpMode&PVP_MODE::PvpZoneFree)
			str+="free ";
		if( pvpMode&PVP_MODE::PvpZoneFaction)
			str+="zone_faction ";
		if( pvpMode&PVP_MODE::PvpZoneGuild)
			str+="zone_guild ";
		if( pvpMode&PVP_MODE::PvpZoneOutpost)
			str+="outpost ";
		if( pvpMode&PVP_MODE::PvpFaction)
			str+="faction ";
		if( pvpMode&PVP_MODE::PvpFactionFlagged)
			str+="faction_flagged ";
		if( pvpMode&PVP_MODE::PvpZoneSafe)
			str+="in_safe_zone ";
		if( pvpMode&PVP_MODE::PvpSafe)
			str+="safe ";
		IM->displaySystemInfo(ucstring(str));
		nlinfo("<pvpMode> %s",str.c_str());
	}
	else
	{
		PVP_MODE::TPVPMode pvpMode = PVP_MODE::fromString(args[0]);
		bool state;
		fromString(args[1], state);
		if( state )
		{
			uint16 currentPVPMode = playerTarget->getPvpMode();
			currentPVPMode |= pvpMode;
			playerTarget->setPvpMode(currentPVPMode);
			IM->displaySystemInfo(toString("<pvpMode> adding pvp mode %s",args[0].c_str()));
		}
		else
		{
			uint16 currentPVPMode = playerTarget->getPvpMode();
			currentPVPMode &= ~pvpMode;
			playerTarget->setPvpMode(currentPVPMode);
			IM->displaySystemInfo(toString("<pvpMode> removing pvp mode %s",args[0].c_str()));
		}
	}
	playerTarget->buildInSceneInterface();
	return true;
}

/*
NLMISC_COMMAND(pvpClan, "modify pvp clan", "<pvp clan>")
{
	if (args.size() != 1) return false;

	CInterfaceManager *IM = CInterfaceManager::getInstance();

	CEntityCL *target = EntitiesMngr.entity(UserEntity->targetSlot());
	if (!target)
	{
		IM->displaySystemInfo(toString("<pvpClan> no target"));
		return false;
	}
	if (target->Type != CEntityCL::Player && target->Type != CEntityCL::User)
	{
		IM->displaySystemInfo(toString("<pvpMode> target is not a player"));
		return false;
	}
	CPlayerCL *playerTarget = dynamic_cast<CPlayerCL*>(target);
	if (!playerTarget)
		return false;

//	PVP_CLAN::TPVPClan clan = PVP_CLAN::fromString(args[0]);
//	playerTarget->setPvpClan(clan);
	playerTarget->buildInSceneInterface();

	return true;
}
*/
#endif // !FINAL_VERSION

#include "r2/editor.h"

//---------------------------------------------------
// setDead :
// Method to Flag the character as dead and do everything needed.
//---------------------------------------------------
void CCharacterCL::setDead()	// virtual
{
	// If the entity dead is the user -> switch to dead mode.
	if(_Slot == UserEntity->slot())
		UserControls.mode(CUserControls::DeathMode);

	// If the entity killed was the current user target, we update context cursor
	if(_Slot == UserEntity->selection())
	{
		bool nextContextSelected = false;
		// Quartering
		if (!R2::getEditor().isDMing())
		{
			if(_Properties.harvestable())
				nextContextSelected = ContextCur.context("QUARTER");
			// Loot
			else if(_Properties.lootable())
				nextContextSelected = ContextCur.context("LOOT");
			// Pick Up
			else if(_Properties.liftable())
				nextContextSelected = ContextCur.context("PICKUP");
			if( !nextContextSelected )
				ContextCur.context("STAND BY");
		}
	}

	// The character now won't be an obstacle anymore
	_Primitive->setOcclusionMask(MaskColNone);
}// setDead //