diff --git a/proj/sxgame/vs2013/sxgame.vcxproj b/proj/sxgame/vs2013/sxgame.vcxproj
index fed316c00790aab5a2a61029057c26bc4a5ba285..7f3e5ddc166ec66e758f117e73184bdad7a61ab0 100644
--- a/proj/sxgame/vs2013/sxgame.vcxproj
+++ b/proj/sxgame/vs2013/sxgame.vcxproj
@@ -195,6 +195,7 @@
     <ClCompile Include="..\..\..\source\game\EditorObject.cpp" />
     <ClCompile Include="..\..\..\source\game\EditorOutputsTab.cpp" />
     <ClCompile Include="..\..\..\source\game\EntityFactory.cpp" />
+    <ClCompile Include="..\..\..\source\game\EntityList.cpp" />
     <ClCompile Include="..\..\..\source\game\EntityManager.cpp" />
     <ClCompile Include="..\..\..\source\game\EnvSkybox.cpp" />
     <ClCompile Include="..\..\..\source\game\FuncRotating.cpp" />
@@ -267,6 +268,8 @@
     <ClInclude Include="..\..\..\source\game\EditorExtension.h" />
     <ClInclude Include="..\..\..\source\game\EditorObject.h" />
     <ClInclude Include="..\..\..\source\game\EditorOutputsTab.h" />
+    <ClInclude Include="..\..\..\source\game\EntityList.h" />
+    <ClInclude Include="..\..\..\source\game\EntityPointer.h" />
     <ClInclude Include="..\..\..\source\game\EnvSkybox.h" />
     <ClInclude Include="..\..\..\source\game\FuncRotating.h" />
     <ClInclude Include="..\..\..\source\game\GameStateManager.h" />
diff --git a/proj/sxgame/vs2013/sxgame.vcxproj.filters b/proj/sxgame/vs2013/sxgame.vcxproj.filters
index b56011f928a25960c1a89f27dddcc5c7969112e0..7371a9da2d308080086def4dac1f06d82cdde174 100644
--- a/proj/sxgame/vs2013/sxgame.vcxproj.filters
+++ b/proj/sxgame/vs2013/sxgame.vcxproj.filters
@@ -312,6 +312,9 @@
     <ClCompile Include="..\..\..\source\common\guid.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\..\source\game\EntityList.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\..\source\game\sxgame.h">
@@ -539,6 +542,12 @@
     <ClInclude Include="..\..\..\source\game\SoundEmitter.h">
       <Filter>Header Files\ents\sound</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\..\source\game\EntityPointer.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\..\source\game\EntityList.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="..\..\..\source\game\sxgame.rc">
diff --git a/source/anim/DynamicModel.cpp b/source/anim/DynamicModel.cpp
index f83a8ead9a6580097941f65cc73b3bdfebe4aa13..06f265584ec72f15819474e41dac2a6705795278 100644
--- a/source/anim/DynamicModel.cpp
+++ b/source/anim/DynamicModel.cpp
@@ -94,9 +94,12 @@ void XMETHODCALLTYPE CDynamicModel::setPosition(const float3 &vPos)
 	m_vPosition = vPos;
 	m_isWorldDirty = true;
 
-	m_pProvider->notifyModelChanged(this, XEventModelChanged::TYPE_MOVED);
+	if(m_isEnabled)
+	{
+		m_pProvider->notifyModelChanged(this, XEventModelChanged::TYPE_MOVED);
 
-	m_pSceneObject->update(getLocalBound() + getPosition());
+		m_pSceneObject->update(getLocalBound() + getPosition());
+	}
 }
 
 SMQuaternion XMETHODCALLTYPE CDynamicModel::getOrientation() const
@@ -113,9 +116,12 @@ void XMETHODCALLTYPE CDynamicModel::setOrientation(const SMQuaternion &qRot)
 	m_isLocalAABBvalid = false;
 	m_isWorldDirty = true;
 
-	m_pProvider->notifyModelChanged(this, XEventModelChanged::TYPE_MOVED);
+	if(m_isEnabled)
+	{
+		m_pProvider->notifyModelChanged(this, XEventModelChanged::TYPE_MOVED);
 
-	m_pSceneObject->update(getLocalBound() + getPosition());
+		m_pSceneObject->update(getLocalBound() + getPosition());
+	}
 }
 
 float XMETHODCALLTYPE CDynamicModel::getScale() const
@@ -132,9 +138,12 @@ void XMETHODCALLTYPE CDynamicModel::setScale(float fScale)
 	m_isLocalAABBvalid = false;
 	m_isWorldDirty = true;
 
-	m_pProvider->notifyModelChanged(this, XEventModelChanged::TYPE_MOVED);
+	if(m_isEnabled)
+	{
+		m_pProvider->notifyModelChanged(this, XEventModelChanged::TYPE_MOVED);
 
-	m_pSceneObject->update(getLocalBound() + getPosition());
+		m_pSceneObject->update(getLocalBound() + getPosition());
+	}
 }
 
 UINT XMETHODCALLTYPE CDynamicModel::getSkin() const
diff --git a/source/anim/DynamicModelProvider.cpp b/source/anim/DynamicModelProvider.cpp
index cc06aaed5d550f1b81c80d82e8cdb5accb95aacd..bc5df76e702cb858e02aa3be5cd58e81d4e3bd90 100644
--- a/source/anim/DynamicModelProvider.cpp
+++ b/source/anim/DynamicModelProvider.cpp
@@ -300,7 +300,7 @@ void CDynamicModelProvider::onSharedModelReady(CDynamicModelShared *pShared)
 }
 void CDynamicModelProvider::onSharedModelRelease(CDynamicModelShared *pShared)
 {
-	m_mModels[pShared->getResource()] = NULL;
+	m_mModels.erase(pShared->getResource());
 }
 void CDynamicModelProvider::onSharedModelFeaturesChanged(CDynamicModelShared *pShared)
 {
diff --git a/source/common b/source/common
index ace72cd79ddea6874c56131ca7dde7b896f38a03..e3014e94d2fe3e5211344f785df552ad38a62b89 160000
--- a/source/common
+++ b/source/common
@@ -1 +1 @@
-Subproject commit ace72cd79ddea6874c56131ca7dde7b896f38a03
+Subproject commit e3014e94d2fe3e5211344f785df552ad38a62b89
diff --git a/source/core/ResourceManager.cpp b/source/core/ResourceManager.cpp
index 09e48e77e9a392c2e404254bd60b2cceafa04d13..0ff41aa560d0e8711c47e118decad5117156503d 100644
--- a/source/core/ResourceManager.cpp
+++ b/source/core/ResourceManager.cpp
@@ -92,8 +92,8 @@ CResourceManager::CResourceManager(IXCore *pCore):
 
 bool XMETHODCALLTYPE CResourceManager::getModel(const char *szName, IXResourceModel **ppOut, bool bForceReload)
 {
-	const AssotiativeArray<String, IXResourceModel*>::Node *pNode1;
-	if(!bForceReload && m_mpModels.KeyExists(szName, &pNode1) && (*pNode1->Val))
+	const Map<String, IXResourceModel*>::Node *pNode1;
+	if(!bForceReload && m_mpModels.KeyExists(szName, &pNode1))
 	{
 		(*pNode1->Val)->AddRef();
 		*ppOut = *pNode1->Val;
@@ -112,7 +112,7 @@ bool XMETHODCALLTYPE CResourceManager::getModel(const char *szName, IXResourceMo
 	strlwr(szLowcaseExt);
 
 	CResourceModel *pResource = NULL;
-	const AssotiativeArray<AAString, Array<IXModelLoader*>>::Node *pNode;
+	const Map<AAString, Array<IXModelLoader*>>::Node *pNode;
 	if(m_mapModelLoaders.KeyExists(AAString(szLowcaseExt), &pNode))
 	{
 		auto &aLoaders = *pNode->Val;
@@ -284,7 +284,7 @@ bool XMETHODCALLTYPE CResourceManager::getModelInfo(const char *szName, XModelIn
 	char *szLowcaseExt = strdupa(szExt);
 	strlwr(szLowcaseExt);
 
-	const AssotiativeArray<AAString, Array<IXModelLoader*>>::Node *pNode;
+	const Map<AAString, Array<IXModelLoader*>>::Node *pNode;
 	if(m_mapModelLoaders.KeyExists(AAString(szLowcaseExt), &pNode))
 	{
 		auto &aLoaders = *pNode->Val;
@@ -330,7 +330,7 @@ void CResourceManager::onResourceModelRelease(CResourceModel *pResource)
 {
 	if(pResource->getFileName())
 	{
-		m_mpModels[pResource->getFileName()] = NULL;
+		m_mpModels.erase(pResource->getFileName());
 	}
 }
 
@@ -382,16 +382,13 @@ const XFormatName* XMETHODCALLTYPE CResourceManager::getSoundSupportedFormat(UIN
 
 bool XMETHODCALLTYPE CResourceManager::getTexture(const char *szName, IXResourceTexture **ppOut, bool bForceReload)
 {
-	const AssotiativeArray<String, IXResourceTexture*>::Node *pNode1;
+	const Map<String, IXResourceTexture*>::Node *pNode1;
 	if(!bForceReload && m_mpTextures.KeyExists(szName, &pNode1))
 	{
 		IXResourceTexture *pOut = (*pNode1->Val);
-		if(pOut)
-		{
-			*ppOut = pOut;
-			pOut->AddRef();
-			return(true);
-		}
+		*ppOut = pOut;
+		pOut->AddRef();
+		return(true);
 	}
 
 	char *szFileName = strdupa(szName);
@@ -414,7 +411,7 @@ bool XMETHODCALLTYPE CResourceManager::getTexture(const char *szName, IXResource
 	char *szLowcaseExt = strdupa(szExt);
 	strlwr(szLowcaseExt);
 
-	const AssotiativeArray<AAString, Array<IXTextureLoader*>>::Node *pNode;
+	const Map<AAString, Array<IXTextureLoader*>>::Node *pNode;
 	if(m_mapTextureLoaders.KeyExists(AAString(szLowcaseExt), &pNode))
 	{
 		auto &aLoaders = *pNode->Val;
@@ -541,7 +538,7 @@ bool XMETHODCALLTYPE CResourceManager::getTextureInfo(const char *szName, XTextu
 	char *szLowcaseExt = strdupa(szExt);
 	strlwr(szLowcaseExt);
 
-	const AssotiativeArray<AAString, Array<IXTextureLoader*>>::Node *pNode;
+	const Map<AAString, Array<IXTextureLoader*>>::Node *pNode;
 	if(m_mapTextureLoaders.KeyExists(AAString(szLowcaseExt), &pNode))
 	{
 		auto &aLoaders = *pNode->Val;
diff --git a/source/core/ResourceManager.h b/source/core/ResourceManager.h
index b8c4c953c78317f1bebf85a991c95fc87c9e45ff..89642c36c7bf3fea66a13f2759b468deece776ec 100644
--- a/source/core/ResourceManager.h
+++ b/source/core/ResourceManager.h
@@ -50,7 +50,7 @@ public:
 		const char *szName = pTexture->getFileName();
 		if(szName)
 		{
-			m_mpTextures[szName] = NULL;
+			m_mpTextures.erase(szName);
 		}
 	}
 
@@ -60,14 +60,14 @@ public:
 protected:
 	IXCore *m_pCore;
 
-	AssotiativeArray<AAString, Array<IXModelLoader*>> m_mapModelLoaders;
-	AssotiativeArray<String, IXResourceModel*> m_mpModels;
+	Map<AAString, Array<IXModelLoader*>> m_mapModelLoaders;
+	Map<String, IXResourceModel*> m_mpModels;
 	
 	Array<XFormatName> m_aModelExts;
 
 
-	AssotiativeArray<AAString, Array<IXTextureLoader*>> m_mapTextureLoaders;
-	AssotiativeArray<String, IXResourceTexture*> m_mpTextures;
+	Map<AAString, Array<IXTextureLoader*>> m_mapTextureLoaders;
+	Map<String, IXResourceTexture*> m_mpTextures;
 
 	Array<XFormatName> m_aTextureExts;
 
diff --git a/source/core/TaskManager.cpp b/source/core/TaskManager.cpp
index 0581fac28f72fd17da7a92dd1620f1eb46d3df8e..b63dd5ee1574aee7a2ade0a761eb690ffbc3c441 100644
--- a/source/core/TaskManager.cpp
+++ b/source/core/TaskManager.cpp
@@ -115,7 +115,7 @@ void CTaskManager::forceSinglethreaded()
 void CTaskManager::addTask(TaskPtr task, std::chrono::steady_clock::time_point tpWhen)
 {
 	{
-		ScopedSpinLock lock(m_slShedulerArray);
+		ScopedLock lock(m_mutexSchedulerThread);
 		m_aScheduled.insert({task, tpWhen}, [](const ScheduledTask &a, const ScheduledTask &b){
 			return(a.tpRunAt > b.tpRunAt);
 		});
@@ -360,26 +360,25 @@ void CTaskManager::schedulerMain()
 	while(m_isRunning)
 	{
 		tpNow = tpWaitUntil = std::chrono::steady_clock::now();
+
+		std::unique_lock<std::mutex> lock(m_mutexSchedulerThread);
+		for(UINT i = 0, l = m_aScheduled.size(); i < l; ++i)
 		{
-			ScopedSpinLock lock(m_slShedulerArray);
-			for(UINT i = 0, l = m_aScheduled.size(); i < l; ++i)
-			{
-				pScheduledTask = &m_aScheduled[i];
+			pScheduledTask = &m_aScheduled[i];
 
-				if(pScheduledTask->tpRunAt <= tpNow)
-				{
-					addTask(pScheduledTask->pTask);
-					m_aScheduled.erase(i);
-					--i; --l;
-				}
-				else
-				{
-					tpWaitUntil = pScheduledTask->tpRunAt;
-					break;
-				}
+			if(pScheduledTask->tpRunAt <= tpNow)
+			{
+				addTask(pScheduledTask->pTask);
+				m_aScheduled.erase(i);
+				--i; --l;
+			}
+			else
+			{
+				tpWaitUntil = pScheduledTask->tpRunAt;
+				break;
 			}
 		}
-		std::unique_lock<std::mutex> lock(m_mutexSchedulerThread);
+
 		if(tpWaitUntil != tpNow)
 		{
 			m_ConditionSchedulerThread.wait_until(lock, tpWaitUntil);
diff --git a/source/core/TaskManager.h b/source/core/TaskManager.h
index 1f4e98d378290581f2831c4ed26942ba0cb64943..0a312fdf23bdd61caac5b877a7319b8f95233217 100644
--- a/source/core/TaskManager.h
+++ b/source/core/TaskManager.h
@@ -93,7 +93,6 @@ private:
 	mutable mutex m_mutexFor;
 	mutable mutex m_mutexIOThread;
 	mutable mutex m_mutexSchedulerThread;
-	mutable SpinLock m_slShedulerArray;
 	Condition m_Condition;
 	Condition m_ConditionIOThread;
 	Condition m_ConditionSchedulerThread;
diff --git a/source/game/BaseAmmo.cpp b/source/game/BaseAmmo.cpp
index 929b4d3996bd33f9386f50be5e062fcc5eab22ea..9624bfd4d80849e2105dd813a309265d7dcb4a69 100644
--- a/source/game/BaseAmmo.cpp
+++ b/source/game/BaseAmmo.cpp
@@ -61,17 +61,6 @@ protected:
 	btCollisionObject* m_me;
 };
 
-CBaseAmmo::CBaseAmmo(CEntityManager * pMgr):
-	BaseClass(pMgr),
-	m_fStartSpeed(0.0f),
-	m_fBulletMass(0.0f),
-	m_fArmorPiercing(0.0f),
-	m_fNextBarrierDepth(0.0f)
-{
-	//m_bPickable = false;
-	//m_bInvStackable = false;
-}
-
 void CBaseAmmo::fire(const float3 &vStart, const float3 &vDir, CBaseCharacter *pAttacker)
 {
 	extern CTracer *g_pTracer;
diff --git a/source/game/BaseAmmo.h b/source/game/BaseAmmo.h
index 05f1e4abe2840d140c801bb4df957f435f37c368..df926eb7c4c1e243740d908a9cb11a8722b7cb1c 100644
--- a/source/game/BaseAmmo.h
+++ b/source/game/BaseAmmo.h
@@ -26,7 +26,7 @@ class CBaseAmmo: public CBaseSupply
 	DECLARE_CLASS(CBaseAmmo, CBaseSupply);
 	DECLARE_PROPTABLE();
 public:
-	DECLARE_CONSTRUCTOR();
+	DECLARE_TRIVIAL_CONSTRUCTOR();
 
 	//! Стреляет пулю
 	void fire(const float3 &vStart, const float3 &vDir, CBaseCharacter *pAttacker=NULL);
@@ -41,15 +41,15 @@ public:
 protected:
 
 	//! Начальная скорость
-	float m_fStartSpeed;
+	float m_fStartSpeed = 0.0f;
 	//! Масса пули
-	float m_fBulletMass;
+	float m_fBulletMass = 0.0f;
 	//! Бронебойность
-	float m_fArmorPiercing;
+	float m_fArmorPiercing = 0.0f;
 	//! Экспансивная?
-	bool m_isExpansive;
+	bool m_isExpansive = false;
 	//! Разрывная?
-	bool m_isBursting;
+	bool m_isBursting = false;
 
 	struct HitPoint
 	{
@@ -72,7 +72,7 @@ protected:
 	bool canHole(float fDurability, float fCurrentSpeed, float *pfNewSpeed);
 
 	//! Хранит толщину препятствия во время расчета выстрела. Изменяется во время полета от препятствия к препятствию
-	float m_fNextBarrierDepth;
+	float m_fNextBarrierDepth = 0.0f;
 
 	void fire(const float3 &vStart, const float3 &vDir, CBaseCharacter *pAttacker, float fSpeed);
 };
diff --git a/source/game/BaseAmmoBox.cpp b/source/game/BaseAmmoBox.cpp
index f2580eb2d18d61521ee5293cc9187b858b8c3ff3..f9ca62acb248706f118b166d6327e6a351e34813 100644
--- a/source/game/BaseAmmoBox.cpp
+++ b/source/game/BaseAmmoBox.cpp
@@ -24,13 +24,6 @@ END_PROPTABLE()
 
 REGISTER_ENTITY_NOLISTING(CBaseAmmoBox, base_ammobox);
 
-CBaseAmmoBox::CBaseAmmoBox(CEntityManager * pMgr):
-	BaseClass(pMgr)
-{
-	//m_bPickable = false;
-	//m_bInvStackable = false;
-}
-
 void CBaseAmmoBox::onUse(CBaseEntity *pUser)
 {
 	if(m_iCurItems < 0)
diff --git a/source/game/BaseAmmoBox.h b/source/game/BaseAmmoBox.h
index 8c5475579f65dc0ba7581bd0e0c1605eca802e9e..ba52e8a1c75ffa067682e402605c9d0a25f8618e 100644
--- a/source/game/BaseAmmoBox.h
+++ b/source/game/BaseAmmoBox.h
@@ -22,7 +22,7 @@ class CBaseAmmoBox: public CBaseItem
 	DECLARE_CLASS(CBaseAmmoBox, CBaseItem);
 	DECLARE_PROPTABLE();
 public:
-	ThisClass(CEntityManager * pMgr);
+	DECLARE_TRIVIAL_CONSTRUCTOR();
 
 	void onUse(CBaseEntity *pUser);
 
diff --git a/source/game/BaseAnimating.cpp b/source/game/BaseAnimating.cpp
index 43f0e921ce2698dbdd26475c53723f52c080fda0..ee58f156ad3c0e9809ab7654ddfe57699f6e52e1 100644
--- a/source/game/BaseAnimating.cpp
+++ b/source/game/BaseAnimating.cpp
@@ -22,7 +22,7 @@ BEGIN_PROPTABLE(CBaseAnimating)
 	DEFINE_FIELD_FLOATFN(m_fBaseScale, 0, "scale", "Scale", setScale, EDITOR_TEXTFIELD)
 
 	//! Объект референса для цвета свечения
-	DEFINE_FIELD_ENTITY(m_pEntColorRef, 0, "glow_color_ref", "Glow color reference", EDITOR_TEXTFIELD)
+	DEFINE_FIELD_ENTITY(CBaseEntity, m_pEntColorRef, 0, "glow_color_ref", "Glow color reference", EDITOR_TEXTFIELD)
 	//! Цвет свечения
 	DEFINE_FIELD_VECTOR(m_vGlowColor, 0, "glow_color", "Glow color", EDITOR_TEXTFIELD)
 
@@ -77,11 +77,11 @@ private:
 
 //##########################################################################
 
-CBaseAnimating::CBaseAnimating(CEntityManager * pMgr):
-	BaseClass(pMgr)
+CBaseAnimating::CBaseAnimating():
+	m_motionState(this),
+	m_pAnimationCallback(new CAnimationCallback(this))
 {
 	memset(m_vNextAnim, 0, sizeof(m_vNextAnim));
-	m_pAnimationCallback = new CAnimationCallback(this);
 }
 
 CBaseAnimating::~CBaseAnimating()
@@ -191,32 +191,19 @@ SMQuaternion CBaseAnimating::getAttachmentRot(int id)
 	return(/*getOrient() * */rot);
 }
 
+#if 0
 void CBaseAnimating::onSync()
 {
 	BaseClass::onSync();
-	if(!m_pParent && m_pRigidBody && !m_isStatic)
-	{
-		btVector3 &v = m_pRigidBody->getWorldTransform().getOrigin();
-		setPos(BTVEC_F3(v));
-		btQuaternion &q = m_pRigidBody->getWorldTransform().getRotation();
-		setOrient(BTQUAT_Q4(q));
-	}
-	else if(m_pRigidBody)
-	{
-	//	m_pRigidBody->getWorldTransform().setOrigin(F3_BTVEC(getPos()));
-	//	m_pRigidBody->getWorldTransform().setRotation(Q4_BTQUAT(getOrient()));
-	}
 	if(m_pModel && m_pModel->isEnabled())
 	{
-		m_pModel->setPosition(getPos());
-		m_pModel->setOrientation(getOrient());
-
 		float3_t vGlowColor = m_vGlowColor;
 		//bool isGlowEnabled = m_pEntColorRef ? m_pEntColorRef->getMainColor(&vGlowColor) : m_vGlowColor.x != 0.0f || m_vGlowColor.y != 0.0f || m_vGlowColor.z != 0.0f;
 		m_pModel->setColor(float4(vGlowColor));
 		//m_pAnimPlayer->setGlowEnabled(isGlowEnabled);
 	}
 }
+#endif
 
 void CBaseAnimating::playAnimation(const char * name, UINT iFadeTime, UINT slot)
 {
@@ -382,10 +369,9 @@ void CBaseAnimating::createPhysBody()
 		const float fMass = 1.0f;
 		m_pCollideShape->calculateLocalInertia(fMass, vInertia);
 
-		btDefaultMotionState * motionState = new btDefaultMotionState(btTransform(Q4_BTQUAT(m_vOrientation), F3_BTVEC(m_vPosition)));
 		btRigidBody::btRigidBodyConstructionInfo rigidBodyCI(
 			fMass,                  // mass
-			motionState,        // initial position
+			&m_motionState,        // initial position
 			m_pCollideShape,    // collision shape of body
 			vInertia  // local inertia
 			);
@@ -450,15 +436,15 @@ COLLISION_GROUP CBaseAnimating::getCollisionGroup()
 	return(m_collisionGroup);
 }
 
-void CBaseAnimating::setPos(const float3 & pos)
+void CBaseAnimating::setPos(const float3 &pos)
 {
 	BaseClass::setPos(pos);
 	if(m_pRigidBody)
 	{
-		m_pRigidBody->getWorldTransform().setOrigin(F3_BTVEC(pos));
-
 		SPhysics_GetDynWorld()->updateSingleAabb(m_pRigidBody);
 	}
+
+	SAFE_CALL(m_pModel, setPosition, pos);
 }
 
 void CBaseAnimating::setOrient(const SMQuaternion & q)
@@ -466,10 +452,10 @@ void CBaseAnimating::setOrient(const SMQuaternion & q)
 	BaseClass::setOrient(q);
 	if(m_pRigidBody)
 	{
-		m_pRigidBody->getWorldTransform().setRotation(Q4_BTQUAT(q));
-
 		SPhysics_GetDynWorld()->updateSingleAabb(m_pRigidBody);
 	}
+
+	SAFE_CALL(m_pModel, setOrientation, q);
 }
 
 void CBaseAnimating::_cleanup()
diff --git a/source/game/BaseAnimating.h b/source/game/BaseAnimating.h
index 30195eb793ffa472eafc0075944116dff5da751d..e5336bcd4de9646f8c99ca3cb9dcd20f331e9b19 100644
--- a/source/game/BaseAnimating.h
+++ b/source/game/BaseAnimating.h
@@ -22,6 +22,37 @@ See the license in LICENSE
 
 #define BLEND_MAX 4
 
+struct CMotionState: public btMotionState
+{
+private:
+	CBaseEntity *m_pEntity;
+
+public:
+	CMotionState(CBaseEntity *pEntity):
+		m_pEntity(pEntity)
+	{
+	}
+
+	///synchronizes world transform from user to physics
+	void getWorldTransform(btTransform &centerOfMassWorldTrans) const override
+	{
+		float3 vPos = m_pEntity->getPos();
+		SMQuaternion qRot = m_pEntity->getOrient();
+
+		centerOfMassWorldTrans = btTransform(Q4_BTQUAT(qRot), F3_BTVEC(vPos));
+	}
+
+	///synchronizes world transform from physics to user
+	///Bullet only calls the update of worldtransform for active objects
+	void setWorldTransform(const btTransform& centerOfMassWorldTrans) override
+	{
+		const btVector3 &v = centerOfMassWorldTrans.getOrigin();
+		const btQuaternion &q = centerOfMassWorldTrans.getRotation();
+		m_pEntity->setPos(BTVEC_F3(v));
+		m_pEntity->setOrient(BTQUAT_Q4(q));
+	}
+};
+
 class CAnimationCallback;
 //! Анимированный игровой объект
 class CBaseAnimating: public CBaseEntity
@@ -31,19 +62,17 @@ class CBaseAnimating: public CBaseEntity
 
 	friend class CAnimationCallback;
 public:
-	CBaseAnimating(CEntityManager * pMgr);
+	DECLARE_CONSTRUCTOR();
 	~CBaseAnimating();
 
-	void getMinMax(float3 * min, float3 * max);
+	void getMinMax(float3 *min, float3 *max);
 	// void getSphere(float3 * center, float * radius);
 
 	virtual void setModel(const char *szMdl);
 	virtual void setScale(float fScale);
 
-	float3 getAttachmentPos(int id);
-	SMQuaternion getAttachmentRot(int id);
-
-	void onSync() override;
+	float3 getAttachmentPos(int id) override;
+	SMQuaternion getAttachmentRot(int id) override;
 
 	void playAnimation(const char * name, UINT uFadeTime = 0, UINT slot = 0);
 	void playActivity(const char * name, UINT uFadeTime = 0, UINT slot = 0);
@@ -68,13 +97,13 @@ protected:
 	virtual void _initEditorBoxes();
 	virtual void _releaseEditorBoxes();
 
-	void inputPlayAnim(inputdata_t * pInputdata);
-	void inputPlayAnimNext(inputdata_t * pInputdata);
+	void inputPlayAnim(inputdata_t *pInputdata);
+	void inputPlayAnimNext(inputdata_t *pInputdata);
 
-	void inputPlayActivity(inputdata_t * pInputdata);
-	void inputPlayActivityNext(inputdata_t * pInputdata);
+	void inputPlayActivity(inputdata_t *pInputdata);
+	void inputPlayActivityNext(inputdata_t *pInputdata);
 
-	void inputSetSkin(inputdata_t * pInputdata);
+	void inputSetSkin(inputdata_t *pInputdata);
 
 	IXModel *m_pModel = NULL;
 	const char * m_szModelFile;
@@ -82,7 +111,7 @@ protected:
 	bool m_isStatic = false;
 	bool m_useAutoPhysbox = true;
 
-	CBaseEntity *m_pEntColorRef = NULL;
+	CEntityPointer<CBaseEntity> m_pEntColorRef;
 	float3_t m_vGlowColor;
 
 	virtual void initPhysics();
@@ -115,6 +144,8 @@ private:
 	COLLISION_GROUP m_collisionGroup = CG_DEFAULT;
 	COLLISION_GROUP m_collisionMask = CG_ALL;
 	CAnimationCallback *m_pAnimationCallback;
+
+	CMotionState m_motionState;
 };
 
 #endif
diff --git a/source/game/BaseCharacter.cpp b/source/game/BaseCharacter.cpp
index e11f41959166a54bbd9e95890a59426ad53436e4..c0e866e83e7edd1ac96a29e9235628819647822c 100644
--- a/source/game/BaseCharacter.cpp
+++ b/source/game/BaseCharacter.cpp
@@ -21,6 +21,8 @@ END_PROPTABLE()
 
 REGISTER_ENTITY_NOLISTING(CBaseCharacter, base_character);
 
+IEventChannel<XEventPhysicsStep> *CBaseCharacter::m_pTickEventChannel = NULL;
+
 class btKinematicClosestNotMeRayResultCallback: public btCollisionWorld::ClosestRayResultCallback
 {
 public:
@@ -45,19 +47,24 @@ protected:
 	btCollisionObject* m_me;
 };
 
-CBaseCharacter::CBaseCharacter(CEntityManager * pMgr):
-	BaseClass(pMgr),
-	m_uMoveDir(PM_OBSERVER),
-	m_vPitchYawRoll(float3_t(0, 0, 0)),
-	m_pActiveTool(NULL),
-	m_fCurrentSpread(0.0f),
-	m_pHitboxBodies(NULL),
-	m_fCapsHeight(1.8f),
-	m_fCapsHeightCrouch(1.2f),
-	m_fCapsRadius(0.4f),
-	m_idQuadLast(-1),
-	m_fCurrentHeight(1.0f)
+void CCharacterPhysicsTickEventListener::onEvent(const XEventPhysicsStep *pData)
+{
+	m_pCharacter->onPhysicsStep();
+}
+
+CBaseCharacter::CBaseCharacter():
+	m_physicsTicker(this)
+{
+	if(!m_pTickEventChannel)
+	{
+		m_pTickEventChannel = Core_GetIXCore()->getEventChannel<XEventPhysicsStep>(EVENT_PHYSICS_STEP_GUID);
+	}
+}
+
+void CBaseCharacter::onPostLoad()
 {
+	BaseClass::onPostLoad();
+
 	m_pCollideShape = new btCapsuleShape(m_fCapsRadius, m_fCapsHeight - m_fCapsRadius * 2.0f);
 
 	btTransform startTransform;
@@ -69,7 +76,8 @@ CBaseCharacter::CBaseCharacter(CEntityManager * pMgr):
 
 	//btTransform startTransform;
 	startTransform.setIdentity();
-	startTransform.setOrigin(F3_BTVEC(m_vPosition + float3(0.0f, m_fCapsHeight * 0.5f, 0.0f)));
+	float3 vPos = getPos() + float3(0.0f, m_fCapsHeight * 0.5f, 0.0f);
+	startTransform.setOrigin(F3_BTVEC(vPos));
 	//startTransform.setOrigin(btVector3(0, 12, 10));
 
 	m_pGhostObject = new btPairCachingGhostObject();
@@ -123,10 +131,14 @@ CBaseCharacter::CBaseCharacter(CEntityManager * pMgr):
 	m_idTaskSpread = SET_INTERVAL(updateSpread, 1.0f / 30.0f);
 
 	m_pInventory = new CCharacterInventory(this);
+
+	m_pTickEventChannel->addListener(&m_physicsTicker);
 }
 
 CBaseCharacter::~CBaseCharacter()
 {
+	m_pTickEventChannel->removeListener(&m_physicsTicker);
+
 	CLEAR_INTERVAL(m_idTaskSpread);
 	REMOVE_ENTITY(m_pHeadEnt);
 	REMOVE_ENTITY(m_flashlight);
@@ -437,10 +449,15 @@ void CBaseCharacter::releaseHitboxes()
 	mem_delete_a(m_pHitboxBodies);
 }
 
-void CBaseCharacter::onSync()
+float3 CBaseCharacter::getHeadOffset()
 {
-	BaseClass::onSync();
+	float3 vHeadOffset; // = m_pHeadEnt->getOffsetPos();
+	vHeadOffset.y = m_fCapsHeight * m_fCurrentHeight - 0.1f;
+	return(vHeadOffset);
+}
 
+void CBaseCharacter::onPhysicsStep()
+{
 	updateHitboxes();
 
 	if(m_uMoveDir & PM_OBSERVER)
@@ -448,13 +465,11 @@ void CBaseCharacter::onSync()
 		return;
 	}
 	btTransform &trans = m_pGhostObject->getWorldTransform();
-	m_vPosition = (float3)(float3(trans.getOrigin().x(), trans.getOrigin().y() - m_fCapsHeight * m_fCurrentHeight * 0.5f, trans.getOrigin().z()));
-
-	float3 vHeadOffset = m_pHeadEnt->getOffsetPos();
-	vHeadOffset.y = m_fCapsHeight * m_fCurrentHeight - 0.1f;
-	m_pHeadEnt->setOffsetPos(vHeadOffset);
+	setPos(float3(trans.getOrigin().x(), trans.getOrigin().y() - m_fCapsHeight * m_fCurrentHeight * 0.5f, trans.getOrigin().z()));
 
+	m_pHeadEnt->setOffsetPos(getHeadOffset());
 
+#if 0
 	//находим текущий квад аи сетки на котором находится игрок
 	ID idq = SAIG_QuadGet(&float3(m_vPosition), true);
 	//если нашли
@@ -477,6 +492,7 @@ void CBaseCharacter::onSync()
 
 		m_idQuadCurr = idq;
 	}
+#endif
 }
 
 void CBaseCharacter::initPhysics()
diff --git a/source/game/BaseCharacter.h b/source/game/BaseCharacter.h
index 0c2b1559bc47f0c250fd43640e9f7bb5602b289d..6843723365c5e49fbefdee70ca99b026876a10f2 100644
--- a/source/game/BaseCharacter.h
+++ b/source/game/BaseCharacter.h
@@ -42,13 +42,29 @@ enum PLAYER_MOVE
 
 class CHUDcontroller;
 
+class CBaseCharacter;
+class CCharacterPhysicsTickEventListener final: public IEventListener<XEventPhysicsStep>
+{
+public:
+	CCharacterPhysicsTickEventListener(CBaseCharacter *pTrigger):
+		m_pCharacter(pTrigger)
+	{
+	}
+	void onEvent(const XEventPhysicsStep *pData) override;
+
+private:
+	CBaseCharacter *m_pCharacter;
+};
+
 //! Класс игрока  \ingroup cbaseanimating
 class CBaseCharacter: public CBaseAnimating
 {
 	DECLARE_CLASS(CBaseCharacter, CBaseAnimating);
 	DECLARE_PROPTABLE();
+
+	friend class CCharacterPhysicsTickEventListener;
 public:
-	CBaseCharacter(CEntityManager * pMgr);
+	DECLARE_CONSTRUCTOR();
 	~CBaseCharacter();
 
 	//! Запускает/останавливает первичную атаку
@@ -83,8 +99,6 @@ public:
 	void releaseHitboxes();
 	void updateHitboxes();
 
-	void onSync();
-
 	void initPhysics();
 	void releasePhysics();
 
@@ -118,26 +132,28 @@ public:
 		return(m_pHandsModelResource);
 	}
 
+	void onPostLoad() override;
+
 protected:
 	//! Фонарик
 	CLightDirectional* m_flashlight;
 
 	//! Текущее движение
-	UINT m_uMoveDir;
+	UINT m_uMoveDir = PM_OBSERVER;
 
 	//! Текущий инструмент в руках
-	CBaseTool * m_pActiveTool;
+	CBaseTool *m_pActiveTool = NULL;
 
 	//! Для физики @{
-	btCollisionShape * m_pCollideShape;
-	btRigidBody * m_pRigidBody;
-	btPairCachingGhostObject * m_pGhostObject;
-	btKinematicCharacterController * m_pCharacter;
-	btRigidBody ** m_pHitboxBodies;
+	btCollisionShape *m_pCollideShape = NULL;
+	btRigidBody *m_pRigidBody = NULL;
+	btPairCachingGhostObject *m_pGhostObject = NULL;
+	btKinematicCharacterController *m_pCharacter = NULL;
+	btRigidBody **m_pHitboxBodies = NULL;
 	//! @}
 
 	//! Углы вращения игрока
-	float3_t m_vPitchYawRoll;
+	float3_t m_vPitchYawRoll = float3_t(0, 0, 0);
 
 	//! Мгновенное значение коэффициента разброса
 	float getMomentSpread();
@@ -149,22 +165,29 @@ protected:
 	virtual void updateSpread(float dt);
 
 	//! Действующее значение разброса
-	float m_fCurrentSpread;
+	float m_fCurrentSpread = 0.0f;
 
-	CCharacterInventory * m_pInventory;
+	CCharacterInventory *m_pInventory = NULL;
 
-	ID m_idQuadCurr;	//!< текущий квад аи сетки на котором стоит игрок
-	ID m_idQuadLast;	//!< Последний валидный квад аи сетки на котором стоял игрок
+	ID m_idQuadCurr = -1;	//!< текущий квад аи сетки на котором стоит игрок
+	ID m_idQuadLast = -1;	//!< Последний валидный квад аи сетки на котором стоял игрок
 
-	float m_fCapsHeight;
-	float m_fCapsHeightCrouch;
-	float m_fCapsRadius;
+	float m_fCapsHeight = 1.8f;
+	float m_fCapsHeightCrouch = 1.2f;
+	float m_fCapsRadius = 0.4f;
 
-	CPointEntity * m_pHeadEnt;
+	CPointEntity *m_pHeadEnt = NULL;
 
-	float m_fCurrentHeight;
+	float m_fCurrentHeight = 1.0f;
 
 	IXResourceModelAnimated *m_pHandsModelResource = NULL;
+
+	virtual float3 getHeadOffset();
+
+private:
+	static IEventChannel<XEventPhysicsStep> *m_pTickEventChannel;
+	CCharacterPhysicsTickEventListener m_physicsTicker;
+	void onPhysicsStep();
 };
 
 #endif
diff --git a/source/game/BaseEntity.cpp b/source/game/BaseEntity.cpp
index 65a8f2ac5050371187312156379bcbed47e72a6f..18df921c0603dad288073ba305b3ccf39be22221 100644
--- a/source/game/BaseEntity.cpp
+++ b/source/game/BaseEntity.cpp
@@ -18,17 +18,17 @@ See the license in LICENSE
 
 BEGIN_PROPTABLE_NOBASE(CBaseEntity)
 	//! Имя объекта
-	DEFINE_FIELD_STRING(m_szName, 0, "name", "Name", EDITOR_TEXTFIELD)
+	DEFINE_FIELD_STRINGFN(m_szName, 0, "name", "Name", setName, EDITOR_TEXTFIELD)
 	//! Позиция в мире
 	DEFINE_FIELD_VECTORFN(m_vPosition, 0, "origin", "Origin", setPos, EDITOR_TEXTFIELD)
 	//! Ориентация в мире, углы эйлера или кватернион
-	DEFINE_FIELD_ANGLES(m_vOrientation, 0, "rotation", "Rotation", EDITOR_TEXTFIELD)
+	DEFINE_FIELD_ANGLESFN(m_qOrientation, 0, "rotation", "Rotation", setOrient, EDITOR_TEXTFIELD)
 	//! Родительский объект в иерархии движения
-	DEFINE_FIELD_PARENT(m_pParent, 0, "parent", "Parent entity", EDITOR_TEXTFIELD)
+	DEFINE_FIELD_ENTITY(CBaseEntity, m_pParent, 0, "parent", "Parent entity", EDITOR_TEXTFIELD)
 	//! Флаги объекта
 	DEFINE_FIELD_FLAGS(m_iFlags, 0, "flags", "Flags", EDITOR_FLAGS)
 	//! Объект-владелец
-	DEFINE_FIELD_ENTITY(m_pOwner, PDFF_NOEXPORT | PDFF_NOEDIT, "owner", "", EDITOR_NONE)
+	DEFINE_FIELD_ENTITY(CBaseEntity, m_pOwner, PDFF_NOEXPORT | PDFF_NOEDIT, "owner", "", EDITOR_NONE)
 	//! Здоровье
 	DEFINE_FIELD_FLOAT(m_fHealth, PDFF_NOEXPORT | PDFF_NOEDIT, "health", "", EDITOR_NONE)
 
@@ -43,36 +43,34 @@ REGISTER_ENTITY_NOLISTING(CBaseEntity, base_entity);
 
 void CBaseEntity::setDefaults()
 {
-	proptable_t * pt = getPropTable();
-	const char * estr = GetEmptyString();
+	proptable_t *pt = getPropTable();
+	const char *estr = GetEmptyString();
 	while(pt)
 	{
 		for(int i = 0; i < pt->numFields; ++i)
 		{
-			if(pt->pData[i].type == PDF_STRING && !(pt->pData[i].flags & PDFF_INPUT))
+			if(!(pt->pData[i].flags & PDFF_INPUT))
 			{
-				this->*((const char * ThisClass::*)pt->pData[i].pField) = estr;
+				if(pt->pData[i].type == PDF_STRING)
+				{
+					this->*((const char* ThisClass::*)pt->pData[i].pField) = estr;
+				}
+				else if(pt->pData[i].type == PDF_ENTITY)
+				{
+					(this->*((CEntityPointer<CBaseEntity> ThisClass::*)pt->pData[i].pField)).init(this);
+				}
 			}
 		}
 		pt = pt->pBaseProptable;
 	}
 }
 
-CBaseEntity::CBaseEntity(CEntityManager * pWorld):
-	m_iId(0),
-	m_iFlags(0),
-	m_pMgr(pWorld),
-	m_szClassName(NULL),
-	m_szName(NULL),
-	m_pParent(NULL),
-	m_iParentAttachment(-1),
-	m_pOwner(NULL),
-	m_fHealth(100.0f)/*,
-	m_vDiscreteLinearVelocity(float3_t(0.0f, 0.0f, 0.0f))*/
-	, m_bSynced(false)
+CBaseEntity::CBaseEntity()
 {
-	m_iId = pWorld->reg(this);
 	m_pLightSystem = GameData::m_pLightSystem;
+
+	m_pParent.setLinkEstablishedListener(&CBaseEntity::onParentSet);
+	m_pParent.setLinkBrokenListener(&CBaseEntity::onParentUnset);
 }
 
 /*void CBaseEntity::setDefaults()
@@ -97,7 +95,7 @@ CBaseEntity::~CBaseEntity()
 {
 	_releaseEditorBoxes();
 
-	m_pMgr->unreg(m_iId);
+	m_pMgr->unreg(this);
 
 	proptable_t * pt = getPropTable();
 	const char * estr = GetEmptyString();
@@ -116,6 +114,11 @@ CBaseEntity::~CBaseEntity()
 		}
 		pt = pt->pBaseProptable;
 	}
+
+	if(m_pParent)
+	{
+		m_pParent->removeChild(this);
+	}
 }
 
 void CBaseEntity::setClassName(const char * name)
@@ -123,12 +126,12 @@ void CBaseEntity::setClassName(const char * name)
 	m_szClassName = name;
 }
 
-const char * CBaseEntity::getName()
+const char* CBaseEntity::getName()
 {
 	return(m_szName);
 }
 
-const char * CBaseEntity::getClassName()
+const char* CBaseEntity::getClassName()
 {
 	return(m_szClassName);
 }
@@ -151,25 +154,24 @@ void CBaseEntity::getSphere(float3 * center, float * radius)
 		radius = 0;
 }
 
-void CBaseEntity::setPos(const float3 & pos)
+void CBaseEntity::setPos(const float3 &pos)
 {
-	CBaseEntity *pParent = NULL;
-	if(m_pParent)
-	{
-		pParent = m_pParent;
-		setParent(NULL);
-	}
 	m_vPosition = pos;
 
+	onParentMoved(true);
+
 	if(m_pEditorRigidBody)
 	{
 		m_pEditorRigidBody->getWorldTransform().setOrigin(F3_BTVEC(m_vPosition));
 		SPhysics_GetDynWorld()->updateSingleAabb(m_pEditorRigidBody);
 	}
 
-	if(pParent)
 	{
-		setParent(pParent, m_iParentAttachment);
+		ScopedSpinLock lock(m_slChildren);
+		for(UINT i = 0, l = m_aChildren.size(); i < l; ++i)
+		{
+			m_aChildren[i]->onParentMoved(m_isSeparateMovement);
+		}
 	}
 }
 
@@ -180,16 +182,47 @@ float3 CBaseEntity::getPos()
 
 void CBaseEntity::setOrient(const SMQuaternion & q)
 {
-	m_vOrientation = q;
+	m_qOrientation = q;
+
+	onParentMoved(true);
+
+	{
+		ScopedSpinLock lock(m_slChildren);
+		for(UINT i = 0, l = m_aChildren.size(); i < l; ++i)
+		{
+			m_aChildren[i]->onParentMoved(m_isSeparateMovement);
+		}
+	}
 }
 void CBaseEntity::setOffsetOrient(const SMQuaternion & q)
 {
-	m_vOffsetOrient = q;
+	m_qOffsetOrient = q;
+	onParentMoved();
 }
 
 void CBaseEntity::setOffsetPos(const float3 & pos)
 {
 	m_vOffsetPos = pos;
+	onParentMoved();
+}
+
+void CBaseEntity::setXform(const float3 &vPos, const SMQuaternion &q)
+{
+	bool bOld = m_isInOnParentMoved;
+	m_isInOnParentMoved = true;
+	setPos(vPos);
+	m_isInOnParentMoved = bOld;
+
+	setOrient(q);
+}
+void CBaseEntity::setOffsetXform(const float3 &vPos, const SMQuaternion &q)
+{
+	bool bOld = m_isInOnParentMoved;
+	m_isInOnParentMoved = true;
+	setOffsetPos(vPos);
+	m_isInOnParentMoved = bOld;
+
+	setOffsetOrient(q);
 }
 
 float3 CBaseEntity::getOffsetPos()
@@ -199,13 +232,33 @@ float3 CBaseEntity::getOffsetPos()
 
 SMQuaternion CBaseEntity::getOrient()
 {
-	return(m_vOrientation);
+	return(m_qOrientation);
 }
 
-
-ID CBaseEntity::getId()
+void CBaseEntity::onParentMoved(bool bAdjustOffsets)
 {
-	return(m_iId);
+	if(!m_pParent || m_isInOnParentMoved)
+	{
+		return;
+	}
+
+	m_isInOnParentMoved = true;
+
+	float3 vParentPos = ID_VALID(m_iParentAttachment) ? m_pParent->getAttachmentPos(m_iParentAttachment) : m_pParent->getPos();
+	SMQuaternion qParentOrient = ID_VALID(m_iParentAttachment) ? m_pParent->getAttachmentRot(m_iParentAttachment) : m_pParent->getOrient();
+
+	if(bAdjustOffsets)
+	{
+		m_vOffsetPos = (float3)(qParentOrient.Conjugate() * (m_vPosition - vParentPos));
+		m_qOffsetOrient = m_qOrientation * qParentOrient.Conjugate();
+	}
+	else
+	{
+		setPos(vParentPos + qParentOrient * m_vOffsetPos);
+		setOrient(m_qOffsetOrient * qParentOrient);
+	}
+
+	m_isInOnParentMoved = false;
 }
 
 UINT CBaseEntity::getFlags()
@@ -220,7 +273,7 @@ void CBaseEntity::setFlags(UINT f)
 
 SMMATRIX CBaseEntity::getWorldTM()
 {
-	return(m_vOrientation.GetMatrix() * SMMatrixTranslation(m_vPosition));
+	return(m_qOrientation.GetMatrix() * SMMatrixTranslation(m_vPosition));
 }
 
 bool CBaseEntity::setKV(const char * name, const char * value)
@@ -235,7 +288,6 @@ bool CBaseEntity::setKV(const char * name, const char * value)
 	SMQuaternion q;
 	int d;
 	float f;
-	CBaseEntity * pEnt;
 	switch(field->type)
 	{
 	case PDF_INT:
@@ -354,34 +406,8 @@ bool CBaseEntity::setKV(const char * name, const char * value)
 		}
 		return(false);
 	case PDF_ENTITY:
-	case PDF_PARENT:
-		pEnt = m_pMgr->findEntityByName(value);
-		if(pEnt || !value[0])
-		{
-			if(field->type == PDF_PARENT)
-			{
-				setParent(pEnt);
-			}
-			else
-			{
-				// check type of pEnt
-				if(field->pfnCheckType && !field->pfnCheckType(pEnt))
-				{
-					LibReport(REPORT_MSG_LEVEL_ERROR, "Unable to set entity field '%s' to entity '%s'. Invalid class. Ent: %s", name, value, m_szName);
-					return(false);
-				}
-				if(field->fnSet.e)
-				{
-					(this->*(field->fnSet.e))(pEnt);
-				}
-				else
-				{
-					this->*((CBaseEntity* ThisClass::*)field->pField) = pEnt;
-				}
-			}
-			return(true);
-		}
-		return(false);
+		(this->*((CEntityPointer<CBaseEntity> ThisClass::*)field->pField)).setEntityName(value);
+		return(true);
 	case PDF_FLAGS:
 		if(1 == sscanf(value, "%d", &d))
 		{
@@ -402,14 +428,13 @@ bool CBaseEntity::setKV(const char * name, const char * value)
 			iConns = parse_str(str, parts, iConns, ',');
 
 			output_t *pOutput = &(this->*((output_t ThisClass::*)field->pField));
-			mem_delete_a(pOutput->pOutputs);
 			{
 				char *pTmpData = (char*)pOutput->pData;
 				mem_delete_a(pTmpData);
 			}
 			pOutput->pData = str;
-			pOutput->pOutputs = new named_output_t[iConns];
-			pOutput->bDirty = true;
+			pOutput->aOutputs.clearFast();
+			pOutput->aOutputs.reserve(iConns);
 
 			int curr = 0;
 			for(int i = 0; i < iConns; ++i)
@@ -444,11 +469,13 @@ bool CBaseEntity::setKV(const char * name, const char * value)
 					printf(COLOR_LRED "Unable to parse output delay '%s' ent %s\n" COLOR_RESET, name, m_szName);
 					continue;
 				}
-				pOutput->pOutputs[curr].fDelay = fDelayFrom;
-				pOutput->pOutputs[curr].fDelayTo = fDelayTo;
+				named_output_t &out = pOutput->aOutputs[curr];
+
+				out.fDelay = fDelayFrom;
+				out.fDelayTo = fDelayTo;
 				if(fDelayFrom < fDelayTo)
 				{
-					pOutput->pOutputs[curr].useRandomDelay = true;
+					out.useRandomDelay = true;
 				}
 				if(fDelayFrom > fDelayTo)
 				{
@@ -456,14 +483,15 @@ bool CBaseEntity::setKV(const char * name, const char * value)
 					continue;
 				}
 
-				pOutput->pOutputs[curr].szTargetName = fields[0];
-				pOutput->pOutputs[curr].szTargetInput = fields[1];
-				pOutput->pOutputs[curr].szTargetData = param;
-				pOutput->pOutputs[curr].iFireLimit = iFireLimit;
+				out.szTargetName = fields[0];
+				out.szTargetInput = fields[1];
+				out.szTargetData = param;
+				out.iFireLimit = iFireLimit;
 				
+				out.init(this);
+
 				++curr;
 			}
-			pOutput->iOutCount = curr;
 		}
 		// target_name:input:delay:parameter\n<repeat>
 		return(false);
@@ -481,7 +509,6 @@ bool CBaseEntity::getKV(const char * name, char * out, int bufsize)
 	}
 	SMQuaternion q;
 	float3_t f3;
-	CBaseEntity *pEnt;
 	switch(field->type)
 	{
 	case PDF_INT:
@@ -511,53 +538,46 @@ bool CBaseEntity::getKV(const char * name, char * out, int bufsize)
 		sprintf_s(out, bufsize, "%f %f %f %f", q.x, q.y, q.z, q.w);
 		break;
 	case PDF_ENTITY:
-	case PDF_PARENT:
-		pEnt = this->*((CBaseEntity * ThisClass::*)field->pField);
-		if(!pEnt)
-		{
-			sprintf_s(out, bufsize, "");
-		}
-		else
-		{
-			sprintf_s(out, bufsize, "%s", pEnt->getName());
-		}
+		(this->*((CEntityPointer<CBaseEntity> ThisClass::*)field->pField)).getEntityName(out, bufsize);
 		break;
 	case PDF_OUTPUT:
 		{
 			output_t *pOutput = &(this->*((output_t ThisClass::*)field->pField));
 			int iWritten = 0;
 			char * szOutBuf = out;
-			if(pOutput->iOutCount == 0)
+			*out = 0;
+			if(pOutput->aOutputs.size() == 0)
 			{
 				*out = 0;
 			}
-			for(int i = 0; i < pOutput->iOutCount; ++i)
+			for(UINT i = 0, l = pOutput->aOutputs.size(); i < l; ++i)
 			{
+				named_output_t &out = pOutput->aOutputs[i];
 				if(i > 0)
 				{
 					*szOutBuf = ',';
 					++szOutBuf;
 				}
 				int c;
-				if(pOutput->pOutputs[i].useRandomDelay)
+				if(out.useRandomDelay)
 				{
 					c = _snprintf(szOutBuf, bufsize - iWritten, "%s:%s:%f-%f:%s:%d", 
-						pOutput->pOutputs[i].szTargetName, 
-						pOutput->pOutputs[i].szTargetInput, 
-						pOutput->pOutputs[i].fDelay,
-						pOutput->pOutputs[i].fDelayTo,
-						pOutput->pOutputs[i].szTargetData ? pOutput->pOutputs[i].szTargetData : ENT_OUTPUT_PARAM_NONE,
-						pOutput->pOutputs[i].iFireLimit
+						out.szTargetName, 
+						out.szTargetInput, 
+						out.fDelay,
+						out.fDelayTo,
+						out.szTargetData ? out.szTargetData : ENT_OUTPUT_PARAM_NONE,
+						out.iFireLimit
 						);
 				}
 				else
 				{
 					c = _snprintf(szOutBuf, bufsize - iWritten, "%s:%s:%f:%s:%d", 
-						pOutput->pOutputs[i].szTargetName, 
-						pOutput->pOutputs[i].szTargetInput, 
-						pOutput->pOutputs[i].fDelay, 
-						pOutput->pOutputs[i].szTargetData ? pOutput->pOutputs[i].szTargetData : ENT_OUTPUT_PARAM_NONE,
-						pOutput->pOutputs[i].iFireLimit
+						out.szTargetName, 
+						out.szTargetInput, 
+						out.fDelay, 
+						out.szTargetData ? out.szTargetData : ENT_OUTPUT_PARAM_NONE,
+						out.iFireLimit
 						);
 				}
 				iWritten += c + 1;
@@ -572,21 +592,45 @@ bool CBaseEntity::getKV(const char * name, char * out, int bufsize)
 	return(true);
 }
 
-void CBaseEntity::setParent(CBaseEntity * pEnt, int attachment)
+void CBaseEntity::onParentSet(CBaseEntity *pNewParent)
+{
+	if(pNewParent)
+	{
+		onParentMoved(true);
+		
+		pNewParent->addChild(this);
+	}
+}
+
+void CBaseEntity::onParentUnset(CBaseEntity *pOldParent)
+{
+	if(pOldParent)
+	{
+		pOldParent->removeChild(this);
+	}
+}
+
+void CBaseEntity::addChild(CBaseEntity *pEnt)
+{
+	ScopedSpinLock lock(m_slChildren);
+	m_aChildren.push_back(pEnt);
+}
+void CBaseEntity::removeChild(CBaseEntity *pEnt)
+{
+	ScopedSpinLock lock(m_slChildren);
+	int idx = m_aChildren.indexOf(pEnt);
+	assert(idx >= 0);
+	if(idx >= 0)
+	{
+		m_aChildren.erase(idx);
+	}
+}
+
+void CBaseEntity::setParent(CBaseEntity *pEnt, int attachment)
 {
 	m_pParent = pEnt;
 	if(pEnt)
 	{
-		if(attachment >= 0)
-		{
-			m_vOffsetPos = (float3)(m_vPosition - m_pParent->getAttachmentPos(attachment));
-			m_vOffsetOrient = m_vOrientation * m_pParent->getAttachmentRot(attachment).Conjugate();
-		}
-		else
-		{
-			m_vOffsetPos = m_pParent->getOrient().Conjugate() * (float3)(m_vPosition - m_pParent->getPos());
-			m_vOffsetOrient = m_vOrientation * m_pParent->getOrient().Conjugate();
-		}
 		m_iParentAttachment = attachment;
 	}
 }
@@ -628,43 +672,8 @@ CBaseEntity* CBaseEntity::getParent()
 	}
 }*/
 
-void CBaseEntity::onSync()
-{
-	m_bSynced = true;
-
-	if(m_pParent)
-	{
-		if(!m_pParent->m_bSynced)
-		{
-			m_pParent->onSync();
-		}
-		if(m_iParentAttachment >= 0)
-		{
-			m_vPosition = (float3)(m_pParent->getAttachmentPos(m_iParentAttachment) + m_vOffsetPos);
-			m_vOrientation = m_pParent->getAttachmentRot(m_iParentAttachment) * m_vOffsetOrient;
-		}
-		else
-		{
-			m_vPosition = (float3)(m_pParent->getPos() + m_pParent->getOrient() * m_vOffsetPos);
-			m_vOrientation = m_vOffsetOrient * m_pParent->getOrient();
-		}
-		//if(m_pPhysObj)
-		//{
-		//	m_pPhysObj->setPos(m_vPosition);
-		//	m_pPhysObj->setOrient(m_vOrientation);
-		//}
-	}
-	//else if(m_pPhysObj)
-	//{
-	//	m_vPosition = m_pPhysObj->GetPos();
-	//	m_vOrientation = m_pPhysObj->getOrient();
-	//}
-
-}
-
 void CBaseEntity::onPostLoad()
 {
-	updateOutputs();
 	updateFlags();
 }
 
@@ -726,126 +735,6 @@ int CBaseEntity::countEntByName(const char *szName)
 	return(m_pMgr->countEntityByName(szName));
 }
 
-void CBaseEntity::updateOutputs()
-{
-	proptable_t * pt = getPropTable();
-	while(pt)
-	{
-		for(int i = 0; i < pt->numFields; ++i)
-		{
-			if(pt->pData[i].type == PDF_OUTPUT)
-			{
-				output_t *pOutput = &(this->*((output_t ThisClass::*)pt->pData[i].pField));
-
-				for(int j = 0, jl = pOutput->iOutCount; j < jl; ++j)
-				{
-					named_output_t *pOut = &pOutput->pOutputs[j];
-					mem_delete_a(pOut->pOutputs);
-
-					pOut->iOutCount = countEntByName(pOut->szTargetName);
-					if(!pOut->iOutCount)
-					{
-						printf(COLOR_CYAN "Broken output target '%s' source '%s'.'%s'\n" COLOR_RESET, pOut->szTargetName, getClassName(), m_szName);
-						continue;
-					}
-					pOut->pOutputs = new input_t[pOut->iOutCount];
-					memset(pOut->pOutputs, 0, sizeof(input_t) * pOut->iOutCount);
-
-
-					CBaseEntity * pEnt = NULL;
-					int c = 0;
-					while((pEnt = getEntByName(pOut->szTargetName, pEnt)))
-					{
-						propdata_t * pField = pEnt->getField(pOut->szTargetInput);
-						if(!pField || !(pField->flags & PDFF_INPUT))
-						{
-							printf(COLOR_CYAN "Class '%s' has no input '%s', obj '%s'\n" COLOR_RESET, pEnt->getClassName(), pOut->szTargetInput, pOut->szTargetName);
-							--pOut->iOutCount;
-							continue;
-						}
-
-						pOut->pOutputs[c].fnInput = pField->fnInput;
-						pOut->pOutputs[c].pTarget = pEnt;
-						pOut->pOutputs[c].data.type = pField->type;
-						if((pOut->pOutputs[c].useOverrideData = pOut->szTargetData != NULL))
-						{
-							float3_t f3;
-							float4_t f4;
-							SMQuaternion q;
-							int d;
-							float f;
-							const char * value = pOut->szTargetData;
-							bool bParsed = false;
-							switch(pField->type)
-							{
-							case PDF_NONE:
-								bParsed = true;
-								break;
-							case PDF_INT:
-								if(1 == sscanf(value, "%d", &d))
-								{
-									pOut->pOutputs[c].data.parameter.i = d;
-									bParsed = true;
-								}
-								break;
-							case PDF_FLOAT:
-								if(1 == sscanf(value, "%f", &f))
-								{
-									pOut->pOutputs[c].data.parameter.f = f;
-									bParsed = true;
-								}
-								break;
-							case PDF_VECTOR:
-								if(3 == sscanf(value, "%f %f %f", &f3.x, &f3.y, &f3.z))
-								{
-									pOut->pOutputs[c].data.v3Parameter = f3;
-									bParsed = true;
-								}
-								break;
-							case PDF_VECTOR4:
-								{
-									int iPrm = sscanf(value, "%f %f %f %f", &f4.x, &f4.y, &f4.z, &f4.w);
-									if(iPrm > 2)
-									{
-										if(iPrm == 3)
-										{
-											f4.w = 1.0f;
-										}
-										pOut->pOutputs[c].data.v4Parameter = f4;
-										bParsed = true;
-									}
-								}
-								break;
-							case PDF_BOOL:
-								if(1 == sscanf(value, "%d", &d))
-								{
-									pOut->pOutputs[c].data.parameter.b = d != 0;
-									bParsed = true;
-								}
-								break;
-							case PDF_STRING:
-								_setStrVal(&pOut->pOutputs[c].data.parameter.str, value);
-								bParsed = true;
-								break;
-							}
-
-							if(!bParsed)
-							{
-								printf(COLOR_CYAN "Cannot parse input parameter '%s', class '%s', input '%s', obj '%s'\n" COLOR_RESET, value, pEnt->getClassName(), pOut->szTargetInput, pOut->szTargetName);
-								--pOut->iOutCount;
-								continue;
-							}
-						}
-
-						++c;
-					}
-				}
-			}
-		}
-		pt = pt->pBaseProptable;
-	}
-}
-
 void CBaseEntity::dispatchDamage(CTakeDamageInfo &takeDamageInfo)
 {
 	float fHealth = takeDamageInfo.m_fDamage * 0.1f;
@@ -1000,3 +889,37 @@ void CBaseEntity::renderEditor(bool is3D)
 {
 
 }
+
+void CBaseEntity::registerPointer(IEntityPointer *pPtr)
+{
+	ScopedSpinLock lock(m_slPointers);
+	m_aPointers.push_back(pPtr);
+}
+
+void CBaseEntity::unregisterPointer(IEntityPointer *pPtr)
+{
+	ScopedSpinLock lock(m_slPointers);
+	int idx = m_aPointers.indexOf(pPtr);
+	if(idx >= 0)
+	{
+		m_aPointers.erase(idx);
+	}
+}
+
+void CBaseEntity::notifyPointers()
+{
+	ScopedSpinLock lock(m_slPointers);
+	for(UINT i = 0, l = m_aPointers.size(); i < l; ++i)
+	{
+		m_aPointers[i]->onTargetRemoved(this);
+	}
+}
+
+void CBaseEntity::setName(const char *szName)
+{
+	if(fstrcmp(m_szName, szName))
+	{
+		m_pMgr->onEntityNameChanged(this, m_szName, szName);
+		_setStrVal(&m_szName, szName);
+	}
+}
diff --git a/source/game/BaseEntity.h b/source/game/BaseEntity.h
index 3d5bd758066f751ec9c9604d4d8b7ca8867314ff..68a3595589f16edabde539a34e456e41374336f0 100644
--- a/source/game/BaseEntity.h
+++ b/source/game/BaseEntity.h
@@ -46,9 +46,12 @@ class SXGAME_EXPORT CBaseEntity
 
 	friend class CEntityManager;
 
+	template<typename T>
+	friend class CEntityPointer;
+	friend class CEntityList;
 public:
 	//! Конструктор
-	CBaseEntity(CEntityManager * pMgr);
+	CBaseEntity();
 	virtual ~CBaseEntity();
 
 	//! Возвращает имя движкового класса объекта
@@ -58,22 +61,19 @@ public:
 	const char* getName();
 	
 	//! Возвращает баунд объекта
-	virtual void getMinMax(float3 * min, float3 * max);
+	virtual void getMinMax(float3 *min, float3 *max);
 	
 	//! Возвращает баунд сферу объекта
-	virtual void getSphere(float3 * center, float * radius);
+	virtual void getSphere(float3 *center, float *radius);
 
 	//! Устанавливает мировую позицию объекта
-	virtual void setPos(const float3 & pos);
+	virtual void setPos(const float3 &pos);
 	//! Устанавливает относительное смещение объекта
-	virtual void setOffsetPos(const float3 & pos);
+	virtual void setOffsetPos(const float3 &pos);
 	//! Получает мировую позицию объекта
 	float3 getPos();
 	float3 getOffsetPos();
 
-	//! Получает ID объекта в системе
-	ID getId();
-
 	//! Получает флаги объекта
 	UINT getFlags();
 	//! Устанавливает флаги объекта
@@ -83,12 +83,15 @@ public:
 	SMMATRIX getWorldTM();
 
 	//! Устанавливает вращение объекта
-	virtual void setOrient(const SMQuaternion & q);
+	virtual void setOrient(const SMQuaternion &q);
 	//! Устанавливает относительное вращение объекта
-	virtual void setOffsetOrient(const SMQuaternion & q);
+	virtual void setOffsetOrient(const SMQuaternion &q);
 	//! Возвращает вращение объекта
 	SMQuaternion getOrient();
 
+	void setXform(const float3 &vPos, const SMQuaternion &q);
+	void setOffsetXform(const float3 &vPos, const SMQuaternion &q);
+
 	//! Устанавливает свойство объекта
 	virtual bool setKV(const char *name, const char *value);
 	//! Получает свойство объекта
@@ -114,13 +117,13 @@ public:
 
 	virtual void onDeath(CBaseEntity *pAttacker, CBaseEntity *pInflictor);
 
-	void broadcastMessage(const char * szInputName, inputdata_t inputData, float fRadius);
-	void broadcastMessage(const char * szInputName, float fArg, float fRadius);
-	void broadcastMessage(const char * szInputName, int iArg, float fRadius);
-	void broadcastMessage(const char * szInputName, bool bArg, float fRadius);
-	void broadcastMessage(const char * szInputName, const char *szArg, float fRadius);
-	void broadcastMessage(const char * szInputName, const float3_t &f3Arg, float fRadius);
-	void broadcastMessage(const char * szInputName, float fRadius);
+	void broadcastMessage(const char *szInputName, inputdata_t inputData, float fRadius);
+	void broadcastMessage(const char *szInputName, float fArg, float fRadius);
+	void broadcastMessage(const char *szInputName, int iArg, float fRadius);
+	void broadcastMessage(const char *szInputName, bool bArg, float fRadius);
+	void broadcastMessage(const char *szInputName, const char *szArg, float fRadius);
+	void broadcastMessage(const char *szInputName, const float3_t &f3Arg, float fRadius);
+	void broadcastMessage(const char *szInputName, float fRadius);
 
 	virtual void onUse(CBaseEntity *pUser);
 
@@ -142,60 +145,87 @@ public:
 	virtual void renderEditor(bool is3D);
 
 
-	CBaseEntity *getEntByName(const char *szName, CBaseEntity *pStartFrom);
+	CBaseEntity* getEntByName(const char *szName, CBaseEntity *pStartFrom);
 	int countEntByName(const char *szName);
 
+	const XGUID* getGUID()
+	{
+		return(m_pGUID);
+	}
+
+	void setSeparateMovement(bool set)
+	{
+		m_isSeparateMovement = set;
+	}
+
+	void setName(const char *szName);
+
 private:
-	void setClassName(const char * name);
+	void setClassName(const char *name);
 	void setDefaults();
 
-	const char * m_szClassName;
+	void setGUID(const XGUID *pGUID)
+	{
+		m_pGUID = pGUID;
+	}
+	void setWorld(CEntityManager *pWorld)
+	{
+		m_pMgr = pWorld;
+	}
 
+	const char *m_szClassName = NULL;
+	const XGUID *m_pGUID = NULL;
 
-protected:
-	virtual void _cleanup();
-	virtual void _initEditorBoxes();
-	virtual void _releaseEditorBoxes();
+	SpinLock m_slPointers;
+	Array<IEntityPointer*> m_aPointers;
+	void registerPointer(IEntityPointer *pPtr);
+	void unregisterPointer(IEntityPointer *pPtr);
+	void notifyPointers();
+
+	void onParentSet(CBaseEntity *pNewParent);
+	void onParentUnset(CBaseEntity *pOldParent);
+
+	Array<CBaseEntity*> m_aChildren;
+	SpinLock m_slChildren;
+	void addChild(CBaseEntity *pEnt);
+	void removeChild(CBaseEntity *pEnt);
+
+	bool m_isSeparateMovement = false;
+	bool m_isInOnParentMoved = false;
+	void onParentMoved(bool bAdjustOffsets = false);
 
-	CEntityManager * m_pMgr;
 
 	//! Позиция объекта
 	float3_t m_vPosition;
-	
-	/*! Скорость
-	\note вероятно, не используется
-	*/
-	float3_t m_vSpeed;
-	
 	//! вращение
-	SMQuaternion m_vOrientation;
-	//float3_t m_vDiscreteLinearVelocity;
-	//float3_t m_vOldPosition;
+	SMQuaternion m_qOrientation;
 
 	//! Позиция смещения (для иерархической структуры)
 	float3_t m_vOffsetPos;
 	//! Вращение смещения (для иерархической структуры)
-	SMQuaternion m_vOffsetOrient;
+	SMQuaternion m_qOffsetOrient;
 
-	//! Идентификатор в системе
-	ID m_iId;
+	//! Имя объекта
+	const char *m_szName = NULL;
 
 	//! Флаги
-	UINT m_iFlags;
-
-	//! Имя объекта
-	const char * m_szName;
+	UINT m_iFlags = 0;
+protected:
+	virtual void _cleanup();
+	virtual void _initEditorBoxes();
+	virtual void _releaseEditorBoxes();
 
+	CEntityManager *m_pMgr = NULL;
+	
 	//! Родитель
-	CBaseEntity * m_pParent;
+	// CBaseEntity *m_pParent = NULL;
+	CEntityPointer<CBaseEntity> m_pParent;
 	//! Индекс кости родителя
-	int m_iParentAttachment;
+	int m_iParentAttachment = -1;
 
 	//! Владелец
-	CBaseEntity * m_pOwner;
+	CEntityPointer<CBaseEntity> m_pOwner;
 
-	//! Вызывается на стадии синхронизации
-	virtual void onSync();
 	//! Вызывается при создании после установки всех свойств
 	virtual void onPostLoad();
 
@@ -204,29 +234,17 @@ protected:
 	//! Получает вращение для кости
 	virtual SMQuaternion getAttachmentRot(int id);
 
-//	/*! Устанавливает значение строкового свойства
-//	\note только для внутреннего использования
-//	*/
-//	void _setStrVal(const char ** to, const char * value);
-
-	/*! Обновляет выходы
-	\note только для внутреннего использования
-	*/
-	void updateOutputs();
-	
 	//! здоровье [0,+inf]
-	float m_fHealth;
+	float m_fHealth = 100.0f;
 
 	void takeHealth(float fVal, CBaseEntity *pAttacker, CBaseEntity *pInflictor=NULL);
 
-	bool m_bSynced;
-
 
 	//! Для редактора
 	//@{
 	float3_t m_vEditorBoxSize = float3_t(0.16f, 0.16f, 0.16f);
-	btCollisionShape * m_pEditorCollideShape = NULL;
-	btRigidBody * m_pEditorRigidBody = NULL;
+	btCollisionShape *m_pEditorCollideShape = NULL;
+	btRigidBody *m_pEditorRigidBody = NULL;
 	//@}
 
 	IXLightSystem *m_pLightSystem = NULL;
diff --git a/source/game/BaseHandle.cpp b/source/game/BaseHandle.cpp
index ab4abe1a7b9c3e13ff6036e83f9c809c5351cfa4..c97d9cc3e42b56dd1bcb719199a2ece555651f71 100644
--- a/source/game/BaseHandle.cpp
+++ b/source/game/BaseHandle.cpp
@@ -16,8 +16,7 @@ END_PROPTABLE()
 
 REGISTER_ENTITY_NOLISTING(CBaseHandle, base_handle);
 
-CBaseHandle::CBaseHandle(CEntityManager * pMgr):
-	BaseClass(pMgr)
+CBaseHandle::CBaseHandle()
 {
 	m_addonType = WPN_ADDON_HANDLE;
 }
\ No newline at end of file
diff --git a/source/game/BaseItem.cpp b/source/game/BaseItem.cpp
index c3837d54967f241caa4134ba00bf350979f60d94..752f4753be1e8514f4b7212b017ef4b77e36a5d5 100644
--- a/source/game/BaseItem.cpp
+++ b/source/game/BaseItem.cpp
@@ -35,17 +35,13 @@ END_PROPTABLE()
 
 REGISTER_ENTITY_NOLISTING(CBaseItem, base_item);
 
-CBaseItem::CBaseItem(CEntityManager * pMgr):
-	BaseClass(pMgr),
-	m_bInvStackable(true),
-	m_iInvStackCurSize(0),
-	m_iInvStackMaxSize(1),
-	m_iInvWeight(0.0f),
-	m_bPickable(true)
+void CBaseItem::onPostLoad()
 {
-	if(m_bPickable)
+	BaseClass::onPostLoad();
+
+	if(m_bPickable && !m_pTriggerUse)
 	{
-		m_pTriggerUse = (CTriggerItemUse*)CREATE_ENTITY("trigger_itemuse", m_pMgr);
+		m_pTriggerUse = (CTriggerItemUse *)CREATE_ENTITY("trigger_itemuse", m_pMgr);
 		m_pTriggerUse->setItem(this);
 		m_pTriggerUse->setModel("meshes/dev/item_trigger.dse");
 		m_pTriggerUse->setPos(getPos());
@@ -205,25 +201,19 @@ void CBaseItem::onModelChanged()
 	}
 }
 
-void CBaseItem::onSync()
+void CBaseItem::setPos(const float3 &pos)
 {
-	BaseClass::onSync();
-	
-	if(m_pViewModel)
-	{
-		m_pViewModel->setPosition(getPos());
-		m_pViewModel->setOrientation(getOrient());
-	}
+	BaseClass::setPos(pos);
+
+	SAFE_CALL(m_pViewModel, setPosition, pos);
+	SAFE_CALL(m_pTriggerUse, setPos, pos);
 }
 
-void CBaseItem::setPos(const float3 &pos)
+void CBaseItem::setOrient(const SMQuaternion &q)
 {
-	BaseClass::setPos(pos);
+	BaseClass::setOrient(q);
 
-	if(m_pTriggerUse)
-	{
-		m_pTriggerUse->setPos(getPos());
-	}
+	SAFE_CALL(m_pViewModel, setOrientation, q);
 }
 
 void CBaseItem::onIsPickableChanged(bool isPickable)
diff --git a/source/game/BaseItem.h b/source/game/BaseItem.h
index 087524d58783e346ef53326327599ac36480cd59..e3ae75ebaa8d31cc907d616f041ae2d412b5967f 100644
--- a/source/game/BaseItem.h
+++ b/source/game/BaseItem.h
@@ -35,7 +35,7 @@ class CBaseItem: public CBaseAnimating
 	DECLARE_PROPTABLE();
 	friend class CCharacterInventory;
 public:
-	DECLARE_CONSTRUCTOR();
+	DECLARE_TRIVIAL_CONSTRUCTOR();
 	~CBaseItem();
 
 	//! Масса объекта
@@ -46,22 +46,24 @@ public:
 
 	void setHandsResource(IXResourceModelAnimated *pResource);
 
-	void setPos(const float3 &pos);
+	void setPos(const float3 &pos) override;
+	void setOrient(const SMQuaternion &q) override;
 
 protected:
 	virtual void onModeChanged(INVENTORY_ITEM_MODE oldMode, INVENTORY_ITEM_MODE newMode);
 	void onSetViewModel(const char *mdl);
 	void onModelChanged();
-	void onSync() override;
+
+	void onPostLoad() override;
 
 	void setScale(float fScale) override;
 	
 	const char *m_szInvName; //!< Имя, отображаемое в инвентаре
-	bool m_bInvStackable; //!< Можно ли хранить несколько итемов в одной ячейке
-	int m_iInvStackCurSize; //!< Количество итемов в стеке
-	int m_iInvStackMaxSize; //!< Максимальное количество итемов в стеке
-	float m_iInvWeight; //!< Масса объекта
-	bool m_bPickable; //!< Можно ли поднять объект
+	bool m_bInvStackable = true; //!< Можно ли хранить несколько итемов в одной ячейке
+	int m_iInvStackCurSize = 0; //!< Количество итемов в стеке
+	int m_iInvStackMaxSize = 1; //!< Максимальное количество итемов в стеке
+	float m_iInvWeight = 0.0f; //!< Масса объекта
+	bool m_bPickable = true; //!< Можно ли поднять объект
 
 	output_t m_onPickUp;
 	output_t m_onDrop;
diff --git a/source/game/BaseLight.cpp b/source/game/BaseLight.cpp
index dd90a186a968a2691dd7286eb573c9f9cae79a6a..4940347deaa2e964e3ba13d32ee9a2496cba1372 100644
--- a/source/game/BaseLight.cpp
+++ b/source/game/BaseLight.cpp
@@ -12,18 +12,16 @@ See the license in LICENSE
 
 BEGIN_PROPTABLE(CBaseLight)
 	//! Цвет
-	DEFINE_FIELD_VECTOR4(m_vColor, 0, "color", "Color", EDITOR_TEXTFIELD)
+	DEFINE_FIELD_VECTOR4FN(m_vColor, 0, "color", "Color", setColor, EDITOR_TEXTFIELD)
 	//! Дальность
 	DEFINE_FIELD_FLOAT(m_fDist, 0, "dist", "Distance", EDITOR_TEXTFIELD)
 	//! Дальность дальняя
 	//DEFINE_FIELD_FLOAT(m_fShadowDist, 0, "light_far", "Shadow far plane", EDITOR_TEXTFIELD)
 	//! Интенсивность теней
-	DEFINE_FIELD_FLOAT(m_fShadowIntensity, 0, "shadow_intensity", "Shadow intensity", EDITOR_TEXTFIELD)
-	//! Связанный свет (повторяет его состояние включения)
-	DEFINE_FIELD_ENTITYFN(m_pLinkedTo, 0, "linked_to", "Linked light to", setLinkedTo, EDITOR_TEXTFIELD)
+	DEFINE_FIELD_FLOATFN(m_fShadowIntensity, 0, "shadow_intensity", "Shadow intensity", setShadowIntensity, EDITOR_TEXTFIELD)
 
 	//! Тип тени
-	DEFINE_FIELD_INT(m_iShadowType, 0, "type_shadow", "Type shadow", EDITOR_COMBOBOX)
+	DEFINE_FIELD_INTFN(m_iShadowType, 0, "type_shadow", "Type shadow", setShadowType, EDITOR_COMBOBOX)
 		//COMBO_OPTION("None", "-1")   //!< Нет
 		COMBO_OPTION("Static", "0")  //!< Статическая тень
 		COMBO_OPTION("Dynamic", "1") //!< Динамическая тень
@@ -45,21 +43,9 @@ END_PROPTABLE()
 
 REGISTER_ENTITY_NOLISTING(CBaseLight, base_light);
 
-CBaseLight::CBaseLight(CEntityManager * pMgr):
-BaseClass(pMgr)
-{
-	m_vColor = float4(1.0f, 1.0f, 1.0f, 1.0f);
-	m_fDist = 10;
-	m_iShadowType = 1;
-	m_fShadowIntensity = 1.0f;
-}
-
 CBaseLight::~CBaseLight()
 {
-	if(m_pLinkedTo)
-	{
-		((CBaseLight*)m_pLinkedTo)->removeLinkedLight(this);
-	}
+	mem_release(m_pLight);
 }
 
 void CBaseLight::toggleEnable()
@@ -67,32 +53,14 @@ void CBaseLight::toggleEnable()
 	setEnable(!m_isEnable);
 }
 
-void CBaseLight::onSync()
-{
-	BaseClass::onSync();
-
-	if(m_pLight)
-	{
-		m_pLight->setEnabled(m_isEnable);
-		m_pLight->setPosition(m_vPosition);
-		m_pLight->setColor(float3(m_vColor) * m_vColor.w);
-		m_pLight->setShadowIntencity(m_fShadowIntensity);
-		m_pLight->setShadowDynamic(m_iShadowType != 0);
-	}
-}
-
-
 void CBaseLight::turnOn(inputdata_t * pInputdata)
 {
 	if(!m_isEnable)
 	{
 		m_isEnable = true;
+		SAFE_CALL(m_pLight, setEnabled, m_isEnable);
 		FIRE_OUTPUT(m_onTurnOn, pInputdata->pInflictor);
 	}
-	for(int i = 0, l = m_vpLinkedLights.size(); i < l; ++i)
-	{
-		m_vpLinkedLights[i]->turnOn(pInputdata);
-	}
 }
 
 void CBaseLight::turnOff(inputdata_t * pInputdata)
@@ -100,12 +68,9 @@ void CBaseLight::turnOff(inputdata_t * pInputdata)
 	if(m_isEnable)
 	{
 		m_isEnable = false;
+		SAFE_CALL(m_pLight, setEnabled, m_isEnable);
 		FIRE_OUTPUT(m_onTurnOff, pInputdata->pInflictor);
 	}
-	for(int i = 0, l = m_vpLinkedLights.size(); i < l; ++i)
-	{
-		m_vpLinkedLights[i]->turnOff(pInputdata);
-	}
 }
 
 void CBaseLight::setEnable(bool isEnable)
@@ -113,18 +78,15 @@ void CBaseLight::setEnable(bool isEnable)
 	if(!m_isEnable && isEnable)
 	{
 		m_isEnable = isEnable;
+		SAFE_CALL(m_pLight, setEnabled, m_isEnable);
 		FIRE_OUTPUT(m_onTurnOn, this);
 	}
 	else if(m_isEnable && !isEnable)
 	{
 		m_isEnable = isEnable;
+		SAFE_CALL(m_pLight, setEnabled, m_isEnable);
 		FIRE_OUTPUT(m_onTurnOff, this);
 	}
-
-	for(int i = 0, l = m_vpLinkedLights.size(); i < l; ++i)
-	{
-		m_vpLinkedLights[i]->setEnable(isEnable);
-	}
 }
 
 void CBaseLight::updateFlags()
@@ -132,19 +94,7 @@ void CBaseLight::updateFlags()
 	BaseClass::updateFlags();
 
 	m_isEnable = !(getFlags() & LIGHT_INITIALLY_DARK);
-
-	for(int i = 0, l = m_vpLinkedLights.size(); i < l; ++i)
-	{
-		if(m_isEnable)
-		{
-			m_vpLinkedLights[i]->setFlags(m_vpLinkedLights[i]->getFlags() & ~LIGHT_INITIALLY_DARK);
-		}
-		else
-		{
-			m_vpLinkedLights[i]->setFlags(m_vpLinkedLights[i]->getFlags() | LIGHT_INITIALLY_DARK);
-		}
-		m_vpLinkedLights[i]->updateFlags();
-	}
+	SAFE_CALL(m_pLight, setEnabled, m_isEnable);
 }
 
 bool CBaseLight::getMainColor(float3_t *pOut)
@@ -156,56 +106,9 @@ bool CBaseLight::getMainColor(float3_t *pOut)
 	return(m_isEnable);
 }
 
-void CBaseLight::setLinkedTo(CBaseEntity *pEnt)
+void CBaseLight::setPos(const float3 &pos)
 {
-	if(m_pLinkedTo)
-	{
-		((CBaseLight*)m_pLinkedTo)->removeLinkedLight(this);
-	}
-	m_pLinkedTo = pEnt;
-	if(m_pLinkedTo)
-	{
-		((CBaseLight*)m_pLinkedTo)->addLinkedLight(this);
-		if((((CBaseLight*)m_pLinkedTo)->getFlags() & LIGHT_INITIALLY_DARK))
-		{
-			setFlags(getFlags() | LIGHT_INITIALLY_DARK);
-		}
-		else
-		{
-			setFlags(getFlags() & ~LIGHT_INITIALLY_DARK);
-		}
-		updateFlags();
-	}
-}
+	BaseClass::setPos(pos);
 
-void CBaseLight::addLinkedLight(CBaseLight *pEnt)
-{
-	if(!pEnt)
-	{
-		return;
-	}
-	for(int i = 0, l = m_vpLinkedLights.size(); i < l; ++i)
-	{
-		if(m_vpLinkedLights[i] == pEnt)
-		{
-			return;
-		}
-	}
-	m_vpLinkedLights.push_back(pEnt);
-}
-
-void CBaseLight::removeLinkedLight(CBaseLight *pEnt)
-{
-	if(!pEnt)
-	{
-		return;
-	}
-	for(int i = 0, l = m_vpLinkedLights.size(); i < l; ++i)
-	{
-		if(m_vpLinkedLights[i] == pEnt)
-		{
-			m_vpLinkedLights.erase(i);
-			return;
-		}
-	}
+	SAFE_CALL(m_pLight, setPosition, pos);
 }
diff --git a/source/game/BaseLight.h b/source/game/BaseLight.h
index e0bb6ae35241bd14181fc3d653ac308d51c3ba27..c29f632ec85511cbe339256fa930f95bd07ca111 100644
--- a/source/game/BaseLight.h
+++ b/source/game/BaseLight.h
@@ -24,7 +24,7 @@ class CBaseLight: public CPointEntity
 	DECLARE_CLASS(CBaseLight, CPointEntity);
 	DECLARE_PROPTABLE();
 public:
-	DECLARE_CONSTRUCTOR();
+	DECLARE_TRIVIAL_CONSTRUCTOR();
 	~CBaseLight();
 
 	void toggleEnable();
@@ -32,6 +32,7 @@ public:
 	void setColor(const float4 &vColor)
 	{
 		m_vColor = vColor;
+		SAFE_CALL(m_pLight, setColor, float3(m_vColor) * m_vColor.w);
 	}
 	const float4_t& getColor() const
 	{
@@ -59,6 +60,7 @@ public:
 	void setShadowIntensity(float fShadowIntensity)
 	{
 		m_fShadowIntensity = fShadowIntensity;
+		SAFE_CALL(m_pLight, setShadowIntencity, fShadowIntensity);
 	}
 	float getShadowIntensity() const
 	{
@@ -68,6 +70,7 @@ public:
 	void setShadowType(int iShadowType)
 	{
 		m_iShadowType = iShadowType;
+		SAFE_CALL(m_pLight, setShadowDynamic, iShadowType != 0);
 	}
 	int getShadowType() const
 	{
@@ -84,26 +87,18 @@ public:
 
 	void updateFlags();
 
+	void setPos(const float3 &pos) override;
+
 protected:
 	IXLight *m_pLight = NULL;
 
-	float4_t m_vColor;
-	float m_fDist;
+	float4_t m_vColor = float4(1.0f, 1.0f, 1.0f, 1.0f);
+	float m_fDist = 10.0f;
 	//float m_fShadowDist;
-	int m_iShadowType;
-	bool m_isEnable;
-	float m_fShadowIntensity;
-	CBaseEntity *m_pLinkedTo = NULL;
-
-	Array<CBaseLight*> m_vpLinkedLights;
-
-	void setLinkedTo(CBaseEntity *pEnt);
-
-	void onSync();
-
-	void addLinkedLight(CBaseLight *pEnt);
-	void removeLinkedLight(CBaseLight *pEnt);
-
+	int m_iShadowType = 1;
+	bool m_isEnable = true;
+	float m_fShadowIntensity = 1.0f;
+	
 	void turnOn(inputdata_t * pInputdata);
 	void turnOff(inputdata_t * pInputdata);
 
diff --git a/source/game/BaseMag.cpp b/source/game/BaseMag.cpp
index a783175313b8e9f9806ca14921c2c8cf1eb78cac..ad2518574bd7226dbdde191f0a6b2a730cde6f2a 100644
--- a/source/game/BaseMag.cpp
+++ b/source/game/BaseMag.cpp
@@ -19,10 +19,7 @@ END_PROPTABLE()
 
 REGISTER_ENTITY_NOLISTING(CBaseMag, base_mag);
 
-CBaseMag::CBaseMag(CEntityManager * pMgr):
-	BaseClass(pMgr),
-	m_iCapacity(0),
-	m_iCurrentLoad(0)
+CBaseMag::CBaseMag()
 {
 	m_addonType = WPN_ADDON_MAG;
 }
diff --git a/source/game/BaseMag.h b/source/game/BaseMag.h
index aae2f46e12b3deac565ddf9620dc0cb8f6f41dc9..10fb7e90d248cbb8527315f847af4d61d476e7d8 100644
--- a/source/game/BaseMag.h
+++ b/source/game/BaseMag.h
@@ -28,8 +28,8 @@ public:
 	int getCapacity();
 	void load(int count);
 protected:
-	int m_iCapacity;
-	int m_iCurrentLoad;
+	int m_iCapacity = 0;
+	int m_iCurrentLoad = 0;
 };
 
 #endif
diff --git a/source/game/BaseScope.cpp b/source/game/BaseScope.cpp
index 05539b6b22da50ea9022562db0583022f8436cd5..9d89197ee89edbdfeb452ae06d871efb7a3f411a 100644
--- a/source/game/BaseScope.cpp
+++ b/source/game/BaseScope.cpp
@@ -16,8 +16,7 @@ END_PROPTABLE()
 
 REGISTER_ENTITY_NOLISTING(CBaseScope, base_scope);
 
-CBaseScope::CBaseScope(CEntityManager * pMgr):
-	BaseClass(pMgr)
+CBaseScope::CBaseScope()
 {
 	m_addonType = WPN_ADDON_SCOPE;
-}
\ No newline at end of file
+}
diff --git a/source/game/BaseSilencer.cpp b/source/game/BaseSilencer.cpp
index 946fb65908ae930c425ced7a31ca8a4f486fc4e3..ee43f1c4da7ae5de1cb48a26867380b3011fdefa 100644
--- a/source/game/BaseSilencer.cpp
+++ b/source/game/BaseSilencer.cpp
@@ -16,8 +16,7 @@ END_PROPTABLE()
 
 REGISTER_ENTITY_NOLISTING(CBaseSilencer, base_silencer);
 
-CBaseSilencer::CBaseSilencer(CEntityManager * pMgr):
-	BaseClass(pMgr)
+CBaseSilencer::CBaseSilencer()
 {
 	m_addonType = WPN_ADDON_SILENCER;
-}
\ No newline at end of file
+}
diff --git a/source/game/BaseTool.cpp b/source/game/BaseTool.cpp
index 9bfb41ebf5f257d60b15737d3f6d4403c3e49c29..877cfd464516e5dedeb4334723e460b0a0ff2a45 100644
--- a/source/game/BaseTool.cpp
+++ b/source/game/BaseTool.cpp
@@ -85,24 +85,9 @@ protected:
 	btCollisionObject* m_me;
 };
 
-CBaseTool::CBaseTool(CEntityManager * pMgr):
-	BaseClass(pMgr),
-	m_bInPrimaryAction(false),
-	m_bInSecondaryAction(false),
-	m_bWorldModel(false),
-	m_bCanUse(true),
-	m_fZoomTime(0.0f),
-	m_fReloadTime(0.0f),
-	m_iZoomable(1),
-	m_iMuzzleFlash(-1),
-	m_iMuzzleFlash2(-1),
-	m_fMaxDistance(1000.0f),
-	m_bIsWeapon(false),
-	m_pLoadedAmmo(NULL)
+CBaseTool::CBaseTool()
 {
 	m_bInvStackable = false;
-
-	m_iIvalUpdate = SET_INTERVAL(_update, 0);
 }
 
 CBaseTool::~CBaseTool()
@@ -117,6 +102,8 @@ void CBaseTool::onPostLoad()
 {
 	BaseClass::onPostLoad();
 
+	m_iIvalUpdate = SET_INTERVAL(_update, 0);
+
 	IXSoundSystem *pSound = (IXSoundSystem*)(Core_GetIXCore()->getPluginManager()->getInterface(IXSOUNDSYSTEM_GUID));
 	if(pSound)
 	{
@@ -192,7 +179,7 @@ void CBaseTool::secondaryAction(BOOL st)
 	m_bInSecondaryAction = st != FALSE;
 	if(m_iZoomable)
 	{
-		((CPlayer*)m_pOwner)->getCrosshair()->enable(!st);
+		((CPlayer*)m_pOwner.getEntity())->getCrosshair()->enable(!st);
 	}
 }
 
@@ -240,25 +227,18 @@ void CBaseTool::dbgMove(int dir, float dy)
 		printf(COLOR_GREEN "slot_offset = " COLOR_LGREEN "%f %f %f\n"
 			COLOR_GREEN "slot_rotation = " COLOR_LGREEN "%f %f %f %f\n"
 			COLOR_GREEN "center_length = " COLOR_LGREEN "%f\n" COLOR_RESET
-			, m_vOffsetPos.x, m_vOffsetPos.y, m_vOffsetPos.z
+			, m_vSlotPosResult.x, m_vSlotPosResult.y, m_vSlotPosResult.z
 			, m_qSlotRotResult.x, m_qSlotRotResult.y, m_qSlotRotResult.z, m_qSlotRotResult.w
 			, m_fCenterLength);
 		break;
 	}
+
+	updateTransform();
 }
 
+#if 0
 void CBaseTool::onSync()
 {
-	if(m_pOwner)
-	{
-		float3_t ang = ((CPlayer*)m_pOwner)->getWeaponDeltaAngles();
-		m_vOffsetOrient = m_qSlotRotResult * SMQuaternion(ang.x, 'x') * SMQuaternion(ang.y, 'y') * SMQuaternion(ang.z, 'z');
-	}
-	else
-	{
-		m_vOffsetOrient = m_qSlotRotResult;
-	}
-	m_vOffsetPos = m_vSlotPosResult;
 	BaseClass::onSync();
 	if(m_pModel && m_pModel->asAnimatedModel())
 	{
@@ -269,6 +249,18 @@ void CBaseTool::onSync()
 		SPE_EffectSetRotQ(m_iMuzzleFlash, m_vOrientation);
 	}
 }
+#endif
+
+void CBaseTool::setShakeRotation(const SMQuaternion &q)
+{
+	m_qShakeRotation = q;
+	updateTransform();
+}
+
+void CBaseTool::updateTransform()
+{
+	setOffsetXform(m_vSlotPosResult, m_qSlotRotResult * m_qShakeRotation);
+}
 
 void CBaseTool::_update(float dt)
 {
@@ -278,7 +270,7 @@ void CBaseTool::_update(float dt)
 		float3 start = m_pParent->getPos();
 		float3 dir = m_pParent->getOrient() * float3(0.0f, 0.0f, 1.0f);
 		float3 end = start + dir * m_fCenterLength;
-		btKinematicClosestNotMeRayResultCallback cb(((CBaseCharacter*)m_pOwner)->getBtCollisionObject(), F3_BTVEC(start), F3_BTVEC(end));
+		btKinematicClosestNotMeRayResultCallback cb(((CBaseCharacter*)m_pOwner.getEntity())->getBtCollisionObject(), F3_BTVEC(start), F3_BTVEC(end));
 		SPhysics_GetDynWorld()->rayTest(F3_BTVEC(start), F3_BTVEC(end), cb);
 
 		m_isClose = cb.hasHit();
@@ -357,8 +349,9 @@ void CBaseTool::_rezoom()
 	m_qSlotRotResult = SMquaternionSlerp(SMquaternionSlerp(m_qSlotRot, m_qSlotRotClose, m_fCloseProgress), m_qSlotRotAim, m_fZoomProgress);
 	if(m_pOwner && m_pOwner->getClassName() && !fstrcmp(m_pOwner->getClassName(), "player"))
 	{
-		((CPlayer*)m_pOwner)->getCamera()->getCamera()->setFOV(SMToRadian(vlerp(*r_default_fov, *r_default_fov - 10.0f, m_fZoomProgress)));
+		((CPlayer*)m_pOwner.getEntity())->getCamera()->getCamera()->setFOV(SMToRadian(vlerp(*r_default_fov, *r_default_fov - 10.0f, m_fZoomProgress)));
 	}
+	updateTransform();
 }
 
 bool CBaseTool::isWeapon() const
diff --git a/source/game/BaseTool.h b/source/game/BaseTool.h
index 144911221c3678849ab0e535f7749a7cae0bbffd..bd6dcb86977261a661cae9fe0328413d74caa484 100644
--- a/source/game/BaseTool.h
+++ b/source/game/BaseTool.h
@@ -39,7 +39,7 @@ public:
 	DECLARE_CONSTRUCTOR();
 	~CBaseTool();
 
-	virtual void onPostLoad();
+	void onPostLoad() override;
 
 	virtual void primaryAction(BOOL st);
 	virtual void secondaryAction(BOOL st);
@@ -54,8 +54,6 @@ public:
 
 	void dbgMove(int dir, float delta);
 
-	void onSync();
-
 	void setParent(CBaseEntity * pEnt, int attachment = -1);
 
 	//! Этот инструмент - оружие
@@ -77,18 +75,20 @@ public:
 
 	virtual void updateHUDinfo();
 
+	void setShakeRotation(const SMQuaternion &q);
+
 protected:
 
 	bool isValidAmmo(CBaseSupply *pAmmo);
 
-	bool m_bInPrimaryAction;
-	bool m_bInSecondaryAction;
+	bool m_bInPrimaryAction = false;
+	bool m_bInSecondaryAction = false;
 
-	bool m_bWorldModel;
+	bool m_bWorldModel = false;
 
-	bool m_bCanUse;
+	bool m_bCanUse = true;
 
-	float m_fZoomTime;
+	float m_fZoomTime = 0.0f;
 
 	float m_fZoomProgress = 0.0f;
 	float m_fCloseProgress = 0.0f;
@@ -104,7 +104,9 @@ protected:
 	void _update(float dt);
 	void _rezoom();
 
-	float m_fReloadTime;
+	void updateTransform();
+
+	float m_fReloadTime = 0.0f;
 
 	float3_t m_vSlotPos;
 	float3_t m_vSlotPosAim;
@@ -115,29 +117,31 @@ protected:
 	SMQuaternion m_qSlotRotClose;
 	SMQuaternion m_qSlotRotResult;
 
-	int m_iZoomable;
+	int m_iZoomable = 1;
 
 	ID m_iIvalUpdate;
 
-	ID m_iMuzzleFlash;
-	ID m_iMuzzleFlash2;
+	ID m_iMuzzleFlash = -1;
+	ID m_iMuzzleFlash2 = -1;
 	IXSoundEmitter *m_pSoundAction1 = NULL;
 	IXSoundEmitter *m_pSoundAction2 = NULL;
 
-	const char * m_szPrimaryActionSound;
-	const char * m_szSecondaryActionSound;
+	const char *m_szPrimaryActionSound = NULL;
+	const char *m_szSecondaryActionSound = NULL;
 
-	const char * m_szPrimaryActionMuzzleflash;
-	const char * m_szSecondaryActionMuzzleflash;
+	const char *m_szPrimaryActionMuzzleflash = NULL;
+	const char *m_szSecondaryActionMuzzleflash = NULL;
 
-	const char * m_szUsableAmmos;
-	const char * m_szLoadedAmmo;
-	CBaseSupply * m_pLoadedAmmo;
+	const char *m_szUsableAmmos = NULL;
+	const char *m_szLoadedAmmo = NULL;
+	CBaseSupply *m_pLoadedAmmo = NULL;
 
-	float m_fMaxDistance;
+	float m_fMaxDistance = 1000.0f;
 
 	//! Этот инструмент - оружие
-	bool m_bIsWeapon;
+	bool m_bIsWeapon = false;
+
+	SMQuaternion m_qShakeRotation;
 };
 
 #endif
diff --git a/source/game/BaseTrigger.cpp b/source/game/BaseTrigger.cpp
index 6a4bd04f866b6719ea08b7457b6b60706080abe6..3d23d5f18d63ef089cb2eebb4583c096bd1d473e 100644
--- a/source/game/BaseTrigger.cpp
+++ b/source/game/BaseTrigger.cpp
@@ -30,19 +30,20 @@ END_PROPTABLE()
 
 REGISTER_ENTITY(CBaseTrigger, trigger);
 
-CBaseTrigger::CBaseTrigger(CEntityManager * pMgr):
-	BaseClass(pMgr),
-	m_bEnabled(true),
-	m_pGhostObject(NULL),
-	m_idUpdateInterval(-1)
+IEventChannel<XEventPhysicsStep> *CBaseTrigger::m_pTickEventChannel = NULL;
+
+CBaseTrigger::CBaseTrigger():
+	m_physicsTicker(this)
 {
-	m_idUpdateInterval = SET_INTERVAL(update, 0);
+	if(!m_pTickEventChannel)
+	{
+		m_pTickEventChannel = Core_GetIXCore()->getEventChannel<XEventPhysicsStep>(EVENT_PHYSICS_STEP_GUID);
+	}
 }
 
 CBaseTrigger::~CBaseTrigger()
 {
 	removePhysBody();
-	CLEAR_INTERVAL(m_idUpdateInterval);
 }
 
 void CBaseTrigger::onPostLoad()
@@ -61,10 +62,10 @@ void CBaseTrigger::enable()
 	if(!m_bEnabled)
 	{
 		m_bEnabled = true;
-		m_idUpdateInterval = SET_INTERVAL(update, 0);
 		if(m_pGhostObject)
 		{
 			SPhysics_GetDynWorld()->addCollisionObject(m_pGhostObject, CG_TRIGGER, CG_CHARACTER);
+			m_pTickEventChannel->addListener(&m_physicsTicker);
 		}
 	}
 }
@@ -73,9 +74,9 @@ void CBaseTrigger::disable()
 	if(m_bEnabled)
 	{
 		m_bEnabled = false;
-		CLEAR_INTERVAL(m_idUpdateInterval);
 		if(m_pGhostObject)
 		{
+			m_pTickEventChannel->removeListener(&m_physicsTicker);
 			SPhysics_GetDynWorld()->removeCollisionObject(m_pGhostObject);
 		}
 	}
@@ -92,15 +93,15 @@ void CBaseTrigger::toggle()
 	}
 }
 
-void CBaseTrigger::inEnable(inputdata_t * pInputdata)
+void CBaseTrigger::inEnable(inputdata_t *pInputdata)
 {
 	enable();
 }
-void CBaseTrigger::inDisable(inputdata_t * pInputdata)
+void CBaseTrigger::inDisable(inputdata_t *pInputdata)
 {
 	disable();
 }
-void CBaseTrigger::inToggle(inputdata_t * pInputdata)
+void CBaseTrigger::inToggle(inputdata_t *pInputdata)
 {
 	toggle();
 }
@@ -109,13 +110,17 @@ void CBaseTrigger::createPhysBody()
 {
 	if(m_pCollideShape)
 	{
+		float3 vPos = getPos();
+		SMQuaternion qRot = getOrient();
+
 		m_pGhostObject = new btPairCachingGhostObject();
-		m_pGhostObject->setWorldTransform(btTransform(Q4_BTQUAT(m_vOrientation), F3_BTVEC(m_vPosition)));
+		m_pGhostObject->setWorldTransform(btTransform(Q4_BTQUAT(qRot), F3_BTVEC(vPos)));
 		m_pGhostObject->setUserPointer(this);
 		m_pGhostObject->setCollisionShape(m_pCollideShape);
 		m_pGhostObject->setCollisionFlags(m_pGhostObject->getCollisionFlags() ^ btCollisionObject::CF_NO_CONTACT_RESPONSE);
 
 		SPhysics_GetDynWorld()->addCollisionObject(m_pGhostObject, CG_TRIGGER, CG_CHARACTER);
+		m_pTickEventChannel->addListener(&m_physicsTicker);
 	}
 }
 
@@ -124,6 +129,7 @@ void CBaseTrigger::removePhysBody()
 	if(m_pGhostObject)
 	{
 		SPhysics_GetDynWorld()->removeCollisionObject(m_pGhostObject);
+		m_pTickEventChannel->removeListener(&m_physicsTicker);
 		mem_delete(m_pGhostObject);
 	}
 }
@@ -141,16 +147,17 @@ void CBaseTrigger::onTouchEndAll(CBaseEntity *pActivator)
 	FIRE_OUTPUT(m_onTouchEndAll, pActivator);
 }
 
-void CBaseTrigger::onSync()
+void CBaseTrigger::onPhysicsStep()
 {
-	BaseClass::onSync();
-
-	static const bool *dev_show_triggers = GET_PCVAR_BOOL("dev_show_triggers");
-
-	if(m_pModel && *dev_show_triggers != m_isModelEnabled)
 	{
-		m_isModelEnabled = *dev_show_triggers;
-		m_pModel->enable(m_isModelEnabled);
+		// TODO move this!
+		static const bool *dev_show_triggers = GET_PCVAR_BOOL("dev_show_triggers");
+
+		if(m_pModel && *dev_show_triggers != m_isModelEnabled)
+		{
+			m_isModelEnabled = *dev_show_triggers;
+			m_pModel->enable(m_isModelEnabled);
+		}
 	}
 
 	if(!m_pGhostObject || !m_bEnabled)
@@ -193,17 +200,12 @@ void CBaseTrigger::onSync()
 		}
 	}
 	//m_pGhostObject->getOverlappingObject(0);
-	//printf("%d\n", m_iTouches);
+
+	update();
 }
 
-void CBaseTrigger::update(float dt)
+void CBaseTrigger::update()
 {
-	if(!m_bEnabled)
-	{
-		return;
-	}
-
-	
 	bool bFound;
 	for(int i = 0, l = m_aNewTouches.size(); i < l; ++i)
 	{
@@ -212,7 +214,8 @@ void CBaseTrigger::update(float dt)
 		{
 			if(m_aNewTouches[i] == m_aTouches[j])
 			{
-				m_aTouches[j] = NULL;
+				m_aTouches[j] = m_aTouches[jl - 1];
+				m_aTouches.erase(jl - 1);
 				bFound = true;
 				break;
 			}
@@ -222,16 +225,11 @@ void CBaseTrigger::update(float dt)
 			onTouchStart(m_aNewTouches[i]);
 		}
 	}
-	CBaseEntity * pLastTouch = NULL;
 	for(int j = 0, jl = m_aTouches.size(); j < jl; ++j)
 	{
-		if(m_aTouches[j])
-		{
-			onTouchEnd(m_aTouches[j]);
-			pLastTouch = m_aTouches[j];
-		}
+		onTouchEnd(m_aTouches[j]);
 	}
-	if(pLastTouch && !m_aNewTouches.size())
+	if(m_aTouches.size() && !m_aNewTouches.size())
 	{
 		onTouchEndAll(m_aTouches[0]);
 	}
@@ -260,3 +258,8 @@ void CBaseTrigger::setOrient(const SMQuaternion & q)
 		SPhysics_GetDynWorld()->updateSingleAabb(m_pGhostObject);
 	}
 }
+
+void CPhysicsTickEventListener::onEvent(const XEventPhysicsStep *pData)
+{
+	m_pTrigger->onPhysicsStep();
+}
diff --git a/source/game/BaseTrigger.h b/source/game/BaseTrigger.h
index 116883366eb5a6642a52d9d945b84e266c567c9a..f9dc832c137df29676a8862c92904577415399a4 100644
--- a/source/game/BaseTrigger.h
+++ b/source/game/BaseTrigger.h
@@ -19,17 +19,32 @@ See the license in LICENSE
 
 #include "BaseAnimating.h"
 
+class CBaseTrigger;
+class CPhysicsTickEventListener final: public IEventListener<XEventPhysicsStep>
+{
+public:
+	CPhysicsTickEventListener(CBaseTrigger *pTrigger):
+		m_pTrigger(pTrigger)
+	{
+	}
+	void onEvent(const XEventPhysicsStep *pData) override;
+
+private:
+	CBaseTrigger *m_pTrigger;
+};
+
 //! Базовый класс триггера
 class CBaseTrigger: public CBaseAnimating
 {
 	DECLARE_CLASS(CBaseTrigger, CBaseAnimating);
 	DECLARE_PROPTABLE();
+
+	friend class CPhysicsTickEventListener;
 public:
 	DECLARE_CONSTRUCTOR();
 	~CBaseTrigger();
 
-	void onSync();
-	void onPostLoad();
+	void onPostLoad() override;
 
 	void enable();
 	void disable();
@@ -39,10 +54,9 @@ public:
 	void setOrient(const SMQuaternion & q) override;
 
 protected:
-	bool m_bEnabled;
-	ID m_idUpdateInterval;
+	bool m_bEnabled = true;
 
-	ID m_idDevMaterial;
+	ID m_idDevMaterial = -1;
 	
 	Array<CBaseEntity*> m_aTouches;
 	Array<CBaseEntity*> m_aNewTouches;
@@ -51,9 +65,9 @@ protected:
 	output_t m_onTouchEnd;
 	output_t m_onTouchEndAll;
 
-	void update(float dt);
+	void update();
 
-	btPairCachingGhostObject *m_pGhostObject;
+	btPairCachingGhostObject *m_pGhostObject = NULL;
 
 	bool m_isModelEnabled = true;
 
@@ -67,6 +81,13 @@ protected:
 	virtual void onTouchStart(CBaseEntity *pActivator);
 	virtual void onTouchEnd(CBaseEntity *pActivator);
 	virtual void onTouchEndAll(CBaseEntity *pActivator);
+
+private:
+	static IEventChannel<XEventPhysicsStep> *m_pTickEventChannel;
+
+	CPhysicsTickEventListener m_physicsTicker;
+
+	void onPhysicsStep();
 };
 
 #endif
diff --git a/source/game/BaseWeapon.cpp b/source/game/BaseWeapon.cpp
index 48e6217cf4e53b25ac6a525e890857322e147710..67f5c8803f5bbcb3e3cf75a34eee39b56ff4cc73 100644
--- a/source/game/BaseWeapon.cpp
+++ b/source/game/BaseWeapon.cpp
@@ -93,33 +93,7 @@ END_PROPTABLE()
 
 REGISTER_ENTITY_NOLISTING(CBaseWeapon, base_weapon);
 
-CBaseWeapon::CBaseWeapon(CEntityManager * pMgr):
-	BaseClass(pMgr),
-
-	m_idTaskShoot(-1),
-
-	m_pSilencer(NULL),
-	m_pScope(NULL),
-	m_pHandle(NULL),
-	m_pMag(NULL),
-	m_fireMode(FIRE_MODE_SINGLE),
-	m_iFireModes(0),
-	
-	m_iCapacity(1),
-	m_iCurrentLoad(0),
-
-	m_fBaseSpread(0.33f),
-	m_fSpreadIdle(0.01f),
-	m_fSpreadCrouch(0.007f),
-	m_fSpreadCrawl(0.001f),
-	m_fSpreadWalk(1.0f),
-	m_fSpreadRun(4.0f),
-	m_fSpreadAirborne(5.0f),
-	m_fSpreadCondition(3.0f),
-	m_fSpreadArm(3.0f),
-	m_fSpreadIronSight(-0.8f),
-
-	m_fAimingRange(100.f)
+CBaseWeapon::CBaseWeapon()
 {
 	m_bIsWeapon = true;
 }
@@ -256,7 +230,7 @@ void CBaseWeapon::secondaryAction(BOOL st)
 	m_bInSecondaryAction = st != FALSE;
 	if(m_iZoomable)
 	{
-		((CPlayer*)m_pOwner)->getCrosshair()->enable(!st);
+		((CPlayer*)m_pOwner.getEntity())->getCrosshair()->enable(!st);
 	}
 }
 
@@ -280,7 +254,7 @@ void CBaseWeapon::reload()
 			printf(COLOR_MAGENTA "Mag full!\n" COLOR_RESET);
 			return;
 		}
-		int count = ((CBaseCharacter*)m_pOwner)->getInventory()->consumeItems(m_szLoadedAmmo, iWantLoad);
+		int count = ((CBaseCharacter*)m_pOwner.getEntity())->getInventory()->consumeItems(m_szLoadedAmmo, iWantLoad);
 		if(count)
 		{
 			bool isFast = m_iCapacity == m_iCurrentLoad;
@@ -309,7 +283,7 @@ void CBaseWeapon::reload()
 			if(pHUD)
 			{
 				pHUD->setWeaponCurrentLoad((m_pMag ? m_pMag->getLoad() : 0) + m_iCurrentLoad);
-				pHUD->setWeaponMaxAmmo(((CBaseCharacter*)m_pOwner)->getInventory()->getItemCount(m_szLoadedAmmo));
+				pHUD->setWeaponMaxAmmo(((CBaseCharacter*)m_pOwner.getEntity())->getInventory()->getItemCount(m_szLoadedAmmo));
 			}
 		}
 		else
@@ -531,12 +505,12 @@ void CBaseWeapon::updateHUDinfo()
 {
 	if(m_pOwner)
 	{
-		CHUDcontroller * pHUD = ((CBaseCharacter*)m_pOwner)->getHUDcontroller();
+		CHUDcontroller *pHUD = ((CBaseCharacter*)m_pOwner.getEntity())->getHUDcontroller();
 		if(pHUD)
 		{
 			pHUD->setWeaponMaxLoad((m_pMag ? m_pMag->getCapacity() : 0)/* + m_iCapacity*/);
 			pHUD->setWeaponCurrentLoad((m_pMag ? m_pMag->getLoad() : 0) + m_iCurrentLoad);
-			pHUD->setWeaponMaxAmmo(((CBaseCharacter*)m_pOwner)->getInventory()->getItemCount(m_szLoadedAmmo));
+			pHUD->setWeaponMaxAmmo(((CBaseCharacter*)m_pOwner.getEntity())->getInventory()->getItemCount(m_szLoadedAmmo));
 		}
 	}
 }
diff --git a/source/game/BaseWeapon.h b/source/game/BaseWeapon.h
index fbd1dcc3bbc887afe6ac3da3093a2a7e10a9c45e..f9f6203a0a33efd63cfde21633c307bb31829ba1 100644
--- a/source/game/BaseWeapon.h
+++ b/source/game/BaseWeapon.h
@@ -63,7 +63,7 @@ class CBaseWeapon: public CBaseTool
 public:
 	DECLARE_CONSTRUCTOR();
 	~CBaseWeapon();
-	virtual void onPostLoad();
+	void onPostLoad() override;
 
 	virtual void primaryAction(BOOL st);
 	virtual void secondaryAction(BOOL st);
@@ -104,38 +104,38 @@ protected:
 	//! Задача стрельбы
 	virtual void taskShoot(float dt);
 
-	ID m_idTaskShoot;
+	ID m_idTaskShoot = -1;
 
 	// Compatible addons
-	const char * m_szAddonScopes;
-	const char * m_szAddonSilencers;
-	const char * m_szAddonMags;
-	const char * m_szAddonHandlers;
+	const char *m_szAddonScopes = NULL;
+	const char *m_szAddonSilencers = NULL;
+	const char *m_szAddonMags = NULL;
+	const char *m_szAddonHandlers = NULL;
 
 	// Addons
-	CBaseSilencer * m_pSilencer;
-	CBaseScope * m_pScope;
-	CBaseHandle * m_pHandle;
-	CBaseMag * m_pMag;
+	CBaseSilencer *m_pSilencer = NULL;
+	CBaseScope *m_pScope = NULL;
+	CBaseHandle *m_pHandle = NULL;
+	CBaseMag *m_pMag = NULL;
 
 	// Fire modes
-	FIRE_MODE m_fireMode;
-	int m_iFireModes;
-	const char * m_szFireModes;
-	int m_iSingleRate;
-	int m_iBurstRate;
-	int m_iCutoffRate;
-	int m_iCutoffSize;
+	FIRE_MODE m_fireMode = FIRE_MODE_SINGLE;
+	int m_iFireModes = 0;
+	const char *m_szFireModes = NULL;
+	int m_iSingleRate = 1;
+	int m_iBurstRate = 1;
+	int m_iCutoffRate = 1;
+	int m_iCutoffSize = 1;
 
-	int m_iCutoffCurrent;
+	int m_iCutoffCurrent = 0;
 
 	// Sounds
-	const char *m_szSndDraw;
-	const char *m_szSndHolster;
-	const char *m_szSndShoot;
-	const char *m_szSndEmpty;
-	const char *m_szSndReload;
-	const char *m_szSndSwitch;
+	const char *m_szSndDraw = NULL;
+	const char *m_szSndHolster = NULL;
+	const char *m_szSndShoot = NULL;
+	const char *m_szSndEmpty = NULL;
+	const char *m_szSndReload = NULL;
+	const char *m_szSndSwitch = NULL;
 
 	IXSoundPlayer *m_pSndDraw = NULL;
 	IXSoundPlayer *m_pSndHolster = NULL;
@@ -145,26 +145,26 @@ protected:
 	IXSoundPlayer *m_pSndSwitch = NULL;
 
 	// Shooting
-	float m_fEffectiveDistance;
-	RIFLE_TYPE m_rifleType;
-	float m_fRifleStep;
-	float m_fAimingRange;
+	float m_fEffectiveDistance = 1000.0f;
+	RIFLE_TYPE m_rifleType = RIFLE_TYPE_UNRIFLED;
+	float m_fRifleStep = 0.0f;
+	float m_fAimingRange = 100.0f;
 
 	// Without mag
-	int m_iCapacity;
-	int m_iCurrentLoad;
+	int m_iCapacity = 1;
+	int m_iCurrentLoad = 0;
 
 	// Spread
-	float m_fBaseSpread;
-	float m_fSpreadIdle;
-	float m_fSpreadCrouch;
-	float m_fSpreadCrawl;
-	float m_fSpreadWalk;
-	float m_fSpreadRun;
-	float m_fSpreadAirborne;
-	float m_fSpreadCondition;
-	float m_fSpreadArm;
-	float m_fSpreadIronSight;
+	float m_fBaseSpread = 0.33f;
+	float m_fSpreadIdle = 0.01f;
+	float m_fSpreadCrouch = 0.007f;
+	float m_fSpreadCrawl = 0.001f;
+	float m_fSpreadWalk = 1.0f;
+	float m_fSpreadRun = 4.0f;
+	float m_fSpreadAirborne = 5.0f;
+	float m_fSpreadCondition = 3.0f;
+	float m_fSpreadArm = 3.0f;
+	float m_fSpreadIronSight = -0.8f;
 };
 
 #endif
diff --git a/source/game/BaseWeaponAddon.cpp b/source/game/BaseWeaponAddon.cpp
index 03e94db9ff4e3bceecacd595ab4ec7e9b2e8971c..6234e216d1b4ac83be0814b6ca87d626133c319b 100644
--- a/source/game/BaseWeaponAddon.cpp
+++ b/source/game/BaseWeaponAddon.cpp
@@ -16,12 +16,6 @@ END_PROPTABLE()
 
 REGISTER_ENTITY_NOLISTING(CBaseWeaponAddon, base_wpn_addon);
 
-CBaseWeaponAddon::CBaseWeaponAddon(CEntityManager * pMgr):
-	BaseClass(pMgr),
-	m_addonType(WPN_ADDON_NONE)
-{
-}
-
 WPN_ADDON CBaseWeaponAddon::getType() const
 {
 	return(m_addonType);
diff --git a/source/game/BaseWeaponAddon.h b/source/game/BaseWeaponAddon.h
index 5d3922b21c39facd9410ee4523ca34d322d5a7c9..c2f1ad13512428746f09d03918884ca6819c8820 100644
--- a/source/game/BaseWeaponAddon.h
+++ b/source/game/BaseWeaponAddon.h
@@ -34,14 +34,14 @@ class CBaseWeaponAddon: public CBaseItem
 	DECLARE_CLASS(CBaseWeaponAddon, CBaseItem);
 	DECLARE_PROPTABLE();
 public:
-	DECLARE_CONSTRUCTOR();
+	DECLARE_TRIVIAL_CONSTRUCTOR();
 
 	//! Получить тип навеса
 	WPN_ADDON getType() const;
 
 protected:
 	//! Тип навеса
-	WPN_ADDON m_addonType;
+	WPN_ADDON m_addonType = WPN_ADDON_NONE;
 };
 
 #endif
diff --git a/source/game/Baseline.h b/source/game/Baseline.h
index 103516a477f98ce5778bff7d5231ee92bf5ed4df..1526f336094452a95f121d85f7da0fa858454650 100644
--- a/source/game/Baseline.h
+++ b/source/game/Baseline.h
@@ -16,7 +16,7 @@ class CBaseline
 
 	struct ent_record_s
 	{
-		UINT m_id;
+		XGUID m_guid;
 		String m_sClassname;
 		AssotiativeArray<String, String> m_mProps;
 	};
diff --git a/source/game/EditorObject.cpp b/source/game/EditorObject.cpp
index 9bb29d1105cf9013ba7862bde423aea5157b0351..11af1e264f46b7b7d47f0209a4a20f45149e92c2 100644
--- a/source/game/EditorObject.cpp
+++ b/source/game/EditorObject.cpp
@@ -8,7 +8,7 @@
 CEditorObject::CEditorObject(CEditable *pEditable, CBaseEntity *pEntity):
 	m_pEditable(pEditable),
 	m_pEntity(pEntity),
-	m_idEnt(pEntity->getId())
+	m_guidEnt(*pEntity->getGUID())
 {
 	assert(pEntity);
 
@@ -40,13 +40,22 @@ void CEditorObject::_iniFieldList()
 {
 	proptable_t *pTable = CEntityFactoryMap::GetInstance()->getPropTable(m_szClassName);
 	propdata_t *pField = NULL;
-	X_PROP_FIELD xField;
+	X_PROP_FIELD xField = {};
 
 	for(UINT i = 0; i < 16; ++i)
 	{
 		m_aszFlags[i] = NULL;
 	}
 
+	{
+		xField.editorType = XPET_TEXT; 
+		xField.szHelp = "";
+		xField.szKey = "guid";
+		xField.szName = "GUID";
+
+		m_aFields.push_back(xField);
+	}
+
 	while(pTable)
 	{
 		for(int i = 0; i < pTable->numFields; ++i)
@@ -123,29 +132,68 @@ void CEditorObject::_iniFieldList()
 
 void XMETHODCALLTYPE CEditorObject::setPos(const float3_t &pos)
 {
-	if(m_pEntity)
+	SAFE_CALL(m_pEntity, setPos, pos);
+	m_vPos = pos;
+}
+
+void CEditorObject::setPos(const float3_t &pos, bool isSeparate)
+{
+	if(isSeparate)
 	{
-		m_pEntity->setPos(pos);
+		SAFE_CALL(m_pEntity, setSeparateMovement, true);
+	}
+
+	setPos(pos);
+
+	if(isSeparate)
+	{
+		SAFE_CALL(m_pEntity, setSeparateMovement, false);
 	}
-	m_vPos = pos;
 }
 
 void XMETHODCALLTYPE CEditorObject::setScale(const float3_t &vScale)
 {
-	//@TODO: Implement me
+	// TODO Implement me
 	m_vScale = vScale;
 }
 
-void XMETHODCALLTYPE CEditorObject::setOrient(const SMQuaternion &orient)
+void CEditorObject::setScale(const float3_t &vScale, bool isSeparate)
 {
-	if(m_pEntity)
+	if(isSeparate)
 	{
-		m_pEntity->setOrient(orient);
+		SAFE_CALL(m_pEntity, setSeparateMovement, true);
 	}
 
+	setScale(vScale);
+
+	if(isSeparate)
+	{
+		SAFE_CALL(m_pEntity, setSeparateMovement, false);
+	}
+}
+
+void XMETHODCALLTYPE CEditorObject::setOrient(const SMQuaternion &orient)
+{
+	SAFE_CALL(m_pEntity, setOrient, orient);
+
 	m_qRot = orient;
 }
 
+void CEditorObject::setOrient(const SMQuaternion &orient, bool isSeparate)
+{
+	if(isSeparate)
+	{
+		SAFE_CALL(m_pEntity, setSeparateMovement, true);
+	}
+
+	setOrient(orient);
+
+	if(isSeparate)
+	{
+		SAFE_CALL(m_pEntity, setSeparateMovement, false);
+	}
+}
+
 float3_t XMETHODCALLTYPE CEditorObject::getPos()
 {
 	if(m_pEntity)
@@ -228,7 +276,7 @@ void XMETHODCALLTYPE CEditorObject::remove()
 	}
 	REMOVE_ENTITY(m_pEntity);
 	m_pEntity = NULL;
-	m_idEnt = -1;
+	//m_guidEnt = XGUID();
 }
 void XMETHODCALLTYPE CEditorObject::preSetup()
 {
@@ -241,22 +289,29 @@ void XMETHODCALLTYPE CEditorObject::postSetup()
 void XMETHODCALLTYPE CEditorObject::create()
 {
 	assert(!m_pEntity);
-	m_pEntity = CREATE_ENTITY(m_szClassName, GameData::m_pMgr);
 
-	m_idEnt = m_pEntity->getId();
+	if(m_guidEnt == XGUID())
+	{
+		m_pEntity = CREATE_ENTITY(m_szClassName, GameData::m_pMgr);
+		m_guidEnt = *m_pEntity->getGUID();
+	}
+	else
+	{
+		m_pEntity = CEntityFactoryMap::GetInstance()->create(m_szClassName, GameData::m_pMgr, false, &m_guidEnt);
+	}
 
 	m_pEntity->setFlags(m_pEntity->getFlags() | EF_LEVEL | EF_EXPORT);
 
-	setPos(getPos());
-	setOrient(getOrient());
-	setScale(getScale());
+	setPos(m_vPos, true);
+	setOrient(m_qRot, true);
+	setScale(m_vScale, true);
 }
 
 void CEditorObject::resync()
 {
-	if(ID_VALID(m_idEnt))
+	if(m_pEntity)
 	{
-		m_pEntity = GameData::m_pMgr->getById(m_idEnt);
+		m_pEntity = GameData::m_pMgr->getByGUID(m_guidEnt);
 	}
 }
 
@@ -276,7 +331,14 @@ const char* XMETHODCALLTYPE CEditorObject::getKV(const char *szKey)
 
 	char tmp[4096];
 
-	m_pEntity->getKV(szKey, tmp, sizeof(tmp));
+	if(!fstrcmp(szKey, "guid"))
+	{
+		XGUIDToSting(*m_pEntity->getGUID(), tmp, sizeof(tmp));
+	}
+	else
+	{
+		m_pEntity->getKV(szKey, tmp, sizeof(tmp));
+	}
 
 	m_msPropCache[szKey] = tmp;
 	return(m_msPropCache[szKey].c_str());
diff --git a/source/game/EditorObject.h b/source/game/EditorObject.h
index e9bab6d374cc047f83c735a9a8e791f532e044ea..e0b4c8141a6fc1df9d2191cfa9bf23a7ab56f616 100644
--- a/source/game/EditorObject.h
+++ b/source/game/EditorObject.h
@@ -16,8 +16,11 @@ public:
 	~CEditorObject();
 
 	void XMETHODCALLTYPE setPos(const float3_t &pos) override;
+	void setPos(const float3_t &pos, bool isSeparate);
 	void XMETHODCALLTYPE setOrient(const SMQuaternion &orient) override;
-	void XMETHODCALLTYPE setScale(const float3_t &pos) override;
+	void setOrient(const SMQuaternion &orient, bool isSeparate);
+	void XMETHODCALLTYPE setScale(const float3_t &scale) override;
+	void setScale(const float3_t &scale, bool isSeparate);
 
 	void XMETHODCALLTYPE getBound(float3 *pvMin, float3 *pvMax) override;
 
@@ -74,7 +77,7 @@ protected:
 
 	void _iniFieldList();
 
-	ID m_idEnt = -1;
+	XGUID m_guidEnt;
 
 protected:
 	bool m_isSelected = false;
diff --git a/source/game/EditorOutputsTab.cpp b/source/game/EditorOutputsTab.cpp
index fe0a6236d8514b85cd27783f4251293cc78544e8..a5efe61d073bf5208d7280aba8fab7315aba03e7 100644
--- a/source/game/EditorOutputsTab.cpp
+++ b/source/game/EditorOutputsTab.cpp
@@ -427,9 +427,9 @@ void CEditorOutputsTab::initSelection()
 						propdata_t *pField = pEnt->getField(pPropData->szKey);
 						output_t *pOutput = &(pEnt->*((output_t CBaseEntity::*)pField->pField));
 						
-						for(int i = 0; i < pOutput->iOutCount; ++i)
+						for(int i = 0, l = pOutput->aOutputs.size(); i < l; ++i)
 						{
-							const named_output_t &namedOutput = pOutput->pOutputs[i];
+							const named_output_t &namedOutput = pOutput->aOutputs[i];
 
 							int idx = m_pCurrentCommand->m_aRows.indexOf(namedOutput, [&](const Row &row, const named_output_t &out){
 								return(
@@ -594,7 +594,7 @@ INT_PTR CALLBACK CEditorOutputsTab::dlgProc(HWND hWnd, UINT msg, WPARAM wParam,
 				if(pNMLV->hdr.idFrom == IDC_LIST_OUTPUTS && !m_isSkipUpdate && (pNMLV->uChanged & LVIF_STATE) && ((pNMLV->uNewState ^ pNMLV->uOldState) & LVIS_SELECTED))
 				{
 					Row *pRow = &m_pCurrentCommand->m_aRows[pNMLV->iItem];
-					pRow->isSelected = pNMLV->uNewState & LVIS_SELECTED;
+					pRow->isSelected = (pNMLV->uNewState & LVIS_SELECTED) != 0;
 
 					updateButtons();
 				}
diff --git a/source/game/EntityFactory.cpp b/source/game/EntityFactory.cpp
index ac4de7c989f397e60b0ec0e9e99d763874c4daa9..fcfa2eb693c8ad01247ef3651741726f32faf4d5 100644
--- a/source/game/EntityFactory.cpp
+++ b/source/game/EntityFactory.cpp
@@ -22,13 +22,14 @@ void CEntityFactoryMap::addFactory(IEntityFactory *pFactory, const char *szName)
 	}
 	m_mFactories[AAString(szName)] = pFactory;
 }
-CBaseEntity* CEntityFactoryMap::create(const char *szName, CEntityManager *pWorld, bool bDelayPostLoad)
+CBaseEntity* CEntityFactoryMap::create(const char *szName, CEntityManager *pWorld, bool bDelayPostLoad, const XGUID *pGUID)
 {
 	IEntityFactory *pFactory = getFactory(szName);
 	if(pFactory)
 	{
 		EntDefaultsMap *defs = pFactory->getDefaults();
-		CBaseEntity *pEnt = pFactory->create(pWorld);
+		CBaseEntity *pEnt = pFactory->create();
+		pWorld->reg(pEnt, pGUID);
 		pEnt->setDefaults();
 		pEnt->setClassName(pFactory->getClassName());
 
@@ -60,11 +61,6 @@ CBaseEntity* CEntityFactoryMap::create(const char *szName, CEntityManager *pWorl
 			pEnt->_initEditorBoxes();
 		}
 
-		if(pFactory->isSyncable())
-		{
-			pWorld->regSync(pEnt);
-		}
-
 		return(pEnt);
 	}
 	return(NULL);
@@ -76,10 +72,6 @@ void CEntityFactoryMap::destroy(CBaseEntity *pEnt)
 		IEntityFactory *pFactory = getFactory(pEnt->getClassName());
 		if(pFactory)
 		{
-			if(pFactory->isSyncable())
-			{
-				pEnt->m_pMgr->unregSync(pEnt);
-			}
 			return(pFactory->destroy(pEnt));
 		}
 	}
diff --git a/source/game/EntityFactory.h b/source/game/EntityFactory.h
index 3aa8d7ef9128fb79c6c7a4b0adee045b14e9547d..bde74bf914ec1c024c8986bcd8ff38e83d0bd019 100644
--- a/source/game/EntityFactory.h
+++ b/source/game/EntityFactory.h
@@ -22,14 +22,13 @@ class CEntityManager;
 class IEntityFactory
 {
 public:
-	virtual CBaseEntity* create(CEntityManager * pWorld) = 0;
+	virtual CBaseEntity* create() = 0;
 	virtual void destroy(CBaseEntity * pEnt) = 0;
 	virtual const char* getClassName() = 0;
 	virtual proptable_t* getPropTable() = 0;
 	virtual bool isEditorHidden() = 0;
 	virtual EntDefaultsMap* getDefaults() = 0;
 	virtual IEntityFactory* copy(const char * szName, bool showInListing) = 0;
-	virtual bool isSyncable() = 0;
 };
 
 class CEntityFactoryMap
@@ -39,7 +38,7 @@ public:
 	CEntityFactoryMap();
 
 	void addFactory(IEntityFactory *pFactory, const char *szName);
-	CBaseEntity* create(const char *szName, CEntityManager *pMgr, bool bDelayPostLoad=false);
+	CBaseEntity* create(const char *szName, CEntityManager *pMgr, bool bDelayPostLoad=false, const XGUID *pGUID=NULL);
 	void destroy(CBaseEntity *pEnt);
 
 	static CEntityFactoryMap* GetInstance();
@@ -86,12 +85,11 @@ template <class T>
 class CEntityFactory: public IEntityFactory
 {
 public:
-	CEntityFactory(const char * szName, bool showInListing, bool isSyncable=true)
+	CEntityFactory(const char * szName, bool showInListing)
 	{
 		m_bShowInListing = showInListing;
 		m_szClassName = szName;
 		m_pPropTable = T::SGetPropTable();
-		m_isSyncable = isSyncable;
 		CEntityFactoryMap::GetInstance()->addFactory(this, szName);
 	}
 
@@ -113,9 +111,9 @@ public:
 		return(newF);
 	}
 
-	CBaseEntity* create(CEntityManager *pWorld) override
+	CBaseEntity* create() override
 	{
-		return(new T(pWorld));
+		return(new T());
 	}
 
 	void destroy(CBaseEntity *pEnt) override
@@ -141,11 +139,6 @@ public:
 		return(!m_bShowInListing);
 	}
 
-	bool isSyncable() override
-	{
-		return(m_isSyncable);
-	}
-
 	EntDefaultsMap* getDefaults() override
 	{
 		return(&m_mDefaults);
@@ -155,7 +148,6 @@ private:
 	const char * m_szClassName;
 	proptable_t * m_pPropTable;
 	bool m_bShowInListing;
-	bool m_isSyncable;
 	EntDefaultsMap m_mDefaults;
 	Array<CEntityFactory<T>*> m_vDerivatives;
 };
@@ -163,9 +155,6 @@ private:
 #define REGISTER_ENTITY(cls, name) \
 	CEntityFactory<cls> ent_ ## name ## _factory(#name, 1)
 
-#define REGISTER_ENTITY_NOSYNC(cls, name) \
-	CEntityFactory<cls> ent_ ## name ## _factory(#name, 1, 0)
-
 #define REGISTER_ENTITY_NOLISTING(cls, name) \
 	CEntityFactory<cls> ent_ ## name ## _factory(#name, 0)
 
diff --git a/source/game/EntityList.cpp b/source/game/EntityList.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4c5f9ad0476f88c5373aacaef261a593f17bfd28
--- /dev/null
+++ b/source/game/EntityList.cpp
@@ -0,0 +1,146 @@
+#include "EntityList.h"
+#include "BaseEntity.h"
+
+CEntityList::~CEntityList()
+{
+	clearList();
+
+	unregisterWait();
+}
+
+//! Установка имени или GUID связанного объекта
+void CEntityList::setEntityName(const char *szName)
+{
+	clearList();
+
+	unregisterWait();
+	m_sName = szName;
+
+	if(szName[0])
+	{
+		registerWait();
+
+		CBaseEntity *pEnt = NULL;
+		while((pEnt = m_pThisEntity->getEntByName(szName, pEnt)))
+		{
+			addEntity(pEnt);
+		}
+	}
+}
+
+//! Установка
+void CEntityList::addEntity(CBaseEntity *pEnt)
+{
+	assert(pEnt);
+
+	pEnt->registerPointer(this);
+
+	int idx = m_aEntities.indexOf(pEnt);
+	assert(idx < 0);
+	if(idx < 0)
+	{
+		m_aEntities.push_back(pEnt);
+		onLinkEstablished(pEnt);
+	}
+}
+
+void CEntityList::removeEntity(CBaseEntity *pEnt)
+{
+	assert(pEnt);
+	int idx = m_aEntities.indexOf(pEnt);
+	assert(idx >= 0);
+	if(idx >= 0)
+	{
+		onLinkBroken(pEnt);
+		m_aEntities[idx] = m_aEntities[m_aEntities.size() - 1];
+		m_aEntities.erase(m_aEntities.size() - 1);
+	}
+}
+
+//! Получение указателя на объект
+CBaseEntity* CEntityList::getEntity(int idx)
+{
+	return((int)m_aEntities.size() >= idx ? m_aEntities[idx] : NULL);
+}
+
+UINT CEntityList::getEntityCount()
+{
+	return(m_aEntities.size());
+}
+
+const char* CEntityList::getEntityName()
+{
+	return(m_sName.c_str());
+}
+
+CBaseEntity* CEntityList::operator[](int idx)
+{
+	return(getEntity(idx));
+}
+
+CEntityList& CEntityList::operator+=(CBaseEntity *pEnt)
+{
+	addEntity(pEnt);
+	return(*this);
+}
+
+CEntityList& CEntityList::operator-=(CBaseEntity *pEnt)
+{
+	removeEntity(pEnt);
+	return(*this);
+}
+
+void CEntityList::onLinkBroken(CBaseEntity *pOldEnt)
+{
+	if(m_pfnOnLinkBroken)
+	{
+		(m_pThisEntity->*m_pfnOnLinkBroken)(pOldEnt);
+	}
+	if(m_pOnLinkBroken)
+	{
+		m_pOnLinkBroken->onEvent(pOldEnt);
+	}
+}
+void CEntityList::onLinkEstablished(CBaseEntity *pNewEnt)
+{
+	if(m_pfnOnLinkEstablished)
+	{
+		(m_pThisEntity->*m_pfnOnLinkEstablished)(pNewEnt);
+	}
+	if(m_pOnLinkEstablished)
+	{
+		m_pOnLinkEstablished->onEvent(pNewEnt);
+	}
+}
+void CEntityList::onTargetRemoved(CBaseEntity *pEnt)
+{
+	removeEntity(pEnt);
+}
+
+void CEntityList::registerWait()
+{
+	if(!m_isWaiting)
+	{
+		m_pThisEntity->m_pMgr->registerWaitForName(m_sName.c_str(), this);
+		m_isWaiting = true;
+	}
+}
+void CEntityList::unregisterWait()
+{
+	if(m_isWaiting)
+	{
+		m_pThisEntity->m_pMgr->unregisterWaitForName(m_sName.c_str(), this);
+		m_isWaiting = false;
+	}
+}
+
+void CEntityList::clearList()
+{
+	for(UINT i = 0, l = m_aEntities.size(); i < l; ++i)
+	{
+		m_aEntities[i]->unregisterPointer(this);
+	}
+	m_aEntities.clearFast();
+}
+
+
diff --git a/source/game/EntityList.h b/source/game/EntityList.h
new file mode 100644
index 0000000000000000000000000000000000000000..5e03cb9ad4ded82c260d7bca0afaa4945d4cedba
--- /dev/null
+++ b/source/game/EntityList.h
@@ -0,0 +1,95 @@
+#ifndef __ENTITY_LIST_H
+#define __ENTITY_LIST_H
+
+#include <gdefines.h>
+#include "EntityPointer.h"
+#include <common/string.h>
+
+class CBaseEntity;
+class CEntityManager;
+class CEntityList: public IEntityPointer
+{
+	DECLARE_CLASS_NOBASE(CEntityList);
+	friend class CBaseEntity;
+	friend struct named_output_t;
+public:
+	~CEntityList();
+
+	//! Установка имени или GUID связанного объекта
+	void setEntityName(const char *szName);
+	
+	//! Установка
+	void addEntity(CBaseEntity *pEnt);
+
+	void removeEntity(CBaseEntity *pEnt);
+
+	//! Получение указателя на объект
+	CBaseEntity* getEntity(int idx);
+
+	UINT getEntityCount();
+
+	const char* getEntityName();
+	
+	CBaseEntity* operator[](int idx);
+
+	CEntityList& operator+=(CBaseEntity *pEnt);
+
+	CEntityList& operator-=(CBaseEntity *pEnt);
+
+	//! Вызывается при разрушении связи
+	template<typename F>
+	void setLinkBrokenListener(void(F::*func)(CBaseEntity*))
+	{
+		static_assert(std::is_base_of<CBaseEntity, F>::value, "F must be subclass of CBaseEntity");
+
+		m_pfnOnLinkBroken = func;
+	}
+
+	//! Вызывается при установке связи
+	template<typename F>
+	void setLinkEstablishedListener(void(F::*func)(CBaseEntity*))
+	{
+		static_assert(std::is_base_of<CBaseEntity, F>::value, "F must be subclass of CBaseEntity");
+
+		m_pfnOnLinkEstablished = func;
+	}
+
+	void setLinkBrokenListener(IEntityPointerEvent *pFunc)
+	{
+		m_pOnLinkBroken = pFunc;
+	}
+	void setLinkEstablishedListener(IEntityPointerEvent *pFunc)
+	{
+		m_pOnLinkEstablished = pFunc;
+	}
+	
+private:
+	String m_sName;
+	Array<CBaseEntity*> m_aEntities;
+	CBaseEntity *m_pThisEntity = NULL;
+
+	void(CBaseEntity::*m_pfnOnLinkEstablished)(CBaseEntity*) = NULL;
+	void(CBaseEntity::*m_pfnOnLinkBroken)(CBaseEntity*) = NULL;
+	IEntityPointerEvent *m_pOnLinkEstablished = NULL;
+	IEntityPointerEvent *m_pOnLinkBroken = NULL;
+
+	void onLinkBroken(CBaseEntity *pOldEnt);
+	void onLinkEstablished(CBaseEntity *pNewEnt);
+	void onTargetRemoved(CBaseEntity *pEnt) override;
+
+	bool m_isWaiting = false;
+	void registerWait();
+	void unregisterWait();
+	void onWaitDone(CBaseEntity *pEnt) override
+	{
+	}
+
+	void clearList();
+
+	void init(CBaseEntity *pThisEntity)
+	{
+		m_pThisEntity = pThisEntity;
+	}
+};
+
+#endif
diff --git a/source/game/EntityManager.cpp b/source/game/EntityManager.cpp
index 7075321213822d2510c056703d53f226be6184ad..1f808ecc7eef7fee82a41b1741286f61a7a1dbe8 100644
--- a/source/game/EntityManager.cpp
+++ b/source/game/EntityManager.cpp
@@ -72,30 +72,31 @@ void CEntityManager::update(int thread)
 			inputData.pActivator = to->data.pActivator;
 			inputData.pInflictor = to->data.pInflictor;
 
-			for(int j = 0; j < to->pOutput->iOutCount; ++j)
+			for(UINT j = 0, jl = to->pOutput->aOutputs.size(); j < jl; ++j)
 			{
-				if(!to->pOutput->pOutputs[j].pTarget)
+				input_t &out = to->pOutput->aOutputs[j];
+				if(!out.pTarget)
 				{
 					continue;
 				}
 
-				inputData.type = to->pOutput->pOutputs[j].data.type;
+				inputData.type = out.data.type;
 
 				if(inputData.type == PDF_STRING)
 				{
 					inputData.parameter.str = NULL;
 				}
 
-				if(to->pOutput->pOutputs[j].useOverrideData)
+				if(out.useOverrideData)
 				{
-					inputData.setParameter(to->pOutput->pOutputs[j].data);
+					inputData.setParameter(out.data);
 				}
 				else
 				{
 					inputData.setParameter(to->data);
 				}
 
-				(to->pOutput->pOutputs[j].pTarget->*(to->pOutput->pOutputs[j].fnInput))(&inputData);
+				(out.pTarget->*(out.fnInput))(&inputData);
 
 				if(inputData.type == PDF_STRING && inputData.parameter.str != GetEmptyString())
 				{
@@ -167,8 +168,6 @@ void CEntityManager::finalRemove()
 
 void CEntityManager::sync()
 {
-	CBaseEntity * pEnt;
-
 	finalRemove();
 
 	for(int i = 0, l = m_vTimeout.size(); i < l; ++i)
@@ -199,25 +198,7 @@ void CEntityManager::sync()
 	//static time_point tOld = std::chrono::high_resolution_clock::now();
 	//float dt;
 	//dt = (float)std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - tOld).count() / 1000000.0f;
-	for(int i = 0, l = m_vEntSyncList.size(); i < l; ++i)
-	{
-		pEnt = m_vEntSyncList[i];
-		if(pEnt)
-		{
-			pEnt->m_bSynced = false;
-		}
-	}
 	
-	for(int i = 0, l = m_vEntSyncList.size(); i < l; ++i)
-	{
-		pEnt = m_vEntSyncList[i];
-		if(pEnt && !pEnt->m_bSynced)
-		{
-			//pEnt->updateDiscreteLinearVelocity(0, dt);
-			pEnt->onSync();
-			//pEnt->updateDiscreteLinearVelocity(1, dt);
-		}
-	}
 	//tOld = std::chrono::high_resolution_clock::now();
 }
 
@@ -234,54 +215,74 @@ void CEntityManager::unloadObjLevel()
 	}
 }
 
-ID CEntityManager::reg(CBaseEntity *pEnt)
+const XGUID* CEntityManager::reg(CBaseEntity *pEnt, const XGUID *pGUID)
 {
-	ID ent;
 	if(!pEnt)
 	{
-		return(-1);
+		return(NULL);
 	}
-	if(m_vFreeIDs.size())
+
+	XGUID guid;
+	if(pGUID)
 	{
-		ent = m_vFreeIDs[0];
-		m_vFreeIDs.erase(0);
-		m_vEntList[ent] = pEnt;
+		guid = *pGUID;
 	}
 	else
 	{
-		ent = m_vEntList.size();
-		m_vEntList.push_back(pEnt);
+		XCreateGUID(&guid);
 	}
-	return(ent);
-}
-void CEntityManager::unreg(ID ent)
-{
-	//@TODO: Clear all outputs
-	if(m_vEntList.size() <= (UINT)ent || ent < 0)
+
+	m_mEnts[guid] = pEnt;
+
+	const XGUID *pNewGUID = &m_mEnts.TmpNode->Key;
+
+	pEnt->setGUID(pNewGUID);
+	pEnt->setWorld(this);
+
+	m_vEntList.push_back(pEnt);
+
+	if(pGUID)
 	{
-		return;
+		notifyWaitForGUID(*pGUID, pEnt);
+
+		char tmp[64];
+		XGUIDToSting(*pGUID, tmp, sizeof(tmp));
+		onEntityNameChanged(pEnt, "", tmp);
 	}
 
+	return(pNewGUID);
+}
+void CEntityManager::unreg(CBaseEntity *pEnt)
+{
+	assert(pEnt && pEnt->getGUID());
+
+	int iKey = m_vEntList.indexOf(pEnt);
+	assert(iKey >= 0);
+	UINT uLast = m_vEntList.size() - 1;
+	m_vEntList[iKey] = m_vEntList[uLast];
+	m_vEntList[uLast] = NULL;
+	m_vEntList.erase(uLast);
+
 	timeout_t * t;
 	timeout_output_t * to;
 
-	CBaseEntity *pEnt = m_vEntList[ent];
-
 	for(int i = 0, l = m_vOutputTimeout.size(); i < l; ++i)
 	{
 		to = &m_vOutputTimeout[i];
 		if(to->status == TS_WAIT)
 		{
-			int iRemoved = 0;
-			for(int j = 0; j < to->pOutput->iOutCount; ++j)
+			UINT iRemoved = 0;
+			for(UINT j = 0, jl = to->pOutput->aOutputs.size(); j < jl; ++j)
 			{
-				if(to->pOutput->pOutputs[j].pTarget == pEnt)
+				input_t &out = to->pOutput->aOutputs[j];
+
+				if(out.pTarget == pEnt)
 				{
-					to->pOutput->pOutputs[j].pTarget = NULL;
+					out.pTarget = NULL;
 					++iRemoved;
 				}
 			}
-			if(iRemoved == to->pOutput->iOutCount)
+			if(iRemoved == to->pOutput->aOutputs.size())
 			{
 				to->status = TS_DONE;
 			}
@@ -306,26 +307,7 @@ void CEntityManager::unreg(ID ent)
 		}
 	}
 
-	m_vEntList[ent] = NULL;
-	m_vFreeIDs.push_back(ent);
-}
-
-void CEntityManager::regSync(CBaseEntity *pEnt)
-{
-	assert(pEnt);
-	m_vEntSyncList.push_back(pEnt);
-}
-void CEntityManager::unregSync(CBaseEntity *pEnt)
-{
-	assert(pEnt);
-	for(UINT i = 0, l = m_vEntSyncList.size(); i < l; ++i)
-	{
-		if(m_vEntSyncList[i] == pEnt)
-		{
-			m_vEntSyncList.erase(i);
-			break;
-		}
-	}
+	m_mEnts.erase(*pEnt->getGUID());
 }
 
 ID CEntityManager::setTimeout(void(CBaseEntity::*func)(float dt), CBaseEntity *pEnt, float delay)
@@ -412,11 +394,21 @@ bool CEntityManager::exportList(const char * file)
 {
 	ISXConfig * conf = Core_CrConfig();
 	conf->New(file);
-	char buf[4096], sect[32];
+	char buf[4096], sect[64];
 	CBaseEntity * pEnt;
 	proptable_t * pTbl;
 	int ic = 0;
 
+	if(m_isOldImported)
+	{
+		FILE *fp = fopen(file, "w");
+		if(fp)
+		{
+			fclose(fp);
+		}
+		m_isOldImported = false;
+	}
+
 	// conf->set("meta", "count", "0");
 
 	for(int i = 0, l = m_vEntList.size(); i < l; ++i)
@@ -426,13 +418,14 @@ bool CEntityManager::exportList(const char * file)
 		{
 			continue;
 		}
-		sprintf(sect, "ent_%d", ic);
 
 		if(!(pEnt->getFlags() & EF_EXPORT))
 		{
 			continue;
 		}
 
+		XGUIDToSting(*pEnt->getGUID(), sect, sizeof(sect));
+
 		conf->set(sect, "classname", pEnt->getClassName());
 		pTbl = CEntityFactoryMap::GetInstance()->getPropTable(pEnt->getClassName());
 		do
@@ -450,8 +443,8 @@ bool CEntityManager::exportList(const char * file)
 		++ic;
 	}
 
-	sprintf(buf, "%d", ic);
-	conf->set("meta", "count", buf);
+	// sprintf(buf, "%d", ic);
+	// conf->set("meta", "count", buf);
 
 	bool ret = !conf->save();
 	mem_release(conf);
@@ -465,9 +458,9 @@ bool CEntityManager::import(const char * file, bool shouldSendProgress)
 	{
 		pEventChannel = Core_GetIXCore()->getEventChannel<XEventLevelProgress>(EVENT_LEVEL_PROGRESS_GUID);
 	}
-	ISXConfig * conf = Core_CrConfig();
-	char sect[32];
-	CBaseEntity * pEnt = NULL;
+	ISXConfig *conf = Core_CrConfig();
+	const char *sect;
+	CBaseEntity *pEnt = NULL;
 	Array<CBaseEntity*> tmpList;
 
 	char szFullPath[1024];
@@ -481,20 +474,13 @@ bool CEntityManager::import(const char * file, bool shouldSendProgress)
 		goto err;
 	}
 
-	if(!conf->keyExists("meta", "count"))
-	{
-		goto err;
-	}
-
-	int ic;
-	if(sscanf(conf->getKey("meta", "count"), "%d", &ic) != 1)
-	{
-		goto err;
-	}
-
+	int ic = conf->getSectionCount();
 	tmpList.reserve(ic);
 
+	m_isOldImported = conf->getKeyCount("meta") != 0;
+
 	{
+		XGUID guid;
 
 		XEventLevelProgress ev;
 		ev.idPlugin = -3;
@@ -503,64 +489,87 @@ bool CEntityManager::import(const char * file, bool shouldSendProgress)
 		ev.fProgress = 0.0f;
 		for(int i = 0; i < ic; ++i)
 		{
-			sprintf(sect, "ent_%d", i);
-			if(!conf->keyExists(sect, "classname"))
+			sect = conf->getSectionName(i);
+
+			if(sect[0] == '{' || (sect[0] == 'e' && sect[1] == 'n' && sect[2] == 't' && sect[3] == '_'))
 			{
-				printf(COLOR_LRED "Unable to load entity #%d, classname undefined\n" COLOR_RESET, i);
-				tmpList[i] = NULL;
-				continue;
+				if(!conf->keyExists(sect, "classname"))
+				{
+					printf(COLOR_LRED "Unable to load entity #%d, classname undefined\n" COLOR_RESET, i);
+					tmpList[i] = NULL;
+					continue;
+				}
+
+				XGUID *pGUID = NULL;
+				if(XGUIDFromString(&guid, sect))
+				{
+					pGUID = &guid;
+				}
+
+				if(!(pEnt = CEntityFactoryMap::GetInstance()->create(conf->getKey(sect, "classname"), this, true, pGUID)))
+				{
+					printf(COLOR_LRED "Unable to load entity #%d, classname '%s' undefined\n" COLOR_RESET, i, conf->getKey(sect, "classname"));
+					tmpList[i] = NULL;
+					continue;
+				}
+				if(conf->keyExists(sect, "name"))
+				{
+					pEnt->setKV("name", conf->getKey(sect, "name"));
+				}
+				if(conf->keyExists(sect, "origin"))
+				{
+					pEnt->setKV("origin", conf->getKey(sect, "origin"));
+				}
+				if(conf->keyExists(sect, "rotation"))
+				{
+					pEnt->setKV("rotation", conf->getKey(sect, "rotation"));
+				}
+				pEnt->setFlags(pEnt->getFlags() | EF_EXPORT | EF_LEVEL);
+				tmpList[i] = pEnt;
+
+				if((i & 0xF) == 0 && pEventChannel)
+				{
+					ev.fProgress = (float)i / (float)ic * 0.1f;
+					pEventChannel->broadcastEvent(&ev);
+				}
 			}
-			if(!(pEnt = CREATE_ENTITY_NOPOST(conf->getKey(sect, "classname"), this)))
+			else
 			{
-				printf(COLOR_LRED "Unable to load entity #%d, classname '%s' undefined\n" COLOR_RESET, i, conf->getKey(sect, "classname"));
 				tmpList[i] = NULL;
-				continue;
-			}
-			if(conf->keyExists(sect, "name"))
-			{
-				pEnt->setKV("name", conf->getKey(sect, "name"));
-			}
-			if(conf->keyExists(sect, "origin"))
-			{
-				pEnt->setKV("origin", conf->getKey(sect, "origin"));
-			}
-			if(conf->keyExists(sect, "rotation"))
-			{
-				pEnt->setKV("rotation", conf->getKey(sect, "rotation"));
-			}
-			pEnt->setFlags(pEnt->getFlags() | EF_EXPORT | EF_LEVEL);
-			tmpList[i] = pEnt;
-
-			if((i & 0xF) == 0 && pEventChannel)
-			{
-				ev.fProgress = (float)i / (float)ic * 0.1f;
-				pEventChannel->broadcastEvent(&ev);
 			}
 		}
 
 		for(int i = 0; i < ic; ++i)
 		{
-			sprintf(sect, "ent_%d", i);
-			if(!(pEnt = tmpList[i]))
-			{
-				continue;
-			}
-			int keyc = conf->getKeyCount(sect);
-			const char * key;
-			for(int j = 0; j < keyc; ++j)
+			sect = conf->getSectionName(i);
+
+			if(sect[0] == '{' || (sect[0] == 'e' && sect[1] == 'n' && sect[2] == 't' && sect[3] == '_'))
 			{
-				key = conf->getKeyName(sect, j);
-				if(strcmp(key, "classname") && strcmp(key, "origin") && strcmp(key, "name") && strcmp(key, "rotation"))
+				if(!(pEnt = tmpList[i]))
 				{
-					pEnt->setKV(key, conf->getKey(sect, key));
+					continue;
 				}
-			}
-			pEnt->onPostLoad();
+				int keyc = conf->getKeyCount(sect);
+				const char *key;
+				for(int j = 0; j < keyc; ++j)
+				{
+					key = conf->getKeyName(sect, j);
+					if(strcmp(key, "classname") && strcmp(key, "origin") && strcmp(key, "name") && strcmp(key, "rotation"))
+					{
+						pEnt->setKV(key, conf->getKey(sect, key));
+					}
+				}
+				pEnt->onPostLoad();
 
-			if(/*(i & 0xF) == 0 && */pEventChannel)
+				if(/*(i & 0xF) == 0 && */pEventChannel)
+				{
+					ev.fProgress = (float)i / (float)ic * 0.9f + 0.1f;
+					pEventChannel->broadcastEvent(&ev);
+				}
+			}
+			else
 			{
-				ev.fProgress = (float)i / (float)ic * 0.9f + 0.1f;
-				pEventChannel->broadcastEvent(&ev);
+				tmpList[i] = NULL;
 			}
 		}
 	}
@@ -770,14 +779,14 @@ void CEntityManager::dumpList(int argc, const char **argv)
 		filter = argv[1];
 	}
 
-	printf(COLOR_GREEN "-----------------------------------------------------\n"
+	printf(COLOR_GREEN "---------------------------------------------------------------------------------------\n"
 		COLOR_GREEN "    Filter: " COLOR_LGREEN "%s\n"
 		COLOR_GREEN "    Total count: " COLOR_LGREEN "%u\n"
-		COLOR_GREEN "-----------------------------------------------------\n"
-		"  id  |          class           |       name       |\n"
-		"------|--------------------------|------------------|\n"
+		COLOR_GREEN "---------------------------------------------------------------------------------------\n"
+		"                  guid                  |          class           |       name       |\n"
+		"----------------------------------------|--------------------------|------------------|\n"
 		, filter, m_vEntList.size());
-
+	char tmp[64];
 	for(int i = 0, l = m_vEntList.size(); i < l; ++i)
 	{
 		CBaseEntity * pEnt = m_vEntList[i];
@@ -787,11 +796,12 @@ void CEntityManager::dumpList(int argc, const char **argv)
 		}
 		if(!filter[0] || strstr(pEnt->getClassName(), filter))
 		{
-			printf(" " COLOR_LGREEN "%-4d" COLOR_GREEN " | " COLOR_LGREEN "%-24s" COLOR_GREEN " | " COLOR_LGREEN "%-16s" COLOR_GREEN " |\n", i, pEnt->getClassName(), pEnt->getName());
+			XGUIDToSting(*pEnt->getGUID(), tmp, sizeof(tmp));
+			printf(" " COLOR_LGREEN "%s" COLOR_GREEN " | " COLOR_LGREEN "%-24s" COLOR_GREEN " | " COLOR_LGREEN "%-16s" COLOR_GREEN " |\n", tmp, pEnt->getClassName(), pEnt->getName());
 		}
 	}
 
-	printf("-----------------------------------------------------\n" COLOR_RESET);
+	printf("---------------------------------------------------------------------------------------\n" COLOR_RESET);
 }
 
 void CEntityManager::entKV(int argc, const char **argv)
@@ -811,6 +821,7 @@ void CEntityManager::entKV(int argc, const char **argv)
 	if(id < 0 || (UINT)id >= m_vEntList.size() || !(pEnt = m_vEntList[id]))
 	{
 		printf(COLOR_LRED "Invalid entity id\n" COLOR_RESET);
+		return;
 	}
 	char buf[128];
 	buf[0] = 0;
@@ -823,7 +834,7 @@ void CEntityManager::entKV(int argc, const char **argv)
 			{
 				for(int i = 0; i < pt->numFields; ++i)
 				{
-					if(pt->pData[i].szKey)
+					if(pt->pData[i].szKey && !(pt->pData[i].flags & PDFF_INPUT))
 					{
 						pEnt->getKV(pt->pData[i].szKey, buf, sizeof(buf));
 						printf("%s = %s\n", pt->pData[i].szKey, buf);
@@ -859,6 +870,12 @@ CBaseEntity* CEntityManager::getById(ID id)
 	return(pEnt ? (pEnt->getFlags() & EF_REMOVED ? NULL : pEnt) : NULL);
 }
 
+CBaseEntity* CEntityManager::getByGUID(const XGUID &guid)
+{
+	CBaseEntity *const *ppEnt = m_mEnts.at(guid);
+	return(ppEnt ? *ppEnt : NULL);
+}
+
 CBaseEntity* CEntityManager::cloneEntity(CBaseEntity *pOther)
 {
 	if(!pOther)
@@ -928,6 +945,8 @@ void CEntityManager::sheduleDestroy(CBaseEntity *pEnt)
 	{
 		pEnt->_releaseEditorBoxes();
 	}
+
+	pEnt->notifyPointers();
 }
 
 void CEntityManager::setEditorMode(bool isEditor)
@@ -1044,7 +1063,7 @@ CBaseline* CEntityManager::createBaseline(ID id)
 		if(pEnt && (pEnt->getFlags() & EF_LEVEL) && !(pEnt->getFlags() & EF_REMOVED))
 		{
 			CBaseline::ent_record_s record;
-			record.m_id = pEnt->getId();
+			record.m_guid = *pEnt->getGUID();
 			record.m_sClassname = pEnt->getClassName();
 
 			pDefaults = CEntityFactoryMap::GetInstance()->getDefaults(pEnt->getClassName());
@@ -1095,23 +1114,31 @@ void CEntityManager::dispatchBaseline(CBaseline *pBaseline)
 		return;
 	}
 
+#if 0
 	UINT idMax = pBaseline->m_aRecords[pBaseline->m_aRecords.size() - 1].m_id;
 	if(m_vEntList.size() <= idMax)
 	{
 		m_vEntList.reserve(idMax + 1);
 	}
+#endif
+
+	Array<CBaseEntity*> aPostLoadList(pBaseline->m_aRecords.size());
 
 	const AssotiativeArray<String, String>::Node *pNode;
 	for(int i = 0, l = pBaseline->m_aRecords.size(); i < l; ++i)
 	{
 		CBaseline::ent_record_s *pRecord = &pBaseline->m_aRecords[i];
 
-		if(!(pEnt = CREATE_ENTITY_NOPOST(pRecord->m_sClassname.c_str(), this)))
+		if(!(pEnt = CEntityFactoryMap::GetInstance()->create(pRecord->m_sClassname.c_str(), this, true, &pRecord->m_guid)))
 		{
 			printf(COLOR_LRED "Unable to load entity #%d, classname '%s' undefined\n" COLOR_RESET, i, pRecord->m_sClassname.c_str());
+			aPostLoadList[i] = NULL;
 			continue;
 		}
 
+		aPostLoadList[i] = pEnt;
+
+#if 0
 		if(pEnt->getId() != pRecord->m_id)
 		{
 			m_vEntList[pEnt->getId()] = NULL;
@@ -1144,6 +1171,7 @@ void CEntityManager::dispatchBaseline(CBaseline *pBaseline)
 			m_vEntList[pRecord->m_id] = pEnt;
 			pEnt->m_iId = pRecord->m_id;
 		}
+#endif
 
 		if(pRecord->m_mProps.KeyExists("name", &pNode))
 		{
@@ -1166,25 +1194,23 @@ void CEntityManager::dispatchBaseline(CBaseline *pBaseline)
 	{
 		CBaseline::ent_record_s *pRecord = &pBaseline->m_aRecords[i];
 
-		pEnt = m_vEntList[pRecord->m_id];
-		for(AssotiativeArray<String, String>::Iterator it = pRecord->m_mProps.begin(); it; it++)
+		if((pEnt = aPostLoadList[i]))
 		{
-			key = it.first->c_str();
-
-			if(strcmp(key, "origin") && strcmp(key, "name") && strcmp(key, "rotation"))
+			for(AssotiativeArray<String, String>::Iterator it = pRecord->m_mProps.begin(); it; it++)
 			{
-				pEnt->setKV(key, it.second->c_str());
+				key = it.first->c_str();
+
+				if(strcmp(key, "origin") && strcmp(key, "name") && strcmp(key, "rotation"))
+				{
+					pEnt->setKV(key, it.second->c_str());
+				}
 			}
 		}
 	}
 
-	for(int i = 1, l = m_vEntList.size(); i < l; ++i)
+	for(UINT i = 0, l = aPostLoadList.size(); i < l; ++i)
 	{
-		pEnt = m_vEntList[i];
-		if(pEnt)
-		{
-			pEnt->onPostLoad();
-		}
+		SAFE_CALL(aPostLoadList[i], onPostLoad);
 	}
 }
 
@@ -1256,3 +1282,88 @@ CBaseline *CEntityManager::deserializeBaseline(ID id, INETbuff *pBuf)
 	return(pBaseline);
 }
 #endif
+
+void CEntityManager::registerWaitForGUID(const XGUID &guid, IEntityPointer *pPtr)
+{
+	ScopedSpinLock lock(m_slWaitingPointers);
+
+	m_maWaitingPointers[guid].push_back(pPtr);
+}
+
+void CEntityManager::unregisterWaitForGUID(const XGUID &guid, IEntityPointer *pPtr)
+{
+	ScopedSpinLock lock(m_slWaitingPointers);
+
+	Array<IEntityPointer*> &list = m_maWaitingPointers[guid];
+
+	int idx = list.indexOf(pPtr);
+	assert(idx >= 0);
+	if(idx >= 0)
+	{
+		list.erase(idx);
+	}
+	if(!list.size())
+	{
+		m_maWaitingPointers.erase(guid);
+	}
+}
+
+void CEntityManager::notifyWaitForGUID(const XGUID &guid, CBaseEntity *pEnt)
+{
+	ScopedSpinLock lock(m_slWaitingPointers);
+
+	const Map<XGUID, Array<IEntityPointer*>>::Node *pNode;
+	if(m_maWaitingPointers.KeyExists(guid, &pNode))
+	{
+		Array<IEntityPointer*> &list = m_maWaitingPointers[guid];
+		for(UINT i = 0, l = list.size(); i < l; ++i)
+		{
+			list[i]->onWaitDone(pEnt);
+		}
+		m_maWaitingPointers.erase(guid);
+	}
+}
+
+void CEntityManager::registerWaitForName(const char *szName, CEntityList *pList)
+{
+	ScopedSpinLock lock(m_slWaitingLists);
+
+	Array<CEntityList*> &list = m_maWaitingLists[szName];
+
+	assert(list.indexOf(pList) < 0);
+
+	list.push_back(pList);
+}
+void CEntityManager::unregisterWaitForName(const char *szName, CEntityList *pList)
+{
+	ScopedSpinLock lock(m_slWaitingLists);
+
+	Array<CEntityList*> &list = m_maWaitingLists[szName];
+
+	int idx = list.indexOf(pList);
+	assert(idx >= 0);
+	list[idx] = list[list.size() - 1];
+	list.erase(list.size() - 1);
+}
+
+void CEntityManager::onEntityNameChanged(CBaseEntity *pEnt, const char *szOldName, const char *szNewName)
+{
+	const Map<String, Array<CEntityList*>>::Node *pNode;
+	if(szOldName[0] && m_maWaitingLists.KeyExists(szOldName, &pNode))
+	{
+		Array<CEntityList*> &list = *pNode->Val;
+		for(UINT i = 0, l = list.size(); i < l; ++i)
+		{
+			list[i]->removeEntity(pEnt);
+		}
+	}
+
+	if(szNewName[0] && m_maWaitingLists.KeyExists(szNewName, &pNode))
+	{
+		Array<CEntityList*> &list = *pNode->Val;
+		for(UINT i = 0, l = list.size(); i < l; ++i)
+		{
+			list[i]->addEntity(pEnt);
+		}
+	}
+}
diff --git a/source/game/EntityManager.h b/source/game/EntityManager.h
index 03cd994d3df1453b7708ab743569c6cf8f2e90bd..1444c9dede3c96560b45583a38bbb7003234b437 100644
--- a/source/game/EntityManager.h
+++ b/source/game/EntityManager.h
@@ -89,6 +89,9 @@ class CEntityManager
 
 	friend class CBaseEntity;
 	friend class CEntityFactoryMap;
+	template<typename T>
+	friend class CEntityPointer;
+	friend class CEntityList;
 public:
 	CEntityManager();
 	~CEntityManager();
@@ -122,7 +125,8 @@ public:
 	void entKV(int argc, const char **argv);
 
 	int getCount();
-	CBaseEntity* getById(ID id);
+	CBaseEntity *getById(ID id);
+	CBaseEntity *getByGUID(const XGUID &guid);
 
 	CBaseEntity* cloneEntity(CBaseEntity *pEnt);
 
@@ -143,16 +147,13 @@ public:
 #endif
 
 protected:
-	ID reg(CBaseEntity *pEnt);
-	void unreg(ID ent);
-
-	void regSync(CBaseEntity *pEnt);
-	void unregSync(CBaseEntity *pEnt);
+	const XGUID* reg(CBaseEntity *pEnt, const XGUID *pGUID=NULL);
+	void unreg(CBaseEntity *pEnt);
 
+	Map<XGUID, CBaseEntity*> m_mEnts;
 	Array<CBaseEntity*, 64> m_vEntList;
-	Array<CBaseEntity*, 64> m_vEntSyncList;
 	Array<CBaseEntity*> m_vEntRemoveList;
-	Array<ID> m_vFreeIDs;
+	Array<UINT> m_vFreeIDs;
 
 	Array<timeout_t> m_vTimeout;
 	Array<timeout_t> m_vInterval;
@@ -179,6 +180,20 @@ protected:
 
 private:
 	void finalRemove();
+
+	Map<XGUID, Array<IEntityPointer*>> m_maWaitingPointers;
+	SpinLock m_slWaitingPointers;
+	void registerWaitForGUID(const XGUID &guid, IEntityPointer *pPtr);
+	void unregisterWaitForGUID(const XGUID &guid, IEntityPointer *pPtr);
+	void notifyWaitForGUID(const XGUID &guid, CBaseEntity *pEnt);
+
+	bool m_isOldImported = false;
+
+	SpinLock m_slWaitingLists;
+	Map<String, Array<CEntityList*>> m_maWaitingLists;
+	void registerWaitForName(const char *szName, CEntityList *pList);
+	void unregisterWaitForName(const char *szName, CEntityList *pList);
+	void onEntityNameChanged(CBaseEntity *pEnt, const char *szOldName, const char *szNewName);
 };
 
 #endif
diff --git a/source/game/EntityPointer.h b/source/game/EntityPointer.h
new file mode 100644
index 0000000000000000000000000000000000000000..5a4a45efbda53ef29aaff41be5db1be3a67b8b66
--- /dev/null
+++ b/source/game/EntityPointer.h
@@ -0,0 +1,294 @@
+#ifndef __ENTITY_POINTER_H
+#define __ENTITY_POINTER_H
+
+#include <gdefines.h>
+
+class IEntityPointer
+{
+	friend class CBaseEntity;
+	friend class CEntityManager;
+
+private:
+	virtual void onTargetRemoved(CBaseEntity *pEnt) = 0;
+	virtual void onWaitDone(CBaseEntity *pEnt) = 0;
+};
+
+class IEntityPointerEvent
+{
+public:
+	virtual void onEvent(CBaseEntity *pEnt) = 0;
+};
+
+class CBaseEntity;
+class CEntityManager;
+template<typename T>
+class CEntityPointer: public IEntityPointer
+{
+	DECLARE_CLASS_NOBASE(CEntityPointer);
+	friend class CBaseEntity;
+public:
+	
+	CEntityPointer():
+		m_pfnCheckEntityType(&CEntityFactoryMap::IsEntityOfClass<T>)
+	{
+	}
+
+	~CEntityPointer()
+	{
+		SAFE_CALL(m_pEntity, unregisterPointer, this);
+
+		unregisterWait();
+	}
+
+	//! Установка имени или GUID связанного объекта
+	void setEntityName(const char *szName)
+	{
+		if(szName[0] == '{')
+		{
+			XGUID guid;
+			if(XGUIDFromString(&guid, szName))
+			{
+				setEntityGUID(guid);
+				return;
+			}
+		}
+
+		CBaseEntity *pEnt = ((CBaseEntity*)m_pThisEntity)->getEntByName(szName, NULL);
+
+		if(pEnt)
+		{
+			if(m_pfnCheckEntityType(pEnt))
+			{
+				setEntity(pEnt);
+			}
+			else
+			{
+				char tmp1[64], tmp2[64];
+				XGUIDToSting(m_guid, tmp1, sizeof(tmp1));
+				XGUIDToSting(*m_pThisEntity->getGUID(), tmp2, sizeof(tmp2));
+				LibReport(REPORT_MSG_LEVEL_ERROR, "Unable to link entity '%s' to entity '%s'. Invalid class %s\n", tmp1, tmp2, pEnt->getClassName());
+			}
+		}
+	}
+
+	//! Установка GUID
+	void setEntityGUID(const XGUID &guid)
+	{
+		CBaseEntity *pEnt = ((CBaseEntity*)m_pThisEntity)->m_pMgr->getByGUID(guid);
+		
+		if(pEnt)
+		{
+			if(m_pfnCheckEntityType(pEnt))
+			{
+				setEntity(pEnt);
+			}
+			else
+			{
+				char tmp1[64], tmp2[64];
+				XGUIDToSting(m_guid, tmp1, sizeof(tmp1));
+				XGUIDToSting(*m_pThisEntity->getGUID(), tmp2, sizeof(tmp2));
+				LibReport(REPORT_MSG_LEVEL_ERROR, "Unable to link entity '%s' to entity '%s'. Invalid class %s\n", tmp1, tmp2, pEnt->getClassName());
+			}
+		}
+		else
+		{
+			m_guid = guid;
+			registerWait();
+		}
+	}
+
+	//! Установка
+	void setEntity(T *pEnt)
+	{
+		if(m_pEntity != pEnt)
+		{
+			unregisterWait();
+
+			if(m_pEntity)
+			{
+				onLinkBroken(m_pEntity);
+			}
+			m_pEntity = pEnt;
+			if(pEnt)
+			{
+				m_guid = *pEnt->getGUID();
+			}
+			else
+			{
+				m_guid = XGUID();
+			}
+			if(m_pEntity)
+			{
+				onLinkEstablished(m_pEntity);
+			}
+		}
+	}
+
+	//! Получение указателя на объект
+	T* getEntity()
+	{
+		return(m_pEntity);
+	}
+
+	void getEntityName(char *szOutput, int iBufSize)
+	{
+		if(m_pEntity && m_pEntity->getName()[0])
+		{
+			if(((CBaseEntity*)m_pThisEntity)->m_pMgr->countEntityByName(m_pEntity->getName()) == 1)
+			{
+				strncpy(szOutput, m_pEntity->getName(), iBufSize);
+				szOutput[iBufSize - 1] = 0;
+				return;
+			}
+		}
+
+		if(m_guid == XGUID())
+		{
+			if(iBufSize)
+			{
+				szOutput[0] = 0;
+			}
+			return;
+		}
+
+		char tmp[64];
+		XGUIDToSting(m_guid, tmp, sizeof(tmp));
+		strncpy(szOutput, tmp, iBufSize);
+		szOutput[iBufSize - 1] = 0;
+	}
+	const XGUID& getGUID()
+	{
+		return(m_guid);
+	}
+
+	T* operator->()
+	{
+		return(getEntity());
+	}
+	operator T*()
+	{
+		return(getEntity());
+	}
+
+	CEntityPointer& operator=(T *pEnt)
+	{
+		setEntity(pEnt);
+		return(*this);
+	}
+
+	//! Вызывается при разрушении связи (pEnt -- указатель на объект, если причиной разрыва связи стало не удаление объекта)
+	template<typename F>
+	void setLinkBrokenListener(void(F::*func)(T*))
+	{
+		static_assert(std::is_base_of<CBaseEntity, F>::value, "F must be subclass of CBaseEntity");
+
+		m_pfnOnLinkBroken = (void(CBaseEntity::*)(T*))func;
+	}
+
+	//! Вызывается при установке связи
+	template<typename F>
+	void setLinkEstablishedListener(void(F::*func)(T*))
+	{
+		static_assert(std::is_base_of<CBaseEntity, F>::value, "F must be subclass of CBaseEntity");
+
+		m_pfnOnLinkEstablished = (void(CBaseEntity::*)(T*))func;
+	}
+
+	void setLinkBrokenListener(IEntityPointerEvent *pFunc)
+	{
+		m_pOnLinkBroken = pFunc;
+	}
+	void setLinkEstablishedListener(IEntityPointerEvent *pFunc)
+	{
+		m_pOnLinkEstablished = pFunc;
+	}
+	
+private:
+	XGUID m_guid;
+	T *m_pEntity = NULL;
+	CBaseEntity *m_pThisEntity = NULL;
+	bool(*m_pfnCheckEntityType)(CBaseEntity*) = NULL;
+
+	void(CBaseEntity::*m_pfnOnLinkEstablished)(T*) = NULL;
+	void(CBaseEntity::*m_pfnOnLinkBroken)(T*) = NULL;
+	IEntityPointerEvent *m_pOnLinkEstablished = NULL;
+	IEntityPointerEvent *m_pOnLinkBroken = NULL;
+
+	void init(CBaseEntity *pThisEntity)
+	{
+		m_pThisEntity = pThisEntity;
+	}
+
+	void onLinkBroken(T *pOldEnt)
+	{
+		if(m_pfnOnLinkBroken)
+		{
+			(m_pThisEntity->*m_pfnOnLinkBroken)(pOldEnt);
+		}
+		if(m_pOnLinkBroken)
+		{
+			m_pOnLinkBroken->onEvent(pOldEnt);
+		}
+	}
+	void onLinkEstablished(T *pNewEnt)
+	{
+		pNewEnt->registerPointer(this);
+
+		if(m_pfnOnLinkEstablished)
+		{
+			(m_pThisEntity->*m_pfnOnLinkEstablished)(pNewEnt);
+		}
+		if(m_pOnLinkEstablished)
+		{
+			m_pOnLinkEstablished->onEvent(pNewEnt);
+		}
+	}
+	void onTargetRemoved(CBaseEntity *pEnt) override
+	{
+		assert(pEnt == m_pEntity);
+
+		onLinkBroken(NULL);
+		m_pEntity = NULL;
+		registerWait();
+	}
+
+	bool m_isWaiting = false;
+	void registerWait()
+	{
+		if(!m_isWaiting)
+		{
+			((CBaseEntity*)m_pThisEntity)->m_pMgr->registerWaitForGUID(m_guid, this);
+			m_isWaiting = true;
+		}
+	}
+	void unregisterWait()
+	{
+		if(m_isWaiting)
+		{
+			((CBaseEntity*)m_pThisEntity)->m_pMgr->unregisterWaitForGUID(m_guid, this);
+			m_isWaiting = false;
+		}
+	}
+	void onWaitDone(CBaseEntity *pEnt) override
+	{
+		assert(m_isWaiting);
+
+		m_isWaiting = false;
+
+		if(m_pfnCheckEntityType(pEnt))
+		{
+			m_pEntity = (T*)pEnt;
+
+			onLinkEstablished((T*)pEnt);
+		}
+		else
+		{
+			char tmp1[64], tmp2[64];
+			XGUIDToSting(m_guid, tmp1, sizeof(tmp1));
+			XGUIDToSting(*m_pThisEntity->getGUID(), tmp2, sizeof(tmp2));
+			LibReport(REPORT_MSG_LEVEL_ERROR, "Unable to link entity '%s' to entity '%s'. Invalid class %s\n", tmp1, tmp2, pEnt->getClassName());
+		}
+	}
+};
+
+#endif
diff --git a/source/game/EnvSkybox.cpp b/source/game/EnvSkybox.cpp
index 6593000852727c61de2fd855bf5904e2e23e1279..2727e874a5bbe2bc3d2d6bc0a82968f9acd2f85a 100644
--- a/source/game/EnvSkybox.cpp
+++ b/source/game/EnvSkybox.cpp
@@ -24,8 +24,7 @@ END_PROPTABLE()
 
 REGISTER_ENTITY(CEnvSkybox, env_skybox);
 
-CEnvSkybox::CEnvSkybox(CEntityManager *pMgr):
-	BaseClass(pMgr)
+CEnvSkybox::CEnvSkybox()
 {
 	m_pAmbient = (IXAmbient*)Core_GetIXCore()->getPluginManager()->getInterface(IXAMBIENT_GUID);
 }
diff --git a/source/game/FuncRotating.cpp b/source/game/FuncRotating.cpp
index 1daa3f06133138012981a0a1c6e3b3637d6c2671..a1bd46b4f5599eab645af5364d5b90c8ed71efaa 100644
--- a/source/game/FuncRotating.cpp
+++ b/source/game/FuncRotating.cpp
@@ -19,11 +19,6 @@ END_PROPTABLE()
 
 REGISTER_ENTITY(CFuncRotating, func_rotating);
 
-CFuncRotating::CFuncRotating(CEntityManager * pMgr):
-	BaseClass(pMgr)
-{
-}
-
 CFuncRotating::~CFuncRotating()
 {
 	if(ID_VALID(m_idThinkInterval))
@@ -63,7 +58,7 @@ void CFuncRotating::toggle(inputdata_t *pInputdata)
 void CFuncRotating::think(float fDt)
 {
 	float3 fAxis = getOrient() * float3(0.0f, m_isReversed ? -1.0f : 1.0f, 0.0f);
-	setOrient(getOrient() * SMQuaternion(fAxis, m_fSpeed * fDt));
+	setOrient((getOrient() * SMQuaternion(fAxis, m_fSpeed * fDt)).Normalize());
 }
 
 void CFuncRotating::updateFlags()
diff --git a/source/game/FuncRotating.h b/source/game/FuncRotating.h
index 0caea4942bdfa1e6cf07ad31e44ac25f705780cb..8e4bf9127358cc6a3cf2577741f43b14510341b7 100644
--- a/source/game/FuncRotating.h
+++ b/source/game/FuncRotating.h
@@ -11,7 +11,7 @@ class CFuncRotating: public CPointEntity
 	DECLARE_CLASS(CFuncRotating, CPointEntity);
 	DECLARE_PROPTABLE();
 public:
-	DECLARE_CONSTRUCTOR();
+	DECLARE_TRIVIAL_CONSTRUCTOR();
 	~CFuncRotating();
 	
 protected:
diff --git a/source/game/FuncTrain.cpp b/source/game/FuncTrain.cpp
index 531f72f549ceaa01a31032897e1206ffd9a88022..550adde21b3ef0d56f6aae4c3b13c06a5e518e18 100644
--- a/source/game/FuncTrain.cpp
+++ b/source/game/FuncTrain.cpp
@@ -16,20 +16,11 @@ BEGIN_PROPTABLE(CFuncTrain)
 	DEFINE_FIELD_FLOAT(m_fSpeed, 0, "speed", "Move speed", EDITOR_TEXTFIELD)
 
 	//! path_corner, с которого начнется движение
-	DEFINE_FIELD_ENTITY2(CPathCorner, m_pStartStop, 0, "start", "Start point", EDITOR_TEXTFIELD)
+	DEFINE_FIELD_ENTITY(CPathCorner, m_pStartStop, 0, "start", "Start point", EDITOR_TEXTFIELD)
 END_PROPTABLE()
 
 REGISTER_ENTITY(CFuncTrain, func_train);
 
-CFuncTrain::CFuncTrain(CEntityManager * pMgr):
-	BaseClass(pMgr),
-	m_fSpeed(0.0f),
-	m_pStartStop(NULL),
-	m_bRunning(false),
-	m_fCurDist(0.0f)
-{
-}
-
 void CFuncTrain::onPostLoad()
 {
 	BaseClass::onPostLoad();
diff --git a/source/game/FuncTrain.h b/source/game/FuncTrain.h
index da64b30dc7f9411cb51431cddfcd71443a7f20b9..cc1630befc7d50117e8a94d1e57a27f1cd0d5299 100644
--- a/source/game/FuncTrain.h
+++ b/source/game/FuncTrain.h
@@ -12,8 +12,7 @@ See the license in LICENSE
 #define __FUNC_TRAIN_H
 
 #include "PointEntity.h"
-
-class CPathCorner;
+#include "PathCorner.h"
 
 /*! Поезда класс
 \ingroup cpointentity
@@ -23,7 +22,7 @@ class CFuncTrain: public CPointEntity
 	DECLARE_CLASS(CFuncTrain, CPointEntity);
 	DECLARE_PROPTABLE();
 public:
-	CFuncTrain(CEntityManager * pMgr);
+	DECLARE_TRIVIAL_CONSTRUCTOR();
 
 	//! Остановить
 	void stop();
@@ -31,24 +30,24 @@ public:
 	void start();
 
 protected:
-	void onPostLoad();
+	void onPostLoad() override;
 	void moveFunc(float dt);
 
 	//! Начальная точка движения
-	CPathCorner * m_pStartStop;
+	CEntityPointer<CPathCorner> m_pStartStop;
 	//! Текущая точка
-	CPathCorner * m_pCurStop;
+	CPathCorner *m_pCurStop = NULL;
 
 	//! Скорость
-	float m_fSpeed;
+	float m_fSpeed = 0.0f;
 	//! Текущая дистанция от начала пути
-	float m_fCurDist;
+	float m_fCurDist = 0.0f;
 
 	//! Запущен ли
-	bool m_bRunning;
+	bool m_bRunning = false;
 
 	//! ID таймера
-	ID m_iPostIval;
+	ID m_iPostIval = -1;
 };
 
 #endif
diff --git a/source/game/GameData.cpp b/source/game/GameData.cpp
index a8d93d1dbd081d26ad4860c07ee4794ef7e3a781..a026c74de1a3cff78d487fe975251f5816b22150 100644
--- a/source/game/GameData.cpp
+++ b/source/game/GameData.cpp
@@ -573,7 +573,9 @@ GameData::GameData(HWND hWnd, bool isGame):
 		CBaseEntity *pEnt;
 		if(sscanf(argv[1], "%p", &pEnt))
 		{
-			LibReport(REPORT_MSG_LEVEL_WARNING, "Ent: id:%d; cls:'%s'; name:'%s'\n", pEnt->getId(), pEnt->getClassName(), pEnt->getName());
+			char tmp[64];
+			XGUIDToSting(*pEnt->getGUID(), tmp, sizeof(tmp));
+			LibReport(REPORT_MSG_LEVEL_WARNING, "Ent: guid:%s; cls:'%s'; name:'%s'\n", tmp, pEnt->getClassName(), pEnt->getName());
 		}
 	});
 	
@@ -1322,7 +1324,7 @@ void GameData::render()
 					, g_uFPS,
 
 					pAdapterDesc->szDescription,
-					pAdapterDesc->sizeTotalMemory / 1024 / 1024,
+					(UINT)(pAdapterDesc->sizeTotalMemory / 1024 / 1024),
 
 					(float)(pMemoryStats->sizeIndexBufferBytes + pMemoryStats->sizeRenderTargetBytes + pMemoryStats->sizeShaderConstBytes + pMemoryStats->sizeTextureBytes + pMemoryStats->sizeVertexBufferBytes) / 1024.0f / 1024.0f,
 					(float)pMemoryStats->sizeTextureBytes / 1024.0f / 1024.0f,
diff --git a/source/game/LightDirectional.cpp b/source/game/LightDirectional.cpp
index 106198f4b5db20c06280b9f82e77c87aa9ef285d..d0ae981e3f5d54eb575c03b7fed1e3cf856cf073 100644
--- a/source/game/LightDirectional.cpp
+++ b/source/game/LightDirectional.cpp
@@ -14,14 +14,12 @@ BEGIN_PROPTABLE(CLightDirectional)
 	//! Внешний угол
 	DEFINE_FIELD_FLOAT(m_fOuterAngle, 0, "angle", "Outer angle", EDITOR_TEXTFIELD)
 	//! Внутренний угол
-	DEFINE_FIELD_FLOAT(m_fInnerAngle, 0, "inner_angle", "Inner angle", EDITOR_TEXTFIELD)
-	//! Верхний радиус
-	DEFINE_FIELD_FLOAT(m_fRadiusTop, 0, "radius_top", "Radius top", EDITOR_TEXTFIELD)
+	DEFINE_FIELD_FLOATFN(m_fInnerAngle, 0, "inner_angle", "Inner angle", setInnerAngle, EDITOR_TEXTFIELD)
 END_PROPTABLE()
 
 REGISTER_ENTITY(CLightDirectional, light_directional);
 
-CLightDirectional::CLightDirectional(CEntityManager *pMgr):BaseClass(pMgr)
+CLightDirectional::CLightDirectional()
 {
 	if(m_pLightSystem)
 	{
@@ -38,24 +36,30 @@ CLightDirectional::CLightDirectional(CEntityManager *pMgr):BaseClass(pMgr)
 	}
 }
 
-CLightDirectional::~CLightDirectional()
+void CLightDirectional::setOrient(const SMQuaternion &q)
 {
-	mem_release(m_pLight);
+	BaseClass::setOrient(q);
+
+	SAFE_CALL(m_pLightSpot, setDirection, q);
 }
 
-void CLightDirectional::onSync()
+void CLightDirectional::setOuterAngle(float fAngle)
 {
-	BaseClass::onSync();
+	m_fOuterAngle = fAngle;
 
-	if(m_pLightSpot)
-	{
-		m_pLightSpot->setDirection(m_vOrientation);
-		m_pLightSpot->setOuterAngle(m_fOuterAngle);
-		m_pLightSpot->setInnerAngle(m_fInnerAngle);
-	}
-#if 0
-	if (SLight_GetTopRadius(m_idLight) != m_fRadiusTop)
-		SLight_SetTopRadius(m_idLight, m_fRadiusTop);
-#endif
+	SAFE_CALL(m_pLightSpot, setOuterAngle, fAngle);
 }
+float CLightDirectional::getOuterAngle() const
+{
+	return m_fOuterAngle;
+}
+void CLightDirectional::setInnerAngle(float fAngle)
+{
+	m_fInnerAngle = fAngle;
 
+	SAFE_CALL(m_pLightSpot, setInnerAngle, fAngle);
+}
+float CLightDirectional::getInnerAngle() const
+{
+	return m_fInnerAngle;
+}
diff --git a/source/game/LightDirectional.h b/source/game/LightDirectional.h
index ba49edf9c54b301377216495d931f3c5d40dc660..c9e981194f2cda96e2c9ee649d8028dac928ee60 100644
--- a/source/game/LightDirectional.h
+++ b/source/game/LightDirectional.h
@@ -23,34 +23,17 @@ class CLightDirectional: public CBaseLight
 	DECLARE_PROPTABLE();
 public:
 	DECLARE_CONSTRUCTOR();
-	~CLightDirectional();
-
-	void setOuterAngle(float fAngle)
-	{
-		m_fOuterAngle = fAngle;
-	}
-	float getOuterAngle() const
-	{
-		return m_fOuterAngle;
-	}
-	void setInnerAngle(float fAngle)
-	{
-		m_fInnerAngle = fAngle;
-	}
-	float getInnerAngle() const
-	{
-		return m_fInnerAngle;
-	}
-
-	void setRadiusTop(float fRadiusTop) { m_fRadiusTop = fRadiusTop; };
-	float getRadiusTop() const { return m_fRadiusTop; };
-	
-protected:
-	void onSync() override;
 
+	void setOuterAngle(float fAngle);
+	float getOuterAngle() const;
+	void setInnerAngle(float fAngle);
+	float getInnerAngle() const;
+
+	void setOrient(const SMQuaternion &q) override;
+
+protected:
 	float m_fOuterAngle = SM_PI * 0.4f;
 	float m_fInnerAngle = SM_PI * 0.4f * 0.7f;
-	float m_fRadiusTop = 0.01f;
 
 	IXLightSpot *m_pLightSpot = NULL;
 };
diff --git a/source/game/LightPoint.cpp b/source/game/LightPoint.cpp
index 484a931ccfd3f23150a525975129c7839fc44cfb..dd08c1ea832595f2a281dd509762a18c416b5d2b 100644
--- a/source/game/LightPoint.cpp
+++ b/source/game/LightPoint.cpp
@@ -16,18 +16,12 @@ END_PROPTABLE()
 
 REGISTER_ENTITY(CLightPoint, light_point);
 
-CLightPoint::CLightPoint(CEntityManager * pMgr):BaseClass(pMgr)
+CLightPoint::CLightPoint()
 {
 	if(m_pLightSystem)
 	{
 		m_pLight = m_pLightSystem->newPoint();
-		//m_pLight->setDistance(m_fDist);
 		m_pLight->setColor(float4(float3(m_vColor) * m_vColor.w, m_fDist));
 	}
 }
 
-CLightPoint::~CLightPoint()
-{
-	mem_release(m_pLight);
-}
-
diff --git a/source/game/LightPoint.h b/source/game/LightPoint.h
index 5eeb62f983b5d4c08f003ef1ef51a3267a8d27a7..ecf3c0e0de384bebca697df97d30c428674a6855 100644
--- a/source/game/LightPoint.h
+++ b/source/game/LightPoint.h
@@ -23,7 +23,6 @@ class CLightPoint: public CBaseLight
 	DECLARE_PROPTABLE();
 public:
 	DECLARE_CONSTRUCTOR();
-	~CLightPoint();
 };
 
 #endif
diff --git a/source/game/LightSun.cpp b/source/game/LightSun.cpp
index c52dec51121541b4f63ff89cb7686778ee561aea..e4e1817806e9ea42c56f218eeb7ba47357375bad 100644
--- a/source/game/LightSun.cpp
+++ b/source/game/LightSun.cpp
@@ -16,7 +16,7 @@ END_PROPTABLE()
 
 REGISTER_ENTITY(CLightSun, light_sun);
 
-CLightSun::CLightSun(CEntityManager * pMgr):BaseClass(pMgr)
+CLightSun::CLightSun()
 {
 	if(m_pLightSystem)
 	{
@@ -25,17 +25,9 @@ CLightSun::CLightSun(CEntityManager * pMgr):BaseClass(pMgr)
 	}
 }
 
-CLightSun::~CLightSun()
+void CLightSun::setOrient(const SMQuaternion &q)
 {
-	mem_release(m_pLight);
-}
-
-void CLightSun::onSync()
-{
-	BaseClass::onSync();
+	BaseClass::setOrient(q);
 
-	if(m_pSun)
-	{
-		m_pSun->setDirection(m_vOrientation);
-	}
+	SAFE_CALL(m_pSun, setDirection, q);
 }
diff --git a/source/game/LightSun.h b/source/game/LightSun.h
index 08f933975d23dc475c2d4eddb0dd1f79cab97216..291b36f8d95a92e9a279830266199bdeaac06884 100644
--- a/source/game/LightSun.h
+++ b/source/game/LightSun.h
@@ -23,10 +23,10 @@ class CLightSun: public CBaseLight
 	DECLARE_PROPTABLE();
 public:
 	DECLARE_CONSTRUCTOR();
-	~CLightSun();
+
+	void setOrient(const SMQuaternion &q) override;
 
 protected:
-	void onSync() override;
 	IXLightSun *m_pSun = NULL;
 };
 
diff --git a/source/game/LogicAuto.cpp b/source/game/LogicAuto.cpp
index 332fd232fe16e518de08cebed35cef91684f9674..b01741d60975cc32d0857f1ccf092ca9b71fd5d0 100644
--- a/source/game/LogicAuto.cpp
+++ b/source/game/LogicAuto.cpp
@@ -20,11 +20,6 @@ END_PROPTABLE()
 
 REGISTER_ENTITY(CLogicAuto, logic_auto);
 
-CLogicAuto::CLogicAuto(CEntityManager * pMgr):
-	BaseClass(pMgr)
-{
-}
-
 void CLogicAuto::activate()
 {
 	SET_TIMEOUT(doTrigger, m_fDelay);
diff --git a/source/game/LogicAuto.h b/source/game/LogicAuto.h
index 445c91e327db420548225a5f9ede20ba92055226..2b6160e72b2120d9dc1379da37bcf90e844eac3f 100644
--- a/source/game/LogicAuto.h
+++ b/source/game/LogicAuto.h
@@ -8,7 +8,7 @@ class CLogicAuto: public CPointEntity
 	DECLARE_CLASS(CLogicAuto, CPointEntity);
 	DECLARE_PROPTABLE();
 public:
-	DECLARE_CONSTRUCTOR();
+	DECLARE_TRIVIAL_CONSTRUCTOR();
 	
 	void activate();
 
diff --git a/source/game/LogicRelay.cpp b/source/game/LogicRelay.cpp
index d467453432c66dc692ae849f8582e5a5ba32cdef..b4e66070be51a06364a25150135ea0adddd62999 100644
--- a/source/game/LogicRelay.cpp
+++ b/source/game/LogicRelay.cpp
@@ -29,12 +29,6 @@ END_PROPTABLE()
 
 REGISTER_ENTITY(CLogicRelay, logic_relay);
 
-CLogicRelay::CLogicRelay(CEntityManager * pMgr):
-	BaseClass(pMgr)
-{
-	m_isEnabled = true;
-}
-
 void CLogicRelay::turnOn(inputdata_t * pInputdata)
 {
 	m_isEnabled = true;
diff --git a/source/game/LogicRelay.h b/source/game/LogicRelay.h
index 89afdd9b1bed934b806f17e4e05570b38c12d933..05d976e762ad1df29e41a1522858169dbe082bb6 100644
--- a/source/game/LogicRelay.h
+++ b/source/game/LogicRelay.h
@@ -1,12 +1,12 @@
 
 /***********************************************************
-Copyright � Vitaliy Buturlin, Evgeny Danilovich, 2017, 2018
+Copyright © Vitaliy Buturlin, Evgeny Danilovich, 2017, 2018
 See the license in LICENSE
 ***********************************************************/
 
 /*!
 \file
-���������� ����
+Логическое реле
 */
 
 #ifndef __LOGIC_RELAY_H
@@ -16,7 +16,7 @@ See the license in LICENSE
 
 #define LOGIC_START_DISABLED ENT_FLAG_0
 
-/*! ���������� ����
+/*! Логическое реле
 \ingroup cpointentity
 */
 class CLogicRelay: public CPointEntity
@@ -24,7 +24,7 @@ class CLogicRelay: public CPointEntity
 	DECLARE_CLASS(CLogicRelay, CPointEntity);
 	DECLARE_PROPTABLE();
 public:
-	DECLARE_CONSTRUCTOR();
+	DECLARE_TRIVIAL_CONSTRUCTOR();
 	
 protected:
 	void turnOn(inputdata_t * pInputdata);
@@ -32,11 +32,11 @@ protected:
 	void trigger(inputdata_t * pInputdata);
 	void toggle(inputdata_t * pInputdata);
 
-	void onPostLoad();
+	void onPostLoad() override;
 
 	output_t m_onTrigger;
 
-	bool m_isEnabled;
+	bool m_isEnabled = true;
 };
 
 #endif
diff --git a/source/game/NPCBase.cpp b/source/game/NPCBase.cpp
index 7b5e7d3ea8cbbb0de130b85cdd265bd78c8fb5d0..4b715957f582b42b85407598f81e67ce4b5427eb 100644
--- a/source/game/NPCBase.cpp
+++ b/source/game/NPCBase.cpp
@@ -44,8 +44,7 @@ protected:
 	btCollisionObject* m_me;
 };
 
-CNPCBase::CNPCBase(CEntityManager * pMgr):
-	BaseClass(pMgr),
+CNPCBase::CNPCBase():
 	m_idQuadGoingTo(-1),
 	m_idFindPathInterval(-1),
 	m_idPathFollowInterval(-1),
@@ -112,6 +111,7 @@ void CNPCBase::setPos(const float3 &pos)
 	float3 tpos = pos;
 	m_idQuadCurr = SAIG_QuadGet(&tpos, true);
 
+#if 0
 	if(ID_VALID(m_idQuadCurr))
 	{
 		if(SAIG_QuadGetState(m_idQuadCurr) == AIQUAD_STATE_FREE)
@@ -128,13 +128,13 @@ void CNPCBase::setPos(const float3 &pos)
 				SAIG_QuadSetState(m_idQuadCurr, AIQUAD_STATE_BUSY);
 				SAIG_QuadSetStateWho(m_idQuadCurr, getId());
 				SAIG_QuadGetPos(m_idQuadCurr, &tpos);
-					tpos.y += 0.7f;
-					setPos(tpos);
+				tpos.y += 0.7f;
+				setPos(tpos);
 				return;
-				}
 			}
 		}
-
+	}
+#endif
 	if(ID_VALID(m_idQuadGoingTo))
 	{
 		m_idQuadGoingTo = -1;
@@ -224,7 +224,7 @@ void CNPCBase::findPathThinker(float fDelta)
 		m_aPathQuads.resize(iCount);
 		SAIG_GridGetPath(m_idQueueFindPath, &(m_aPathQuads[0]), m_aPathQuads.size(), true);
 		SAIG_GridSetColorArr(&(m_aPathQuads[0]), m_ulColor, m_aPathQuads.size());
-		m_vLastPathPos = m_vPosition;
+		m_vLastPathPos = getPos();
 		m_idQueueFindPath = -1;
 
 		CLEAR_INTERVAL(m_idFindPathInterval);
@@ -256,7 +256,7 @@ void CNPCBase::pathFollowThinker(float fDelta)
 
 	float fDirLen = fMoveSpeed * fDelta;
 	float fMovDirLen = fDirLen;
-	float fDist2 = SMVector3Length2(m_vLastPathPos - m_vPosition); // Расстояние между актуальным положением NPC и точкой следования
+	float fDist2 = SMVector3Length2(m_vLastPathPos - getPos()); // Расстояние между актуальным положением NPC и точкой следования
 	
 	if(m_iCurrQuaidInPath < (int)m_aPathQuads.size())
 	{
@@ -296,7 +296,7 @@ void CNPCBase::pathFollowThinker(float fDelta)
 	//m_vPosition = m_vLastPathPos;
 	//m_pGhostObject->getWorldTransform().setOrigin(F3_BTVEC(m_vLastPathPos));
 
-	float3 vDir = m_vLastPathPos - m_vPosition;
+	float3 vDir = m_vLastPathPos - getPos();
 	float fDist = SMVector3Length(vDir);
 	vDir /= fDist;
 
@@ -315,9 +315,9 @@ void CNPCBase::pathFollowThinker(float fDelta)
 	//SPhysics_GetDynWorld()->getDebugDrawer()->drawLine(F3_BTVEC(m_vLastPathPos), F3_BTVEC(m_vPosition), btVector3(0, 1, 0));
 
 	m_qOrientTo = SMQuaternion(NPC_BASE_DIR, vDir);
-	setOrient(SMquaternionSlerp(m_vOrientation, m_qOrientTo, clampf(fDelta, 0.1f, 1.0f)));
+	setOrient(SMquaternionSlerp(getOrient(), m_qOrientTo, clampf(fDelta, 0.1f, 1.0f)));
 
-	if(SMVector3Length(m_vPosition - m_vLastFramePos) < fDelta * fMoveSpeed * 0.1f) // застряли, похоже
+	if(SMVector3Length(getPos() - m_vLastFramePos) < fDelta * fMoveSpeed * 0.1f) // застряли, похоже
 	{
 		if(bMayJump)
 		{
@@ -346,7 +346,7 @@ void CNPCBase::pathFollowThinker(float fDelta)
 	{
 		m_iStuckCount = 0;
 	}
-	m_vLastFramePos = m_vPosition;
+	m_vLastFramePos = getPos();
 
 	// это последний, дошли!
 	if(m_iCurrQuaidInPath >= (int)m_aPathQuads.size() && fDist < 0.5)
@@ -568,6 +568,8 @@ void CNPCBase::stopOrientAt()
 	}
 }
 
+
+#if 0
 void CNPCBase::onSync()
 {
 	BaseClass::onSync();
@@ -589,7 +591,6 @@ void CNPCBase::onSync()
 	//SMQuaternion rot = m_pHeadEnt->getOrient();
 	//SPhysics_GetDynWorld()->getDebugDrawer()->drawLine(F3_BTVEC(m_pHeadEnt->getPos()), F3_BTVEC(m_pHeadEnt->getPos() + (rot * float3(0,0,1))), btVector3(1,1,1));
 }
-#if 0
 void CNPCBase::gridCheckBeyond()
 {
 	//находим ближайший квад к текущей позиции нпс
diff --git a/source/game/NPCBase.h b/source/game/NPCBase.h
index 20cc652c05ca4b7e38d9e1c84466c7f43b730d22..1f4ef794fd983bcc6033c6975dd769c00a05dbca 100644
--- a/source/game/NPCBase.h
+++ b/source/game/NPCBase.h
@@ -47,10 +47,8 @@ class CNPCBase: public CBaseCharacter
 	DECLARE_PROPTABLE();
 
 public:
-
 	SX_ALIGNED_OP_MEM();
-
-	CNPCBase(CEntityManager * pMgr);
+	DECLARE_CONSTRUCTOR();
 	~CNPCBase();
 
 	ID getAIQuad();	//!< id квада аи сетки на котором стоит нпс
@@ -74,8 +72,6 @@ public:
 	void stopOrientAt();
 
 protected:
-	void onSync();
-
 	//void think(float fDelta);
 
 	//! процедура проверки найденности пути
diff --git a/source/game/NPCZombie.cpp b/source/game/NPCZombie.cpp
index a021c37327bb63f1f24d96414f86a134b65e60f0..8359a23ff5f8fed36213a69dfcaefa92301ee7c0 100644
--- a/source/game/NPCZombie.cpp
+++ b/source/game/NPCZombie.cpp
@@ -21,8 +21,7 @@ END_PROPTABLE()
 
 REGISTER_ENTITY_NOLISTING(CNPCZombie, npc_zombie);
 
-CNPCZombie::CNPCZombie(CEntityManager * pMgr) :
-	BaseClass(pMgr),
+CNPCZombie::CNPCZombie():
 	m_stateDanger(NPC_STATE_DANGER_CALM),
 	m_iObserveRotateStep(0),
 	m_idRotateInterval(-1),
@@ -70,13 +69,11 @@ void CNPCZombie::onDeath(CBaseEntity *pAttacker, CBaseEntity *pInflictor)
 	m_pActiveTool->stopAction();
 }
 
-void CNPCZombie::onSync()
+void CNPCZombie::setPos(const float3 &pos)
 {
-	BaseClass::onSync();
-
-	SAFE_CALL(m_pSndIdle, setWorldPos, getPos());
-	SAFE_CALL(m_pSndIdle2, setWorldPos, getPos());
-	SAFE_CALL(m_pSndDeath, setWorldPos, getPos());
+	SAFE_CALL(m_pSndIdle, setWorldPos, pos);
+	SAFE_CALL(m_pSndIdle2, setWorldPos, pos);
+	SAFE_CALL(m_pSndDeath, setWorldPos, pos);
 }
 
 void CNPCZombie::rotateThink(float dt)
@@ -294,9 +291,12 @@ void CNPCZombie::randWalk()
 	{*/
 		float rndradius = randf(20.f, 40.f)*0.5f;
 		float3 rndpos;
-		rndpos.x = m_vPosition.x + randf(-rndradius, rndradius);
-		rndpos.y = m_vPosition.y + randf(-rndradius, rndradius);
-		rndpos.z = m_vPosition.z + randf(-rndradius, rndradius);
+
+		float3 vPos = getPos();
+
+		rndpos.x = vPos.x + randf(-rndradius, rndradius);
+		rndpos.y = vPos.y + randf(-rndradius, rndradius);
+		rndpos.z = vPos.z + randf(-rndradius, rndradius);
 
 		//Core_RFloat3Get(G_RI_FLOAT3_OBSERVER_POSITION, &rndpos);
 
diff --git a/source/game/NPCZombie.h b/source/game/NPCZombie.h
index 42b26a47ad8fac9469b25b3361df9e808c1fd5e7..44253c35f0ca667a0f75bc70c452d1e6d3c02554 100644
--- a/source/game/NPCZombie.h
+++ b/source/game/NPCZombie.h
@@ -33,17 +33,16 @@ class CNPCZombie: public CNPCBase
 	DECLARE_PROPTABLE();
 
 public:
-	CNPCZombie(CEntityManager * pMgr);
+	DECLARE_CONSTRUCTOR();
 	~CNPCZombie();
 
 	void onDeath(CBaseEntity *pAttacker, CBaseEntity *pInflictor);
 
 	void dispatchDamage(CTakeDamageInfo &takeDamageInfo);
 
-protected:
-
-	void onSync();
+	void setPos(const float3 & pos) override;
 
+protected:
 	void think(float fDelta);
 	void removeThis(float fDelta);
 
diff --git a/source/game/PathCorner.cpp b/source/game/PathCorner.cpp
index 726020c1186313f88e42fcf97af542d692896a70..a421a920c563f029f206284a56998d97e687eff8 100644
--- a/source/game/PathCorner.cpp
+++ b/source/game/PathCorner.cpp
@@ -21,20 +21,17 @@ BEGIN_PROPTABLE(CPathCorner)
 	DEFINE_FIELD_FLOAT(m_fNewSpeed, 0, "speed", "New speed", EDITOR_TEXTFIELD)
 
 	//! Следующая точка пути
-	DEFINE_FIELD_ENTITY2FN(CPathCorner, m_pNextStop, 0, "next", "Next stop", setNextPoint, EDITOR_TEXTFIELD)
+	DEFINE_FIELD_ENTITY(CPathCorner, m_pNextStop, 0, "next", "Next stop", EDITOR_TEXTFIELD)
+
+	DEFINE_FIELD_ENTITY(CPathCorner, m_pPrevStop, PDFF_NOEDIT | PDFF_NOEXPORT, "prev", "Prev stop", EDITOR_NONE)
 
 END_PROPTABLE()
 
 REGISTER_ENTITY(CPathCorner, path_corner);
 
-CPathCorner::CPathCorner(CEntityManager * pMgr):
-	BaseClass(pMgr),
-	m_type(PCT_SPLINE),
-	m_fNewSpeed(0.0f),
-	m_pNextStop(NULL),
-	m_pPrevStop(NULL),
-	m_fLength(0.0f)
+CPathCorner::CPathCorner()
 {
+	m_pNextStop.setLinkEstablishedListener(&CPathCorner::setNextPoint);
 }
 
 CPathCorner::~CPathCorner()
@@ -109,7 +106,7 @@ void CPathCorner::recalcPath(float t)
 		pCur->m_fLength = SMVector3Length(vec);
 		//pCur->m_fLength = 1.0f;
 		pCur->m_fH = (float3)(vec / pCur->m_fLength);
-		pCur->m_fCoeffsA = pCur->m_pNextStop->m_vPosition;
+		pCur->m_fCoeffsA = pCur->m_pNextStop->getPos();
 
 		pCur = pNext;
 	}
@@ -192,7 +189,7 @@ float3 CPathCorner::getPoint(float dist)
 		}
 		else
 		{
-			return(m_vPosition);
+			return(getPos());
 		}
 	}
 	else if(dist > m_fLength)
@@ -203,7 +200,7 @@ float3 CPathCorner::getPoint(float dist)
 		}
 		else
 		{
-			return(m_vPosition);
+			return(getPos());
 		}
 	}
 	dist -= m_fLength;
@@ -220,7 +217,7 @@ SMQuaternion CPathCorner::getRot(float dist)
 		}
 		else
 		{
-			return(m_vOrientation);
+			return(getOrient());
 		}
 	}
 	else if(dist > m_fLength)
@@ -231,16 +228,16 @@ SMQuaternion CPathCorner::getRot(float dist)
 		}
 		else
 		{
-			return(m_vOrientation);
+			return(getOrient());
 		}
 	}
 	if(m_pNextStop)
 	{
-		return(SMquaternionSlerp(m_vOrientation, m_pNextStop->m_vOrientation, (dist / m_fLength)*(dist / m_fLength) * (3.0f - 2.0f * (dist / m_fLength))));
+		return(SMquaternionSlerp(getOrient(), m_pNextStop->getOrient(), (dist / m_fLength)*(dist / m_fLength) * (3.0f - 2.0f * (dist / m_fLength))));
 	}
 	else
 	{
-		return(m_vOrientation);
+		return(getOrient());
 	}
 }
 
diff --git a/source/game/PathCorner.h b/source/game/PathCorner.h
index 6336ef2dad3ff81a54c49d196367b0d2583f97b8..2e67c98e19964cea56e672c6ae4c5d6973af0e9c 100644
--- a/source/game/PathCorner.h
+++ b/source/game/PathCorner.h
@@ -31,7 +31,7 @@ class CPathCorner: public CPointEntity
 	DECLARE_CLASS(CPathCorner, CPointEntity);
 	DECLARE_PROPTABLE();
 public:
-	CPathCorner(CEntityManager * pMgr);
+	DECLARE_CONSTRUCTOR();
 	~CPathCorner();
 
 	//! получает координаты точки на пути на расстоянии dist от начала
@@ -55,32 +55,32 @@ public:
 protected:
 	//! Пересчитывает путь
 	void recalcPath(float t);
-	void onPostLoad();
+	void onPostLoad() override;
 
 	//! Тип сглаживания
-	int m_type;
+	int m_type = PCT_SPLINE;
 	//! Новая скорость поезда
-	float m_fNewSpeed;
+	float m_fNewSpeed = 0.0f;
 
 	//! Длина сегмента пути
-	float m_fLength;
+	float m_fLength = 0.0f;
 
 	//! Для расчета сплайна @{
-	float3_t m_fH;
+	float3_t m_fH = 0.0f;
 
-	float3_t m_fCoeffsA;
-	float3_t m_fCoeffsB;
-	float3_t m_fCoeffsC;
-	float3_t m_fCoeffsD;
+	float3_t m_fCoeffsA = 0.0f;
+	float3_t m_fCoeffsB = 0.0f;
+	float3_t m_fCoeffsC = 0.0f;
+	float3_t m_fCoeffsD = 0.0f;
 
-	float3_t m_fDelta;
-	float3_t m_fLambda;
+	float3_t m_fDelta = 0.0f;
+	float3_t m_fLambda = 0.0f;
 	//! @}
 
 	//! Следующая точка
-	CPathCorner * m_pNextStop;
+	CEntityPointer<CPathCorner> m_pNextStop;
 	//! Предыдущая точка
-	CPathCorner * m_pPrevStop;
+	CEntityPointer<CPathCorner> m_pPrevStop;
 };
 
 #endif
diff --git a/source/game/Player.cpp b/source/game/Player.cpp
index ea356e0841ba38ef74824cd6ccfdb20723f9ce8c..d2f2782e21a8c0f987c60a844ce0a48a34549815 100644
--- a/source/game/Player.cpp
+++ b/source/game/Player.cpp
@@ -7,7 +7,6 @@ See the license in LICENSE
 #include <input/sxinput.h>
 #include "Player.h"
 #include "LightDirectional.h"
-#include "BaseTool.h"
 #include "BaseAmmo.h"
 
 #include "BaseWeapon.h"
@@ -29,17 +28,11 @@ END_PROPTABLE()
 
 REGISTER_ENTITY_NOLISTING(CPlayer, player);
 
-CPlayer::CPlayer(CEntityManager * pMgr):
-	BaseClass(pMgr),
-	m_canJump(true),
-	m_fViewbobStep(0.0f),
-	m_fViewbobY(0.0f),
-	m_fViewbobStrafe(float3_t(0, 0, 0)),
-	m_vWpnShakeAngles(float3_t(0.0f, 0.0f, 0.0f)),
-	m_iDSM(DSM_NONE),
-	m_bCanRespawn(false)
+void CPlayer::onPostLoad()
 {
-	m_pCamera = (CPointCamera*)CREATE_ENTITY("point_camera", pMgr);
+	BaseClass::onPostLoad();
+
+	m_pCamera = (CPointCamera*)CREATE_ENTITY("point_camera", m_pMgr);
 	m_pCamera->setPos(m_pHeadEnt->getPos());
 	m_pCamera->setParent(m_pHeadEnt);
 
@@ -102,7 +95,8 @@ void CPlayer::updateInput(float dt)
 		return;
 	}
 
-	m_vWpnShakeAngles = (float3)(m_vWpnShakeAngles * 0.4f);
+	// m_vWpnShakeAngles = (float3)(m_vWpnShakeAngles * 0.4f);
+	m_vWpnShakeAngles = (float3)(m_vWpnShakeAngles / (1.05f + dt));
 
 	if(!*editor_mode || SSInput_GetKeyState(SIM_LBUTTON))
 	{
@@ -209,7 +203,7 @@ void CPlayer::updateInput(float dt)
 
 		if(m_uMoveDir & PM_OBSERVER)
 		{
-			m_vPosition = (float3)(m_vPosition + m_pHeadEnt->getOrient() * (SMVector3Normalize(dir) * dt));
+			setPos(getPos() + m_pHeadEnt->getOrient() * (SMVector3Normalize(dir) * dt));
 		}
 		else
 		{
@@ -298,7 +292,7 @@ void CPlayer::updateInput(float dt)
 				float sin = cosf(m_fViewbobStep * 2.0f);
 				float sin2 = sinf(m_fViewbobStep);
 				float3 vec(1.0f, 0.0f, 0.0f);
-				vec = m_vOrientation * vec;
+				vec = getOrient() * vec;
 				m_fViewbobY = (sin * ((m_uMoveDir & PM_RUN) ? *cl_bob_run_y : *cl_bob_walk_y));
 				m_fViewbobStrafe = (float3)(vec * sin2 * ((m_uMoveDir & PM_RUN) ? *cl_bob_run_x : *cl_bob_walk_x));
 				//m_vOrientation = SMQuaternion(SMToRadian(10) * sinf(m_fViewbobStep), 'z') * m_vOrientation;
@@ -316,10 +310,12 @@ void CPlayer::updateInput(float dt)
 			m_vWpnShakeAngles.x = clampf(m_vWpnShakeAngles.x, -fMaxAng, fMaxAng);
 		}
 
-		GameData::m_pHUDcontroller->setPlayerPos(m_vPosition);
+		GameData::m_pHUDcontroller->setPlayerPos(getPos());
 
 	}
 
+	m_pActiveTool->setShakeRotation(SMQuaternion(m_vWpnShakeAngles.x, 'x') * SMQuaternion(m_vWpnShakeAngles.y, 'y') * SMQuaternion(m_vWpnShakeAngles.z, 'z'));
+
 #ifndef _SERVER
 	if(*grab_cursor && (!*editor_mode || SSInput_GetKeyState(SIM_LBUTTON)))
 	{
@@ -352,17 +348,17 @@ CPointCamera * CPlayer::getCamera()
 	return(m_pCamera);
 }
 
-void CPlayer::onSync()
+float3 CPlayer::getHeadOffset()
 {
-	BaseClass::onSync();
+	float3 vOffset = BaseClass::getHeadOffset();
 
-	if(m_uMoveDir & PM_OBSERVER)
+	if(!(m_uMoveDir & PM_OBSERVER))
 	{
-		return;
+		vOffset.y += m_fViewbobY;
+		vOffset += m_fViewbobStrafe;
 	}
 
-	m_vPosition.y += m_fViewbobY;
-	m_vPosition = (float3)(m_vPosition + m_fViewbobStrafe);
+	return(vOffset);
 }
 
 void CPlayer::observe()
@@ -391,7 +387,7 @@ void CPlayer::spawn()
 			m_pCrosshair->enable();
 
 			GameData::m_pHUDcontroller->setPlayerRot(m_vPitchYawRoll);
-			GameData::m_pHUDcontroller->setPlayerPos(m_vPosition);
+			GameData::m_pHUDcontroller->setPlayerPos(getPos());
 			GameData::m_pHUDcontroller->setPlayerHealth(m_fHealth);
 			return;
 		}
diff --git a/source/game/Player.h b/source/game/Player.h
index 22087408352d2eed90be18da590c10a9e7967650..9b4f3f7cc804a81de74695db152a44e3b346dcff 100644
--- a/source/game/Player.h
+++ b/source/game/Player.h
@@ -19,6 +19,7 @@ See the license in LICENSE
 #include "BaseCharacter.h"
 #include "PointCamera.h"
 #include "crosshair.h"
+#include "BaseTool.h"
 
 //! Класс игрока  \ingroup cbaseanimating
 class CPlayer: public CBaseCharacter
@@ -26,7 +27,7 @@ class CPlayer: public CBaseCharacter
 	DECLARE_CLASS(CPlayer, CBaseCharacter);
 	DECLARE_PROPTABLE();
 public:
-	CPlayer(CEntityManager * pMgr);
+	DECLARE_TRIVIAL_CONSTRUCTOR();
 	~CPlayer();
 	
 	//! Возвращает камеру игрока
@@ -45,8 +46,6 @@ public:
 
 	//! Обновляет инпут от игрока
 	virtual void updateInput(float dt);
-
-	void onSync();
 	
 	//! Получает смещения для задержки движения модели оружия при вращении игрока
 	float3_t & getWeaponDeltaAngles();
@@ -84,24 +83,28 @@ protected:
 	ID m_iUpdIval;
 
 	//! Может ли прыгать
-	bool m_canJump;
+	bool m_canJump = true;
 
 	//! Для качания камеры @{
-	float m_fViewbobStep;
-	float m_fViewbobY;
-	float3_t m_fViewbobStrafe;
-	float3_t m_vWpnShakeAngles;
+	float m_fViewbobStep = 0.0f;
+	float m_fViewbobY = 0.0f;
+	float3_t m_fViewbobStrafe = float3_t(0.0f, 0.0f, 0.0f);
+	float3_t m_vWpnShakeAngles = float3_t(0.0f, 0.0f, 0.0f);
 	//! @}
 
-	int m_iDSM;
+	int m_iDSM = DSM_NONE;
 
 	//! Перекрестие
-	CCrosshair * m_pCrosshair;
+	CCrosshair *m_pCrosshair = NULL;
 
 	//! Обновляет разброса значение
 	virtual void updateSpread(float dt);
 
-	bool m_bCanRespawn;
+	void onPostLoad() override;
+
+	bool m_bCanRespawn = false;
+
+	float3 getHeadOffset() override;
 };
 
 #endif
diff --git a/source/game/PointCamera.cpp b/source/game/PointCamera.cpp
index 77bfcee3e82b15f143fe861596978305702eab2c..addfa707908944d2731e4aeb19259434fcdd976e 100644
--- a/source/game/PointCamera.cpp
+++ b/source/game/PointCamera.cpp
@@ -16,8 +16,7 @@ END_PROPTABLE()
 
 REGISTER_ENTITY(CPointCamera, point_camera);
 
-CPointCamera::CPointCamera(CEntityManager * pMgr):
-	BaseClass(pMgr)
+CPointCamera::CPointCamera()
 {
 	const float * r_default_fov = GET_PCVAR_FLOAT("r_default_fov");
 	m_pSXC = SGCore_CrCamera();
@@ -29,15 +28,21 @@ CPointCamera::~CPointCamera()
 	mem_release(m_pSXC);
 }
 
-ICamera * CPointCamera::getCamera()
+ICamera* CPointCamera::getCamera()
 {
 	return(m_pSXC);
 }
 
-void CPointCamera::onSync()
+void CPointCamera::setPos(const float3 &pos)
 {
-	BaseClass::onSync();
+	BaseClass::setPos(pos);
 
-	m_pSXC->setPosition(m_vPosition);
-	m_pSXC->setOrientation(m_vOrientation);
+	m_pSXC->setPosition(pos);
+}
+
+void CPointCamera::setOrient(const SMQuaternion &q)
+{
+	BaseClass::setOrient(q);
+
+	m_pSXC->setOrientation(q);
 }
diff --git a/source/game/PointCamera.h b/source/game/PointCamera.h
index ed21f4fb31be8cf9964d554c2bbdc8728f41ffd3..154a81e4a830e28db6e7a36499457af4a93d8476 100644
--- a/source/game/PointCamera.h
+++ b/source/game/PointCamera.h
@@ -26,16 +26,17 @@ class CPointCamera: public CPointEntity
 	DECLARE_CLASS(CPointCamera, CPointEntity);
 	DECLARE_PROPTABLE();
 public:
-	CPointCamera(CEntityManager * pMgr);
+	DECLARE_CONSTRUCTOR();
 	~CPointCamera();
 
 	//! Возвращает объект камеры из графической либы
-	ICamera * getCamera();
+	ICamera* getCamera();
 
-protected:
-	ICamera * m_pSXC;
+	void setPos(const float3 &pos) override;
+	void setOrient(const SMQuaternion &q) override;
 
-	void onSync();
+protected:
+	ICamera *m_pSXC;
 };
 
 #endif
diff --git a/source/game/PropBreakable.h b/source/game/PropBreakable.h
index 5209a0c5275823d8accd370a985cec2d11fef847..bc00d2aa0906c95eff56a981a9293acf87b2e49b 100644
--- a/source/game/PropBreakable.h
+++ b/source/game/PropBreakable.h
@@ -24,7 +24,7 @@ class CPropBreakable: public CPropDynamic
 public:
 	DECLARE_TRIVIAL_CONSTRUCTOR();
 	~CPropBreakable();
-	virtual void onPostLoad();
+	void onPostLoad() override;
 
 	void onDeath(CBaseEntity *pAttacker, CBaseEntity *pInflictor);
 protected:
diff --git a/source/game/PropButton.cpp b/source/game/PropButton.cpp
index aecf975d4177815cb4b49ae0449e97be356c8484..730847d5e9f311569bdef273e48608ecca405186 100644
--- a/source/game/PropButton.cpp
+++ b/source/game/PropButton.cpp
@@ -45,14 +45,6 @@ END_PROPTABLE()
 
 REGISTER_ENTITY(CPropButton, prop_button);
 
-CPropButton::CPropButton(CEntityManager * pMgr):
-	BaseClass(pMgr)
-{
-	m_isEnabled = true;
-	m_isToggleable = false;
-	m_bState = false;
-}
-
 void CPropButton::turnOn(inputdata_t * pInputdata)
 {
 	m_isEnabled = true;
diff --git a/source/game/PropButton.h b/source/game/PropButton.h
index 3a4315000269056a647d82dc6d95a3f4e081b815..887d7b6d507869d52eaa5257b52434f7daecfef2 100644
--- a/source/game/PropButton.h
+++ b/source/game/PropButton.h
@@ -1,12 +1,12 @@
 
 /***********************************************************
-Copyright � Vitaliy Buturlin, Evgeny Danilovich, 2017, 2018
+Copyright © Vitaliy Buturlin, Evgeny Danilovich, 2017, 2018
 See the license in LICENSE
 ***********************************************************/
 
 /*!
 \file
-������
+Кнопка
 */
 
 #ifndef __PROP_BUTTON_H
@@ -18,7 +18,7 @@ See the license in LICENSE
 #define BUTTON_TOGGLEABLE ENT_FLAG_1
 #define BUTTON_START_PRESSED ENT_FLAG_2
 
-/*! ������
+/*! Кнопка
 \ingroup cbaseanimating
 */
 class CPropButton: public CPropDynamic
@@ -26,19 +26,19 @@ class CPropButton: public CPropDynamic
 	DECLARE_CLASS(CPropButton, CPropDynamic);
 	DECLARE_PROPTABLE();
 public:
-	DECLARE_CONSTRUCTOR();
+	DECLARE_TRIVIAL_CONSTRUCTOR();
 
 	void onUse(CBaseEntity *pUser);
 
 protected:
-	void turnOn(inputdata_t * pInputdata);
-	void turnOff(inputdata_t * pInputdata);
-	void press(inputdata_t * pInputdata);
-	void pushUp(inputdata_t * pInputdata);
-	void pushDown(inputdata_t * pInputdata);
-	void toggle(inputdata_t * pInputdata);
+	void turnOn(inputdata_t *pInputdata);
+	void turnOff(inputdata_t *pInputdata);
+	void press(inputdata_t *pInputdata);
+	void pushUp(inputdata_t *pInputdata);
+	void pushDown(inputdata_t *pInputdata);
+	void toggle(inputdata_t *pInputdata);
 
-	void onPostLoad();
+	void onPostLoad() override;
 
 	output_t m_onPressed;
 	output_t m_onPushUp;
@@ -46,10 +46,10 @@ protected:
 	output_t m_onToggle;
 	output_t m_onUseDisabled;
 
-	bool m_isEnabled;
-	bool m_isToggleable;
+	bool m_isEnabled = true;
+	bool m_isToggleable = false;
 
-	bool m_bState;
+	bool m_bState = false;
 };
 
 #endif
diff --git a/source/game/PropDebris.cpp b/source/game/PropDebris.cpp
index 210fe2329e802889b5f049e292bc881e769b8cdf..f6137b7c81343a0355e8a6d69b01d8766cbf2a7a 100644
--- a/source/game/PropDebris.cpp
+++ b/source/game/PropDebris.cpp
@@ -15,7 +15,7 @@ END_PROPTABLE()
 
 REGISTER_ENTITY(CPropDebris, prop_debris);
 
-CPropDebris::CPropDebris(CEntityManager *pMgr):BaseClass(pMgr)
+CPropDebris::CPropDebris()
 {
 	setCollisionGroup(CG_DEBRIS);
 }
@@ -30,7 +30,8 @@ void CPropDebris::sheduleRemove()
 
 void CPropDebris::checkRemove(float fDT)
 {
-	//@TODO: Reimplement me
+	REMOVE_ENTITY(this);
+	// TODO Reimplement me
 #if 0
 	if(!m_pAnimPlayer->isVisibleFor(SX_ANIM_DEFAULT_VISCALCOBJ))
 	{
diff --git a/source/game/PropDoor.cpp b/source/game/PropDoor.cpp
index e07700ea403f76af505764f7b86fcbc5b183e91a..f9532aa51acd53f1e32e08de39678ede64a37b69 100644
--- a/source/game/PropDoor.cpp
+++ b/source/game/PropDoor.cpp
@@ -68,10 +68,6 @@ END_PROPTABLE()
 
 REGISTER_ENTITY(CPropDoor, prop_door);
 
-CPropDoor::CPropDoor(CEntityManager *pMgr):BaseClass(pMgr)
-{
-}
-
 CPropDoor::~CPropDoor()
 {
 	releasePhysics();
@@ -221,8 +217,11 @@ void CPropDoor::createPhysBody()
 {
 	if(m_pCollideShape)
 	{
+		float3 vPos = getPos();
+		SMQuaternion qRot = getOrient();
+
 		m_pGhostObject = new btPairCachingGhostObject();
-		m_pGhostObject->setWorldTransform(btTransform(Q4_BTQUAT(m_vOrientation), F3_BTVEC(m_vPosition)));
+		m_pGhostObject->setWorldTransform(btTransform(Q4_BTQUAT(qRot), F3_BTVEC(vPos)));
 		m_pGhostObject->setCollisionShape(m_pCollideShape);
 		m_pGhostObject->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
 		m_pGhostObject->setUserPointer(this);
@@ -269,7 +268,7 @@ void CPropDoor::createPhysBody()
 			m_fDistance = fMax - fMin;
 		}
 
-		m_vStartPos = m_vPosition;
+		m_vStartPos = vPos;
 		m_vEndPos = (float3)(m_vStartPos + vDir * m_fDistance);
 
 		if(m_bState)
diff --git a/source/game/PropDoor.h b/source/game/PropDoor.h
index 28ce7e953bf7d8f2cd99a1d082bb357504267a29..c239e8c0c76625ee089b2fe41d8062eac252d54e 100644
--- a/source/game/PropDoor.h
+++ b/source/game/PropDoor.h
@@ -33,9 +33,10 @@ class CPropDoor: public CPropDynamic
 	DECLARE_CLASS(CPropDoor, CPropDynamic);
 	DECLARE_PROPTABLE();
 public:
-	DECLARE_CONSTRUCTOR();
+	DECLARE_TRIVIAL_CONSTRUCTOR();
 	~CPropDoor();
-	virtual void onPostLoad();
+
+	void onPostLoad() override;
 
 	void onUse(CBaseEntity *pUser);
 
diff --git a/source/game/PropStatic.cpp b/source/game/PropStatic.cpp
index 75ca87b30bea5099135ebcd984ba449030f7ab8f..4305c48ba0f79244e6f614ddac5980e719a66553 100644
--- a/source/game/PropStatic.cpp
+++ b/source/game/PropStatic.cpp
@@ -18,10 +18,9 @@ BEGIN_PROPTABLE(CPropStatic)
 	EDITOR_COMBO_END()
 END_PROPTABLE()
 
-REGISTER_ENTITY_NOSYNC(CPropStatic, prop_static);
+REGISTER_ENTITY(CPropStatic, prop_static);
 
-CPropStatic::CPropStatic(CEntityManager *pMgr):
-	BaseClass(pMgr)
+CPropStatic::CPropStatic()
 {
 	m_isStatic = true;
 }
@@ -35,7 +34,10 @@ void CPropStatic::createPhysBody()
 {
 	if(m_pCollideShape)
 	{
-		btDefaultMotionState * motionState = new btDefaultMotionState(btTransform(Q4_BTQUAT(m_vOrientation), F3_BTVEC(m_vPosition)));
+		float3 vPos = getPos();
+		SMQuaternion qRot = getOrient();
+
+		btDefaultMotionState * motionState = new btDefaultMotionState(btTransform(Q4_BTQUAT(qRot), F3_BTVEC(vPos)));
 		btRigidBody::btRigidBodyConstructionInfo rigidBodyCI(
 			0,                  // mass
 			motionState,        // initial position
diff --git a/source/game/SoundEmitter.cpp b/source/game/SoundEmitter.cpp
index 1ec6f3fc69b606de4e44cbb9f908e7751667da91..23a641f76bff401bb8dad4c77203432300b5c55c 100644
--- a/source/game/SoundEmitter.cpp
+++ b/source/game/SoundEmitter.cpp
@@ -15,10 +15,10 @@ BEGIN_PROPTABLE(CSoundEmitter)
 	DEFINE_FIELD_STRINGFN(m_szPathSound, 0, "file", "Sound file", setSound, EDITOR_SOUND)
 
 	//! Громкость
-	DEFINE_FIELD_FLOAT(m_fVolume, 0, "volume", "Volume", EDITOR_TEXTFIELD)
+	DEFINE_FIELD_FLOATFN(m_fVolume, 0, "volume", "Volume", setVolume, EDITOR_TEXTFIELD)
 
 	//! Дистанция слышимости
-	DEFINE_FIELD_FLOAT(m_fDist, 0, "distance", "Hearing distance", EDITOR_TEXTFIELD)
+	DEFINE_FIELD_FLOATFN(m_fDist, 0, "distance", "Hearing distance", setDistance, EDITOR_TEXTFIELD)
 	
 	//! Включить
 	DEFINE_INPUT(play, "play", "Play", PDF_NONE)
@@ -39,12 +39,6 @@ REGISTER_ENTITY(CSoundEmitter, sound_emitter);
 
 //##########################################################################
 
-CSoundEmitter::CSoundEmitter(CEntityManager *pMgr):
-	BaseClass(pMgr)
-{
-	
-}
-
 CSoundEmitter::~CSoundEmitter()
 {
 	mem_release(m_pEmitter);
@@ -54,8 +48,10 @@ CSoundEmitter::~CSoundEmitter()
 
 void CSoundEmitter::setSound(const char *szSound)
 {
-	if(!m_pEmitter || fstrcmp(m_pEmitter->getName(), szSound) != 0)
+	if(!m_pEmitter || fstrcmp(m_szPathSound, szSound) != 0)
 	{
+		_setStrVal(&m_szPathSound, szSound);
+
 		mem_release(m_pEmitter);
 		IXSoundSystem *pSound = (IXSoundSystem*)(Core_GetIXCore()->getPluginManager()->getInterface(IXSOUNDSYSTEM_GUID));
 		IXSoundLayer *pGameLayer = pSound->findLayer("xGame");
@@ -65,34 +61,50 @@ void CSoundEmitter::setSound(const char *szSound)
 
 		if(m_pEmitter)
 		{
-			_setStrVal(&m_szPathSound, szSound);
 			m_pEmitter->setVolume(m_fVolume);
+			m_pEmitter->setWorldPos(getPos());
+			m_pEmitter->setDistance(m_fDist);
 		}
 	}
 }
 
 //##########################################################################
 
-void CSoundEmitter::onSync()
+void CSoundEmitter::setPos(const float3 &pos)
 {
-	BaseClass::onSync();
-	if(!m_pEmitter)
-		return;
+	BaseClass::setPos(pos);
 
-	float3 vPos = getPos();
-	m_pEmitter->setWorldPos(vPos);
+	SAFE_CALL(m_pEmitter, setWorldPos, pos);
+}
 
-	m_pEmitter->setVolume(m_fVolume);
+void CSoundEmitter::setVolume(float fVolume)
+{
+	m_fVolume = fVolume;
+
+	SAFE_CALL(m_pEmitter, setVolume, fVolume);
+}
+float CSoundEmitter::getVolume()
+{
+	return(m_fVolume);
+}
+
+void CSoundEmitter::setDistance(float fDistance)
+{
+	m_fDist = fDistance;
+
+	SAFE_CALL(m_pEmitter, setDistance, fDistance);
+}
+float CSoundEmitter::getDistance()
+{
+	return(m_fDist);
 }
 
 //##########################################################################
 
 void CSoundEmitter::play(inputdata_t * pInputdata)
 {
-	if(m_pEmitter)
-	{
-		m_pEmitter->play();
-	}
+	SAFE_CALL(m_pEmitter, play);
+
 	FIRE_OUTPUT(m_onTurnOn, pInputdata->pInflictor);
 }
 
@@ -105,7 +117,7 @@ void CSoundEmitter::updateFlags()
 	if(!m_pEmitter)
 		return;
 
-	if (getFlags() & SND_EMITTER_TYPE_AMBIENT)
+	if(getFlags() & SND_EMITTER_TYPE_AMBIENT)
 	{
 		m_pEmitter->setSpace(SOUND_SPACE_2D);
 	}
diff --git a/source/game/SoundEmitter.h b/source/game/SoundEmitter.h
index c96e49165363380f2099147ec0dca2cd3ae886a5..10271cd8d81f2c12e6781a2bbe6a2e489fb4a2fa 100644
--- a/source/game/SoundEmitter.h
+++ b/source/game/SoundEmitter.h
@@ -29,15 +29,20 @@ class CSoundEmitter: public CPointEntity
 	DECLARE_CLASS(CSoundEmitter, CPointEntity);
 	DECLARE_PROPTABLE();
 public:
-	CSoundEmitter(CEntityManager * pMgr);
+	DECLARE_TRIVIAL_CONSTRUCTOR();
 	~CSoundEmitter();
 
-	virtual void setSound(const char *szSound);
+	void setSound(const char *szSound);
 
-	void onSync() override;
+	void setPos(const float3 &pos) override;
 
-protected:
+	void setVolume(float fVolume);
+	float getVolume();
+
+	void setDistance(float fDistance);
+	float getDistance();
 
+protected:
 	void updateFlags() override;
 
 	void play(inputdata_t *pInputdata);
diff --git a/source/game/SoundPlayer.cpp b/source/game/SoundPlayer.cpp
index 50c83755b885332c5259b59ddff73259c8f434b0..7b835981d8b9116a1c20aad5b94d31300e8c266c 100644
--- a/source/game/SoundPlayer.cpp
+++ b/source/game/SoundPlayer.cpp
@@ -15,13 +15,13 @@ BEGIN_PROPTABLE(CSoundPlayer)
 	DEFINE_FIELD_STRINGFN(m_szPathSound, 0, "file", "Sound file", setSound, EDITOR_SOUND)
 
 	//! Громкость
-	DEFINE_FIELD_FLOAT(m_fVolume, 0, "volume", "Volume", EDITOR_TEXTFIELD)
+	DEFINE_FIELD_FLOATFN(m_fVolume, 0, "volume", "Volume", setVolume, EDITOR_TEXTFIELD)
 
 	//! Дистанция слышимости
-	DEFINE_FIELD_FLOAT(m_fDist, 0, "distance", "Hearing distance", EDITOR_TEXTFIELD)
+	DEFINE_FIELD_FLOATFN(m_fDist, 0, "distance", "Hearing distance", setDistance, EDITOR_TEXTFIELD)
 
 	//! Зацикливание
-	DEFINE_FIELD_INT(m_iLoop, 0, "loop", "Loop", EDITOR_COMBOBOX)
+	DEFINE_FIELD_INTFN(m_iLoop, 0, "loop", "Loop", setLoop, EDITOR_COMBOBOX)
 		COMBO_OPTION("None", "0")		//!< Нет
 		COMBO_OPTION("Simple", "1")		//!< Простое (могут быть пустоты на стыках конца с началом)
 		COMBO_OPTION("Seamless", "2")	//!< Непрерывное (пустот не будет, все будет заполнено звуком)
@@ -51,12 +51,6 @@ REGISTER_ENTITY(CSoundPlayer, sound_player);
 
 //##########################################################################
 
-CSoundPlayer::CSoundPlayer(CEntityManager *pMgr):
-	BaseClass(pMgr)
-{
-	
-}
-
 CSoundPlayer::~CSoundPlayer()
 {
 	mem_release(m_pPlayer);
@@ -66,8 +60,10 @@ CSoundPlayer::~CSoundPlayer()
 
 void CSoundPlayer::setSound(const char *szSound)
 {
-	if(!m_pPlayer || fstrcmp(m_pPlayer->getName(), szSound) != 0)
+	if(!m_pPlayer || fstrcmp(m_szPathSound, szSound) != 0)
 	{
+		_setStrVal(&m_szPathSound, szSound);
+
 		mem_release(m_pPlayer);
 		IXSoundSystem *pSound = (IXSoundSystem*)(Core_GetIXCore()->getPluginManager()->getInterface(IXSOUNDSYSTEM_GUID));
 		IXSoundLayer *pGameLayer = pSound->findLayer("xGame");
@@ -77,9 +73,10 @@ void CSoundPlayer::setSound(const char *szSound)
 
 		if(m_pPlayer)
 		{
-			_setStrVal(&m_szPathSound, szSound);
 			m_pPlayer->setLoop((SOUND_LOOP)m_iLoop);
 			m_pPlayer->setVolume(m_fVolume);
+			m_pPlayer->setDistance(m_fDist);
+			m_pPlayer->setWorldPos(getPos());
 
 			if(getFlags() & SND_PLAYER_START_PLAYED)
 				m_pPlayer->play();
@@ -89,20 +86,43 @@ void CSoundPlayer::setSound(const char *szSound)
 
 //##########################################################################
 
-void CSoundPlayer::onSync()
+void CSoundPlayer::setPos(const float3 &pos)
 {
-	BaseClass::onSync();
-	if (!m_pPlayer)
-		return;
+	BaseClass::setPos(pos);
+
+	SAFE_CALL(m_pPlayer, setWorldPos, pos);
+}
+
+void CSoundPlayer::setVolume(float fVolume)
+{
+	m_fVolume = fVolume;
 
-	float3 vPos = getPos();
-	m_pPlayer->setWorldPos(vPos);
+	SAFE_CALL(m_pPlayer, setVolume, fVolume);
+}
+float CSoundPlayer::getVolume()
+{
+	return(m_fVolume);
+}
 
-	if (m_pPlayer->getLoop() != (SOUND_LOOP)m_iLoop)
-		m_pPlayer->setLoop((SOUND_LOOP)m_iLoop);
+void CSoundPlayer::setDistance(float fDistance)
+{
+	m_fDist = fDistance;
 
-	if (m_pPlayer->getVolume() != m_fVolume)
-		m_pPlayer->setVolume(m_fVolume);
+	SAFE_CALL(m_pPlayer, setDistance, fDistance);
+}
+float CSoundPlayer::getDistance()
+{
+	return(m_fDist);
+}
+
+void CSoundPlayer::setLoop(int iLoop)
+{
+	m_iLoop = iLoop;
+	SAFE_CALL(m_pPlayer, setLoop, (SOUND_LOOP)iLoop);
+}
+SOUND_LOOP CSoundPlayer::getLoop()
+{
+	return((SOUND_LOOP)m_iLoop);
 }
 
 //##########################################################################
diff --git a/source/game/SoundPlayer.h b/source/game/SoundPlayer.h
index 550095ee1675c17c6ad7a71c699c8ec729cb51c8..e90daef7220e4ee55b778e8325be33111a42bea7 100644
--- a/source/game/SoundPlayer.h
+++ b/source/game/SoundPlayer.h
@@ -31,12 +31,21 @@ class CSoundPlayer: public CPointEntity
 	DECLARE_CLASS(CSoundPlayer, CPointEntity);
 	DECLARE_PROPTABLE();
 public:
-	CSoundPlayer(CEntityManager * pMgr);
+	DECLARE_TRIVIAL_CONSTRUCTOR();
 	~CSoundPlayer();
 
-	virtual void setSound(const char *szSound);
+	void setSound(const char *szSound);
 
-	void onSync() override;
+	void setPos(const float3 &pos) override;
+
+	void setVolume(float fVolume);
+	float getVolume();
+
+	void setDistance(float fDistance);
+	float getDistance();
+
+	void setLoop(int iLoop);
+	SOUND_LOOP getLoop();
 
 protected:
 
diff --git a/source/game/TriggerHurt.cpp b/source/game/TriggerHurt.cpp
index c4ef6d9d4f85c823ad73b58c53782124495289ff..46ae2421b9f010dba07baf7a366881dc28378604 100644
--- a/source/game/TriggerHurt.cpp
+++ b/source/game/TriggerHurt.cpp
@@ -21,12 +21,6 @@ END_PROPTABLE()
 
 REGISTER_ENTITY(CTriggerHurt, trigger_hurt);
 
-CTriggerHurt::CTriggerHurt(CEntityManager * pMgr):
-	BaseClass(pMgr)
-{
-	//m_idHurtInterval = SET_INTERVAL(think, 1000.0f);
-}
-
 CTriggerHurt::~CTriggerHurt()
 {
 	CLEAR_INTERVAL(m_idHurtInterval);
diff --git a/source/game/TriggerHurt.h b/source/game/TriggerHurt.h
index 435e5317d3a7e405d4b76ffa83d2965098c147f3..7260a990f16dbaa88171aa2699249181979a00c0 100644
--- a/source/game/TriggerHurt.h
+++ b/source/game/TriggerHurt.h
@@ -25,7 +25,7 @@ class CTriggerHurt: public CBaseTrigger
 	DECLARE_CLASS(CTriggerHurt, CBaseTrigger);
 	DECLARE_PROPTABLE();
 public:
-	DECLARE_CONSTRUCTOR();
+	DECLARE_TRIVIAL_CONSTRUCTOR();
 	~CTriggerHurt();
 
 protected:
diff --git a/source/game/TriggerItemUse.cpp b/source/game/TriggerItemUse.cpp
index d5d3e786e9a9d2d58d303bcc1eb6f83794727ee4..57c19756a505d1611032537575972d456ffc440e 100644
--- a/source/game/TriggerItemUse.cpp
+++ b/source/game/TriggerItemUse.cpp
@@ -17,12 +17,6 @@ END_PROPTABLE()
 
 REGISTER_ENTITY_NOLISTING(CTriggerItemUse, trigger_itemuse);
 
-CTriggerItemUse::CTriggerItemUse(CEntityManager * pMgr):
-	BaseClass(pMgr)
-{
-	//m_idHurtInterval = SET_INTERVAL(think, 1000.0f);
-}
-
 void CTriggerItemUse::setItem(CBaseItem *pItem)
 {
 	m_pItem = pItem;
diff --git a/source/game/TriggerItemUse.h b/source/game/TriggerItemUse.h
index f116da065ea49810a835818440a95a51b768d019..141feb0f404df5718fcc00978fb0eadf2c1b805c 100644
--- a/source/game/TriggerItemUse.h
+++ b/source/game/TriggerItemUse.h
@@ -26,7 +26,7 @@ class CTriggerItemUse: public CBaseTrigger
 	DECLARE_CLASS(CTriggerItemUse, CBaseTrigger);
 	DECLARE_PROPTABLE();
 public:
-	DECLARE_CONSTRUCTOR();
+	DECLARE_TRIVIAL_CONSTRUCTOR();
 
 	void setItem(CBaseItem *pItem);
 
diff --git a/source/game/TriggerTeleport.cpp b/source/game/TriggerTeleport.cpp
index 6f68091226d8cebaf842d441399c838e8bc5ee1f..d96649db9b2372c0926545162c218be4254abd91 100644
--- a/source/game/TriggerTeleport.cpp
+++ b/source/game/TriggerTeleport.cpp
@@ -14,24 +14,13 @@ See the license in LICENSE
 
 BEGIN_PROPTABLE(CTriggerTeleport)
 	//! Локальный маркер для относительных координат
-	DEFINE_FIELD_ENTITY(m_pLandmark, PDFF_NONE, "landmark", "Landmark object", EDITOR_TEXTFIELD)
+	DEFINE_FIELD_ENTITY(CBaseEntity, m_pLandmark, PDFF_NONE, "landmark", "Landmark object", EDITOR_TEXTFIELD)
 	//! Цель
-	DEFINE_FIELD_ENTITY(m_pDestination, PDFF_NONE, "destination", "Destination landmark object", EDITOR_TEXTFIELD)
+	DEFINE_FIELD_ENTITY(CBaseEntity, m_pDestination, PDFF_NONE, "destination", "Destination landmark object", EDITOR_TEXTFIELD)
 END_PROPTABLE()
 
 REGISTER_ENTITY(CTriggerTeleport, trigger_teleport);
 
-CTriggerTeleport::CTriggerTeleport(CEntityManager * pMgr):
-	BaseClass(pMgr)
-{
-	//m_idHurtInterval = SET_INTERVAL(think, 1000.0f);
-}
-
-CTriggerTeleport::~CTriggerTeleport()
-{
-	//CLEAR_INTERVAL(m_idHurtInterval);
-}
-
 void CTriggerTeleport::onTouchStart(CBaseEntity *pActivator)
 {
 	if(!m_pDestination)
diff --git a/source/game/TriggerTeleport.h b/source/game/TriggerTeleport.h
index 0f8eb54adb9cd1af2b591fba6422bf2b15298c57..61042aa7568c90513d6f8d444b3497c4efc64f67 100644
--- a/source/game/TriggerTeleport.h
+++ b/source/game/TriggerTeleport.h
@@ -25,15 +25,14 @@ class CTriggerTeleport: public CBaseTrigger
 	DECLARE_CLASS(CTriggerTeleport, CBaseTrigger);
 	DECLARE_PROPTABLE();
 public:
-	DECLARE_CONSTRUCTOR();
-	~CTriggerTeleport();
+	DECLARE_TRIVIAL_CONSTRUCTOR();
 
 protected:
 	virtual void onTouchStart(CBaseEntity *pActivator) override;
 
 private:
-	CBaseEntity *m_pLandmark = NULL;
-	CBaseEntity *m_pDestination = NULL;
+	CEntityPointer<CBaseEntity> m_pLandmark;
+	CEntityPointer<CBaseEntity> m_pDestination;
 };
 
 #endif
diff --git a/source/game/proptable.cpp b/source/game/proptable.cpp
index c203467d4501ba223d96a114e0e812d8725b9ef4..6210a2f8dbd4e59066dec68f97a43105ac50d27a 100644
--- a/source/game/proptable.cpp
+++ b/source/game/proptable.cpp
@@ -81,7 +81,7 @@ prop_editor_t _GetEditorFilefield(int start, ...)
 	return(out);
 }
 
-const char * GetEmptyString()
+const char* GetEmptyString()
 {
 	static const char * str = "";
 	return(str);
@@ -92,30 +92,31 @@ void output_t::fire(CBaseEntity *pInflictor, CBaseEntity *pActivator, inputdata_
 	inputdata_t data = {0};
 	data.pActivator = pActivator;
 	data.pInflictor = pInflictor;
-	for(int i = 0; i < iOutCount; ++i)
+	for(UINT i = 0, l = aOutputs.size(); i < l; ++i)
 	{
+		named_output_t &out = aOutputs[i];
 		data.type = PDF_NONE;
-		if(pOutputs[i].fDelay == 0.0f && !pOutputs[i].useRandomDelay)
+		if(out.fDelay == 0.0f && !out.useRandomDelay)
 		{
-			for(int j = 0; j < pOutputs[i].iOutCount; ++j)
+			for(int j = 0, jl = out.aOutputs.size(); j < jl; ++j)
 			{
-				data.type = pOutputs[i].pOutputs[j].data.type;
+				data.type = out.aOutputs[j].data.type;
 				
 				if(data.type == PDF_STRING)
 				{
 					data.parameter.str = NULL;
 				}
 
-				if(pOutputs[i].pOutputs[j].useOverrideData)
+				if(out.aOutputs[j].useOverrideData)
 				{
-					data.setParameter(pOutputs[i].pOutputs[j].data);
+					data.setParameter(out.aOutputs[j].data);
 				}
 				else if(pInputData)
 				{
 					data.setParameter(*pInputData);
 				}
 
-				(pOutputs[i].pOutputs[j].pTarget->*(pOutputs[i].pOutputs[j].fnInput))(&data);
+				(out.aOutputs[j].pTarget->*(out.aOutputs[j].fnInput))(&data);
 
 				if(data.type == PDF_STRING && data.parameter.str != GetEmptyString())
 				{
@@ -130,11 +131,120 @@ void output_t::fire(CBaseEntity *pInflictor, CBaseEntity *pActivator, inputdata_
 				data.type = pInputData->type;
 				data.setParameter(*pInputData);
 			}
-			pActivator->getManager()->setOutputTimeout(&pOutputs[i], &data);
+			pActivator->getManager()->setOutputTimeout(&out, &data);
 		}
 	}
 }
 
+void named_output_t::init(CBaseEntity *pThisEntity)
+{
+	listTargets.init(pThisEntity);
+	listTargets.setEntityName(szTargetName);
+}
+
+void named_output_t::onEntityAdded(CBaseEntity *pEnt)
+{
+	propdata_t * pField = pEnt->getField(szTargetInput);
+	if(!pField || !(pField->flags & PDFF_INPUT))
+	{
+		printf(COLOR_CYAN "Class '%s' has no input '%s', obj '%s'\n" COLOR_RESET, pEnt->getClassName(), szTargetInput, szTargetName);
+	}
+
+	input_t &out = aOutputs[aOutputs.size()];
+
+	out.fnInput = pField->fnInput;
+	out.pTarget = pEnt;
+	memset(&out.data, 0, sizeof(out.data));
+	out.data.type = pField->type;
+	if((out.useOverrideData = szTargetData != NULL))
+	{
+		float3_t f3;
+		float4_t f4;
+		SMQuaternion q;
+		int d;
+		float f;
+		const char *value = szTargetData;
+		bool bParsed = false;
+		switch(pField->type)
+		{
+		case PDF_NONE:
+			bParsed = true;
+			break;
+		case PDF_INT:
+			if(1 == sscanf(value, "%d", &d))
+			{
+				out.data.parameter.i = d;
+				bParsed = true;
+			}
+			break;
+		case PDF_FLOAT:
+			if(1 == sscanf(value, "%f", &f))
+			{
+				out.data.parameter.f = f;
+				bParsed = true;
+			}
+			break;
+		case PDF_VECTOR:
+			if(3 == sscanf(value, "%f %f %f", &f3.x, &f3.y, &f3.z))
+			{
+				out.data.v3Parameter = f3;
+				bParsed = true;
+			}
+			break;
+		case PDF_VECTOR4:
+			{
+				int iPrm = sscanf(value, "%f %f %f %f", &f4.x, &f4.y, &f4.z, &f4.w);
+				if(iPrm > 2)
+				{
+					if(iPrm == 3)
+					{
+						f4.w = 1.0f;
+					}
+					out.data.v4Parameter = f4;
+					bParsed = true;
+				}
+			}
+			break;
+		case PDF_BOOL:
+			if(1 == sscanf(value, "%d", &d))
+			{
+				out.data.parameter.b = d != 0;
+				bParsed = true;
+			}
+			break;
+		case PDF_STRING:
+			_setStrVal(&out.data.parameter.str, value);
+			bParsed = true;
+			break;
+		}
+
+		if(!bParsed)
+		{
+			printf(COLOR_CYAN "Cannot parse input parameter '%s', class '%s', input '%s', obj '%s'\n" COLOR_RESET, value, pEnt->getClassName(), szTargetInput, szTargetName);
+			aOutputs.erase(aOutputs.size() - 1);
+		}
+	}
+}
+void named_output_t::onEntityRemoved(CBaseEntity *pEnt)
+{
+	int idx = aOutputs.indexOf(pEnt, [](const input_t &a, CBaseEntity *b){
+		return(a.pTarget == b);
+	});
+	assert(idx >= 0);
+	if(idx >= 0)
+	{
+		if(aOutputs[idx].useOverrideData && aOutputs[idx].data.type == PDF_STRING)
+		{
+			const char *estr = GetEmptyString();
+			if(estr != aOutputs[idx].data.parameter.str)
+			{
+				mem_delete_a(aOutputs[idx].data.parameter.str);
+			}
+		}
+		aOutputs[idx] = aOutputs[aOutputs.size() - 1];
+		aOutputs.erase(aOutputs.size() - 1);
+	}
+}
 
 void _setStrVal(const char **to, const char *value)
 {
diff --git a/source/game/proptable.h b/source/game/proptable.h
index 9f00d7aed5e1886ebca34aa9e90ac89b72183d38..c77a4b75ab038d1d030130d22a8f3963d022f5d9 100644
--- a/source/game/proptable.h
+++ b/source/game/proptable.h
@@ -8,6 +8,8 @@ See the license in LICENSE
 #define __PROPTABLE_H
 
 #include <common/Math.h>
+#include "EntityPointer.h"
+#include "EntityList.h"
 
 class CBaseEntity;
 
@@ -50,7 +52,6 @@ enum PDF_TYPE
 	PDF_STRING,
 	PDF_ANGLES,
 	PDF_ENTITY,
-	PDF_PARENT,
 	PDF_FLAGS,
 
 	PDF_FLAG,
@@ -192,7 +193,6 @@ struct inputdata_t
 };
 
 typedef void(CBaseEntity::*input_func)(inputdata_t *pInputData);
-typedef bool(*PFNCHECKENTTYPE)(CBaseEntity*);
 
 struct propdata_t
 {
@@ -204,7 +204,7 @@ struct propdata_t
 		szEdName(NULL),
 		editor({})
 	{}
-	propdata_t(fieldtype f, PDF_TYPE t, int fl, const char *key, const char *edname, PFNCHECKENTTYPE pfnCheckType, prop_editor_t ed):
+	propdata_t(fieldtype f, PDF_TYPE t, int fl, const char *key, const char *edname, prop_editor_t ed):
 		pField(f),
 		type(t),
 		flags(fl),
@@ -212,7 +212,7 @@ struct propdata_t
 		szEdName(edname),
 		editor(ed)
 	{}
-	propdata_t(fieldtype f, PDF_TYPE t, int fl, const char *key, const char *edname, PFNFIELDSET _fnSet, PFNCHECKENTTYPE pfnCheckType, prop_editor_t ed):
+	propdata_t(fieldtype f, PDF_TYPE t, int fl, const char *key, const char *edname, PFNFIELDSET _fnSet, prop_editor_t ed):
 		pField(f),
 		type(t),
 		flags(fl),
@@ -241,8 +241,6 @@ struct propdata_t
 	prop_editor_t editor;
 	PFNFIELDSET fnSet;
 
-	PFNCHECKENTTYPE pfnCheckType = NULL;
-
 	template<typename T>
 	static fieldtype ToFieldType(T arg)
 	{
@@ -281,25 +279,64 @@ struct named_output_t
 	const char *szTargetData = NULL;
 	int iFireLimit = -1;
 
-	int iOutCount = 0;
-	input_t *pOutputs = NULL;
+	CEntityList listTargets;
+	Array<input_t> aOutputs;
+	// int iOutCount = 0;
+	// input_t *pOutputs = NULL;
+
+	void init(CBaseEntity *pThisEntity);
+	void onEntityAdded(CBaseEntity *pEnt);
+	void onEntityRemoved(CBaseEntity *pEnt);
+
+	class OnLinkEstablished final: public IEntityPointerEvent
+	{
+	public:
+		OnLinkEstablished(named_output_t *pOut):
+			m_pOut(pOut)
+		{
+		}
+		void onEvent(CBaseEntity *pEnt) override
+		{
+			m_pOut->onEntityAdded(pEnt);
+		}
+	private:
+		named_output_t *m_pOut;
+	};
+	class OnLinkBroken final: public IEntityPointerEvent
+	{
+	public:
+		OnLinkBroken(named_output_t *pOut):
+			m_pOut(pOut)
+		{
+		}
+		void onEvent(CBaseEntity *pEnt) override
+		{
+			m_pOut->onEntityRemoved(pEnt);
+		}
+	private:
+		named_output_t *m_pOut;
+	};
+
+	OnLinkEstablished onLinkEstablished;
+	OnLinkBroken onLinkBroken;
+
+	named_output_t():
+		onLinkEstablished(this),
+		onLinkBroken(this)
+	{
+		listTargets.setLinkEstablishedListener(&onLinkEstablished);
+		listTargets.setLinkBrokenListener(&onLinkBroken);
+	}
 };
 
 struct output_t
 {
-	output_t():
-		iOutCount(0),
-		pOutputs(NULL),
-		pData(NULL),
-		bDirty(false)
-	{
-	}
 	void fire(CBaseEntity *pInflictor, CBaseEntity *pActivator, inputdata_t *pInputData = NULL);
-
-	bool bDirty;
-	int iOutCount;
-	named_output_t * pOutputs;
-	void * pData;
+	
+	// bool bDirty = false;
+	// int iOutCount = 0;
+	Array<named_output_t> aOutputs;
+	void *pData = NULL;
 };
 
 #define FIRE_OUTPUT(output, inflictor) (output).fire((inflictor), this)
@@ -396,8 +433,8 @@ void cls::InitPropData() \
 	} \
 } 
 
-#define DECLARE_TRIVIAL_CONSTRUCTOR() ThisClass(CEntityManager * pMgr):BaseClass(pMgr){}
-#define DECLARE_CONSTRUCTOR() ThisClass(CEntityManager * pMgr);
+#define DECLARE_TRIVIAL_CONSTRUCTOR() ThisClass():BaseClass(){}
+#define DECLARE_CONSTRUCTOR() ThisClass();
 
 const char * GetEmptyString();
 
@@ -420,36 +457,31 @@ const char * GetEmptyString();
 #define EDITOR_SOUND EDITOR_FILEFIELD FILE_OPTION("Select sound", "ogg") EDITOR_FILE_END()
 #define EDITOR_TEXTURE EDITOR_FILEFIELD FILE_OPTION("Select texture", "dds") EDITOR_FILE_END()
 
-#define DEFINE_FIELD_STRING(field, flags, keyname, edname, editor)              , {propdata_t::ToFieldType<const char* DataClass::*>(&DataClass::field),  PDF_STRING,  flags, keyname, edname, NULL,                                     editor
-#define DEFINE_FIELD_VECTOR(field, flags, keyname, edname, editor)              , {propdata_t::ToFieldType<float3_t DataClass::*>(&DataClass::field),     PDF_VECTOR,  flags, keyname, edname, NULL,                                     editor
-#define DEFINE_FIELD_VECTOR4(field, flags, keyname, edname, editor)             , {propdata_t::ToFieldType<float4_t DataClass::*>(&DataClass::field),     PDF_VECTOR4, flags, keyname, edname, NULL,                                     editor
-#define DEFINE_FIELD_ANGLES(field, flags, keyname, edname, editor)              , {propdata_t::ToFieldType<SMQuaternion DataClass::*>(&DataClass::field), PDF_ANGLES,  flags, keyname, edname, NULL,                                     editor
-#define DEFINE_FIELD_INT(field, flags, keyname, edname, editor)                 , {propdata_t::ToFieldType<int DataClass::*>(&DataClass::field),          PDF_INT,     flags, keyname, edname, NULL,                                     editor
-#define DEFINE_FIELD_ENUM(type, field, flags, keyname, edname, editor)          , {propdata_t::ToFieldType<type DataClass::*>(&DataClass::field),         PDF_INT,     flags, keyname, edname, NULL,                                     editor
-#define DEFINE_FIELD_FLOAT(field, flags, keyname, edname, editor)               , {propdata_t::ToFieldType<float DataClass::*>(&DataClass::field),        PDF_FLOAT,   flags, keyname, edname, NULL,                                     editor
-#define DEFINE_FIELD_BOOL(field, flags, keyname, edname, editor)                , {propdata_t::ToFieldType<bool DataClass::*>(&DataClass::field),         PDF_BOOL,    flags, keyname, edname, NULL,                                     editor
-#define DEFINE_FIELD_ENTITY(field, flags, keyname, edname, editor)              , {propdata_t::ToFieldType<CBaseEntity* DataClass::*>(&DataClass::field), PDF_ENTITY,  flags, keyname, edname, NULL,                                     editor
-#define DEFINE_FIELD_ENTITY2(type, field, flags, keyname, edname, editor)       , {propdata_t::ToFieldType<type* DataClass::*>(&DataClass::field),        PDF_ENTITY,  flags, keyname, edname, CEntityFactoryMap::IsEntityOfClass<type>, editor
-#define DEFINE_FIELD_PARENT(field, flags, keyname, edname, editor)              , {propdata_t::ToFieldType<CBaseEntity* DataClass::*>(&DataClass::field), PDF_PARENT,  flags, keyname, edname, NULL,                                     editor
-#define DEFINE_FIELD_FLAGS(field, flags, keyname, edname, editor)               , {propdata_t::ToFieldType<UINT DataClass::*>(&DataClass::field),         PDF_FLAGS,   flags, keyname, edname, NULL,                                     editor
-
-#define DEFINE_FIELD_STRINGFN(field, flags, keyname, edname, fn, editor)        , {propdata_t::ToFieldType<const char* DataClass::*>(&DataClass::field),  PDF_STRING,  flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, const char*>(&DataClass::fn),         NULL,                                     editor
-#define DEFINE_FIELD_VECTORFN(field, flags, keyname, edname, fn, editor)        , {propdata_t::ToFieldType<float3_t DataClass::*>(&DataClass::field),     PDF_VECTOR,  flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, const float3&>(&DataClass::fn),       NULL,                                     editor
-#define DEFINE_FIELD_VECTOR4FN(field, flags, keyname, edname, fn, editor)       , {propdata_t::ToFieldType<float4_t DataClass::*>(&DataClass::field),     PDF_VECTOR4, flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, const float4&>(&DataClass::fn),       NULL,                                     editor
-#define DEFINE_FIELD_ANGLESFN(field, flags, keyname, edname, fn, editor)        , {propdata_t::ToFieldType<SMQuaternion DataClass::*>(&DataClass::field), PDF_ANGLES,  flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, const SMQuaternion&>(&DataClass::fn), NULL,                                     editor
-#define DEFINE_FIELD_INTFN(field, flags, keyname, edname, fn, editor)           , {propdata_t::ToFieldType<int DataClass::*>(&DataClass::field),          PDF_INT,     flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, int>(&DataClass::fn),                 NULL,                                     editor
-#define DEFINE_FIELD_ENUMFN(type, field, flags, keyname, edname, fn, editor)    , {propdata_t::ToFieldType<type DataClass::*>(&DataClass::field),         PDF_INT,     flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, int>(&DataClass::fn),                 NULL,                                     editor
-#define DEFINE_FIELD_FLOATFN(field, flags, keyname, edname, fn, editor)         , {propdata_t::ToFieldType<float DataClass::*>(&DataClass::field),        PDF_FLOAT,   flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, float>(&DataClass::fn),               NULL,                                     editor
-#define DEFINE_FIELD_BOOLFN(field, flags, keyname, edname, fn, editor)          , {propdata_t::ToFieldType<bool DataClass::*>(&DataClass::field),         PDF_BOOL,    flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, bool>(&DataClass::fn),                NULL,                                     editor
-#define DEFINE_FIELD_ENTITYFN(field, flags, keyname, edname, fn, editor)        , {propdata_t::ToFieldType<CBaseEntity* DataClass::*>(&DataClass::field), PDF_ENTITY,  flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, CBaseEntity*>(&DataClass::fn),        NULL,                                     editor
-#define DEFINE_FIELD_ENTITY2FN(type, field, flags, keyname, edname, fn, editor) , {propdata_t::ToFieldType<type* DataClass::*>(&DataClass::field),        PDF_ENTITY,  flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, type*>(&DataClass::fn),               CEntityFactoryMap::IsEntityOfClass<type>, editor
-//#define DEFINE_FIELD_PARENTFN(field, flags, keyname, edname, fn, editor) , {(fieldtype)&DataClass::field, PDF_PARENT, flags, keyname, edname, fn, editor
+#define DEFINE_FIELD_STRING(field, flags, keyname, edname, editor)              , {propdata_t::ToFieldType<const char* DataClass::*>(&DataClass::field),          PDF_STRING,  flags, keyname, edname, editor
+#define DEFINE_FIELD_VECTOR(field, flags, keyname, edname, editor)              , {propdata_t::ToFieldType<float3_t DataClass::*>(&DataClass::field),             PDF_VECTOR,  flags, keyname, edname, editor
+#define DEFINE_FIELD_VECTOR4(field, flags, keyname, edname, editor)             , {propdata_t::ToFieldType<float4_t DataClass::*>(&DataClass::field),             PDF_VECTOR4, flags, keyname, edname, editor
+#define DEFINE_FIELD_ANGLES(field, flags, keyname, edname, editor)              , {propdata_t::ToFieldType<SMQuaternion DataClass::*>(&DataClass::field),         PDF_ANGLES,  flags, keyname, edname, editor
+#define DEFINE_FIELD_INT(field, flags, keyname, edname, editor)                 , {propdata_t::ToFieldType<int DataClass::*>(&DataClass::field),                  PDF_INT,     flags, keyname, edname, editor
+#define DEFINE_FIELD_ENUM(type, field, flags, keyname, edname, editor)          , {propdata_t::ToFieldType<type DataClass::*>(&DataClass::field),                 PDF_INT,     flags, keyname, edname, editor
+#define DEFINE_FIELD_FLOAT(field, flags, keyname, edname, editor)               , {propdata_t::ToFieldType<float DataClass::*>(&DataClass::field),                PDF_FLOAT,   flags, keyname, edname, editor
+#define DEFINE_FIELD_BOOL(field, flags, keyname, edname, editor)                , {propdata_t::ToFieldType<bool DataClass::*>(&DataClass::field),                 PDF_BOOL,    flags, keyname, edname, editor
+#define DEFINE_FIELD_ENTITY(type, field, flags, keyname, edname, editor)        , {propdata_t::ToFieldType<CEntityPointer<type> DataClass::*>(&DataClass::field), PDF_ENTITY,  flags, keyname, edname, editor
+#define DEFINE_FIELD_FLAGS(field, flags, keyname, edname, editor)               , {propdata_t::ToFieldType<UINT DataClass::*>(&DataClass::field),                 PDF_FLAGS,   flags, keyname, edname, editor
+
+#define DEFINE_FIELD_STRINGFN(field, flags, keyname, edname, fn, editor)        , {propdata_t::ToFieldType<const char* DataClass::*>(&DataClass::field),          PDF_STRING,  flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, const char*>(&DataClass::fn),         editor
+#define DEFINE_FIELD_VECTORFN(field, flags, keyname, edname, fn, editor)        , {propdata_t::ToFieldType<float3_t DataClass::*>(&DataClass::field),             PDF_VECTOR,  flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, const float3&>(&DataClass::fn),       editor
+#define DEFINE_FIELD_VECTOR4FN(field, flags, keyname, edname, fn, editor)       , {propdata_t::ToFieldType<float4_t DataClass::*>(&DataClass::field),             PDF_VECTOR4, flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, const float4&>(&DataClass::fn),       editor
+#define DEFINE_FIELD_ANGLESFN(field, flags, keyname, edname, fn, editor)        , {propdata_t::ToFieldType<SMQuaternion DataClass::*>(&DataClass::field),         PDF_ANGLES,  flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, const SMQuaternion&>(&DataClass::fn), editor
+#define DEFINE_FIELD_INTFN(field, flags, keyname, edname, fn, editor)           , {propdata_t::ToFieldType<int DataClass::*>(&DataClass::field),                  PDF_INT,     flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, int>(&DataClass::fn),                 editor
+#define DEFINE_FIELD_ENUMFN(type, field, flags, keyname, edname, fn, editor)    , {propdata_t::ToFieldType<type DataClass::*>(&DataClass::field),                 PDF_INT,     flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, int>(&DataClass::fn),                 editor
+#define DEFINE_FIELD_FLOATFN(field, flags, keyname, edname, fn, editor)         , {propdata_t::ToFieldType<float DataClass::*>(&DataClass::field),                PDF_FLOAT,   flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, float>(&DataClass::fn),               editor
+#define DEFINE_FIELD_BOOLFN(field, flags, keyname, edname, fn, editor)          , {propdata_t::ToFieldType<bool DataClass::*>(&DataClass::field),                 PDF_BOOL,    flags, keyname, edname, propdata_t::ToPFNFieldSet<DataClass, bool>(&DataClass::fn),                editor
 //#define DEFINE_FIELD_FLAGSFN(field, flags, keyname, edname, fn, editor)  , {(fieldtype)&DataClass::field, PDF_FLAGS,  flags, keyname, edname, fn, editor
 
 #define DEFINE_INPUT(method, keyname, edname, argtype)   , {propdata_t::ToInputFunc<void(DataClass::*)(inputdata_t*)>(&DataClass::method), argtype, PDFF_NOEDIT | PDFF_INPUT, keyname, edname, EDITOR_NONE
-#define DEFINE_OUTPUT(field, keyname, edname)            , {propdata_t::ToFieldType<output_t DataClass::*>(&DataClass::field), PDF_OUTPUT, PDFF_NOEDIT | PDFF_OUTPUT, keyname, edname, NULL, EDITOR_NONE
+#define DEFINE_OUTPUT(field, keyname, edname)            , {propdata_t::ToFieldType<output_t DataClass::*>(&DataClass::field), PDF_OUTPUT, PDFF_NOEDIT | PDFF_OUTPUT, keyname, edname, EDITOR_NONE
 #define DEFINE_MESSAGE(method, keyname, edname, argtype) , {propdata_t::ToInputFunc<void(DataClass::*)(inputdata_t*)>(&DataClass::method), argtype, PDFF_NOEDIT | PDFF_MESSAGE, keyname, edname, EDITOR_NONE
 
-#define DEFINE_FLAG(value, edname)                       , {(fieldtype)NULL, PDF_FLAG, value, NULL, edname, NULL, EDITOR_FLAGS
+#define DEFINE_FLAG(value, edname)                       , {(fieldtype)NULL, PDF_FLAG, value, NULL, edname, EDITOR_FLAGS
 
 #endif
diff --git a/source/game/sxgame.h b/source/game/sxgame.h
index be0f9185628f89202bf592efd6c12ed52a6ef56d..39ac95bfbee0e59b842a02175079659fb85f726c 100644
--- a/source/game/sxgame.h
+++ b/source/game/sxgame.h
@@ -246,13 +246,11 @@ SX_LIB_API CBaseEntity *SGame_EntGetByName(const char *szName, ID idStart = 0);
 
 SX_LIB_API BOOL SGame_AddWMsg(UINT message, WPARAM wParam, LPARAM lParam);
 
-/*! Копирует объект, возвращает ID копии
-*/
-SX_LIB_API ID SGame_EntClone(ID idSrc);
-
+#if 0
 /*! Находит объект по пересечению с лучем, в режиме редактора так же находит точечные объекты, в режиме игры - нет
 */
 SX_LIB_API ID SGame_EntGetByRay(const float3 &vStart, const float3 &vDir, float3 *pHitPos = NULL);
+#endif
 
 #endif
 
diff --git a/source/game/sxgame_dll.cpp b/source/game/sxgame_dll.cpp
index d1dd32483d28feeefe53938e587605c9da990661..8a023f1aa2b5ef80987d715fbe42f2f6a8ca342b 100644
--- a/source/game/sxgame_dll.cpp
+++ b/source/game/sxgame_dll.cpp
@@ -379,19 +379,7 @@ SX_LIB_API BOOL SGame_AddWMsg(UINT message, WPARAM wParam, LPARAM lParam)
 	return(GameData::m_pGUIStack->putMessage(message, wParam, lParam));
 }
 
-SX_LIB_API ID SGame_EntClone(ID idSrc)
-{
-	SG_PRECOND(-1);
-	CBaseEntity *pEnt = GameData::m_pMgr->cloneEntity(GameData::m_pMgr->getById(idSrc));
-
-	if(!pEnt)
-	{
-		return(-1);
-	}
-
-	return(pEnt->getId());
-}
-
+#if 0
 SX_LIB_API ID SGame_EntGetByRay(const float3 &vStart, const float3 &vDir, float3 *pHitPos)
 {
 	SG_PRECOND(-1);
@@ -416,3 +404,4 @@ SX_LIB_API ID SGame_EntGetByRay(const float3 &vStart, const float3 &vDir, float3
 	}
 	return(-1);
 }
+#endif
diff --git a/source/mtrl/MaterialSystem.cpp b/source/mtrl/MaterialSystem.cpp
index a772e6dd3babe84773332e7617b4f5343ff34bd1..6c395b8aa2324b1ef7a2be91fad4d2aab524a9ff 100644
--- a/source/mtrl/MaterialSystem.cpp
+++ b/source/mtrl/MaterialSystem.cpp
@@ -109,7 +109,7 @@ void XMETHODCALLTYPE CMaterialSystem::loadMaterial(const char *szName, IXMateria
 	String sName(szName);
 
 	const AssotiativeArray<String, CMaterial*>::Node *pNode;
-	if(m_mapMaterials.KeyExists(sName, &pNode) && *(pNode->Val))
+	if(m_mapMaterials.KeyExists(sName, &pNode))
 	{
 		*ppMaterial = *(pNode->Val);
 		(*ppMaterial)->AddRef();
@@ -132,7 +132,7 @@ void XMETHODCALLTYPE CMaterialSystem::loadMaterial(const char *szName, IXMateria
 bool XMETHODCALLTYPE CMaterialSystem::getMaterial(const char *szName, IXMaterial **ppMaterial)
 {
 	const AssotiativeArray<String, CMaterial*>::Node *pNode;
-	if(m_mapMaterials.KeyExists(szName, &pNode) && *(pNode->Val))
+	if(m_mapMaterials.KeyExists(szName, &pNode))
 	{
 		*ppMaterial = *(pNode->Val);
 		(*ppMaterial)->AddRef();
@@ -176,10 +176,7 @@ void XMETHODCALLTYPE CMaterialSystem::reloadAll()
 {
 	for(AssotiativeArray<String, CMaterial*>::Iterator i = m_mapMaterials.begin(); i; ++i)
 	{
-		if(*(i.second))
-		{
-			loadMaterial(i.first->c_str(), *(i.second));
-		}
+		loadMaterial(i.first->c_str(), *(i.second));
 	}
 }
 
@@ -263,7 +260,7 @@ bool XMETHODCALLTYPE CMaterialSystem::loadTexture(const char *szName, IXTexture
 	String sName(szName);
 
 	const AssotiativeArray<String, CTexture*>::Node *pNode;
-	if(m_mpTextures.KeyExists(sName, &pNode) && *(pNode->Val))
+	if(m_mpTextures.KeyExists(sName, &pNode))
 	{
 		*ppTexture = *(pNode->Val);
 		(*ppTexture)->AddRef();
@@ -414,7 +411,7 @@ bool XMETHODCALLTYPE CMaterialSystem::loadTexture(const char *szName, IXTexture
 bool XMETHODCALLTYPE CMaterialSystem::getTexture(const char *szName, IXTexture **ppTexture)
 {
 	const AssotiativeArray<String, CTexture*>::Node *pNode;
-	if(m_mpTextures.KeyExists(szName, &pNode) && *(pNode->Val))
+	if(m_mpTextures.KeyExists(szName, &pNode))
 	{
 		*ppTexture = *(pNode->Val);
 		(*ppTexture)->AddRef();
@@ -660,7 +657,7 @@ void CMaterialSystem::onTextureRelease(CTexture *pTexture)
 {
 	assert(pTexture);
 
-	m_mpTextures[pTexture->getName()] = NULL;
+	m_mpTextures.erase(pTexture->getName());
 
 	m_poolTextures.Delete(pTexture);
 }
@@ -669,7 +666,7 @@ void CMaterialSystem::onMaterialRelease(CMaterial *pMaterial)
 {
 	assert(pMaterial);
 
-	m_mapMaterials[pMaterial->getName()] = NULL;
+	m_mapMaterials.erase(pMaterial->getName());
 }
 
 void CMaterialSystem::queueTextureUpload(CTexture *pTexture)
diff --git a/source/mtrl/MaterialSystem.h b/source/mtrl/MaterialSystem.h
index 445e8bed175f66fc4d266be2019fb793d9e9c3d4..a4c2c4d8b380d31c70a6aac1370801d00b28e761 100644
--- a/source/mtrl/MaterialSystem.h
+++ b/source/mtrl/MaterialSystem.h
@@ -353,7 +353,7 @@ protected:
 	MemAlloc<CTexture> m_poolTextures;
 	Array<IXTextureProxy*> m_aTextureProxies;
 	AssotiativeArray<String, IXTextureFilter*> m_mapTextureFilters;
-	AssotiativeArray<String, CTexture*> m_mpTextures;
+	Map<String, CTexture*> m_mpTextures;
 	CConcurrentQueue<CTexture*> m_queueTextureToLoad;
 	IXTexture *m_pDefaultTexture = NULL;
 
@@ -366,7 +366,7 @@ protected:
 	Array<IXMaterialProxy*> m_aMaterialProxies;
 	AssotiativeArray<AAString, Array<MaterialLoader>> m_mapMaterialLoaders;
 	Array<XFormatName> m_aMaterialExts;
-	AssotiativeArray<String, CMaterial*> m_mapMaterials;
+	Map<String, CMaterial*> m_mapMaterials;
 
 	IEventChannel<XEventMaterialChanged> *m_pNotifyChannel = NULL;
 
diff --git a/source/physics/PhyWorld.cpp b/source/physics/PhyWorld.cpp
index 3abb3c949dcce3546d1ff7ab0887ab9fcc41603c..9e294766d2f2d30338247b1a4dc7d6eee2ef7157 100644
--- a/source/physics/PhyWorld.cpp
+++ b/source/physics/PhyWorld.cpp
@@ -106,6 +106,10 @@ CPhyWorld::CPhyWorld():
 
 	m_pDynamicsWorld->getSolverInfo().m_numIterations = 30;
 
+	// typedef void (*btInternalTickCallback)(btDynamicsWorld *world, btScalar timeStep);
+
+	m_pDynamicsWorld->setInternalTickCallback(TickCallback, this);
+
 	//btCreateDefaultTaskScheduler();
 	static CTaskScheduler taskSheduler;
 	btSetTaskScheduler(&taskSheduler);
@@ -126,6 +130,8 @@ CPhyWorld::CPhyWorld():
 	btSetCustomEnterProfileZoneFunc(CProfileManager::Start_Profile);
 	btSetCustomLeaveProfileZoneFunc(CProfileManager::Stop_Profile);
 
+	m_pTickEventChannel = Core_GetIXCore()->getEventChannel<XEventPhysicsStep>(EVENT_PHYSICS_STEP_GUID);
+	
 #if 0
 	Core_GetIXCore()->getEventChannel<XEventLevel>(EVENT_LEVEL_GUID)->addListener([](const XEventLevel *pData)
 	{
@@ -853,6 +859,17 @@ void CPhyWorld::enableSimulation()
 	m_iSkipFrames = 3;
 }
 
+void CPhyWorld::TickCallback(btDynamicsWorld *world, btScalar timeStep)
+{
+	CPhyWorld *pThis = (CPhyWorld*)world->getWorldUserInfo();
+
+	XEventPhysicsStep ev;
+	ev.fTimeStep = timeStep;
+	ev.pPhysics = NULL;
+
+	pThis->m_pTickEventChannel->broadcastEvent(&ev);
+}
+
 //##############################################################
 
 void XMETHODCALLTYPE CPhyWorld::CRenderable::renderStage(X_RENDER_STAGE stage, IXRenderableVisibility *pVisibility)
diff --git a/source/physics/PhyWorld.h b/source/physics/PhyWorld.h
index 5985d411a632acca6343d920696c569ee8d40f87..1112d84dc01f6151961b907491d1bbf0b0e00b3e 100644
--- a/source/physics/PhyWorld.h
+++ b/source/physics/PhyWorld.h
@@ -197,6 +197,10 @@ protected:
 
 	bool m_isRunning;
 	int m_iSkipFrames = 3;
+
+	IEventChannel<XEventPhysicsStep> *m_pTickEventChannel = NULL;
+
+	static void TickCallback(btDynamicsWorld *world, btScalar timeStep);
 };
 
 #endif
diff --git a/source/xcommon/IXSoundSystem.h b/source/xcommon/IXSoundSystem.h
index f33663b531408d3aea0737fe65e9a9c4a1a3795b..87d1d85e1c1c3f52509e58579414912aa1ef791b 100644
--- a/source/xcommon/IXSoundSystem.h
+++ b/source/xcommon/IXSoundSystem.h
@@ -37,7 +37,9 @@ enum SOUND_LOOP
 {
 	SOUND_LOOP_NONE = 0,
 	SOUND_LOOP_SIMPLE = 1,
-	SOUND_LOOP_SEAMLESS = 2
+	SOUND_LOOP_SEAMLESS = 2,
+
+	SOUND_LOOP_FORCE_DWORD = 0x7fffffff  /* force 32-bit size enum */
 };
 
 //##########################################################################
diff --git a/source/xcommon/XEvents.h b/source/xcommon/XEvents.h
index 7231051f7c4628df58f5169138db2e7b02229d5b..2a3929d35ceb605a2b64f06474bfbe5ecfe529a3 100644
--- a/source/xcommon/XEvents.h
+++ b/source/xcommon/XEvents.h
@@ -27,46 +27,34 @@ class IEventChannel: public IBaseEventChannel
 public:
 	void addListener(PFNLISTENER fnListener)
 	{
-		for(UINT i = 0, l = m_vListeners.size(); i < l; ++i)
+		if(m_vListeners.indexOf(fnListener) < 0)
 		{
-			if(m_vListeners[i] == fnListener)
-			{
-				return;
-			}
+			m_vListeners.push_back(fnListener);
 		}
-		m_vListeners.push_back(fnListener);
 	}
 	void addListener(IEventListener<T> *pListener)
 	{
-		for(UINT i = 0, l = m_vListeners2.size(); i < l; ++i)
+		if(m_vListeners2.indexOf(pListener) < 0)
 		{
-			if(m_vListeners2[i] == pListener)
-			{
-				return;
-			}
+			m_vListeners2.push_back(pListener);
 		}
-		m_vListeners2.push_back(pListener);
 	}
 	void removeListener(PFNLISTENER fnListener)
 	{
-		for(UINT i = 0, l = m_vListeners.size(); i < l; ++i)
+		int idx = m_vListeners.indexOf(fnListener);
+		if(idx >= 0)
 		{
-			if(m_vListeners[i] == fnListener)
-			{
-				m_vListeners.erase(i);
-				return;
-			}
+			m_vListeners[idx] = m_vListeners[m_vListeners.size() - 1];
+			m_vListeners.erase(m_vListeners.size() - 1);
 		}
 	}
 	void removeListener(IEventListener<T> *pListener)
 	{
-		for(UINT i = 0, l = m_vListeners2.size(); i < l; ++i)
+		int idx = m_vListeners2.indexOf(pListener);
+		if(idx >= 0)
 		{
-			if(m_vListeners2[i] == pListener)
-			{
-				m_vListeners2.erase(i);
-				return;
-			}
+			m_vListeners2[idx] = m_vListeners2[m_vListeners2.size() - 1];
+			m_vListeners2.erase(m_vListeners2.size() - 1);
 		}
 	}
 	void broadcastEvent(const T *pEvent)
@@ -241,4 +229,15 @@ struct XEventSkyboxChanged
 	IXTexture *pTexture;
 };
 
+
+// {1DB80A19-7DFA-4D61-923B-34906590DBB0}
+#define EVENT_PHYSICS_STEP_GUID DEFINE_XGUID(0x1db80a19, 0x7dfa, 0x4d61, 0x92, 0x3b, 0x34, 0x90, 0x65, 0x90, 0xdb, 0xb0)
+
+class IXPhysics;
+struct XEventPhysicsStep
+{
+	IXPhysics *pPhysics;
+	float fTimeStep;
+};
+
 #endif