From 34a3efba0d5f1995510ad36df60b8185bd03b5d4 Mon Sep 17 00:00:00 2001
From: D-AIRY <admin@ds-servers.com>
Date: Tue, 2 Jan 2018 20:41:15 +0300
Subject: [PATCH] Added CBaseCharacter middleclass; Weapon fire spread
 calculation

---
 build/gamesource/config/entities/classes.ent |   6 +-
 proj/sxgame/vs2013/sxgame.vcxproj            |   2 +
 proj/sxgame/vs2013/sxgame.vcxproj.filters    |  54 ++--
 source/game/CBaseCharacter.cpp               | 246 +++++++++++++++++++
 source/game/CBaseCharacter.h                 | 106 ++++++++
 source/game/SXbaseItem.cpp                   |   5 +
 source/game/SXbaseItem.h                     |   4 +
 source/game/SXbaseTool.cpp                   |  13 +-
 source/game/SXbaseTool.h                     |   9 +
 source/game/SXbaseWeapon.cpp                 |  85 ++++++-
 source/game/SXbaseWeapon.h                   |  39 +++
 source/game/SXplayer.cpp                     | 153 +-----------
 source/game/SXplayer.h                       |  66 +----
 source/game/crosshair.cpp                    |  13 +-
 14 files changed, 570 insertions(+), 231 deletions(-)
 create mode 100644 source/game/CBaseCharacter.cpp
 create mode 100644 source/game/CBaseCharacter.h

diff --git a/build/gamesource/config/entities/classes.ent b/build/gamesource/config/entities/classes.ent
index b0b7cf2c7..8b2422ed1 100644
--- a/build/gamesource/config/entities/classes.ent
+++ b/build/gamesource/config/entities/classes.ent
@@ -51,6 +51,10 @@ single_speed = 40; выст/мин
 burst_speed = 100; выст/мин
 
 effective_distance = 650
+
+;разброс
+spread_base       	= 0.33    ;угол (в градусах) базовой дисперсии оружия (оружия, зажатого в тисках)
+
 ; Боевая скорострельность (одиночными): 40 выст/мин
 ; Боевая скорострельность (очередями): 100 выст/мин
 ; Дальность, до которой сохраняется убойное действие пули: 1350 м
@@ -80,8 +84,6 @@ durability = 350000
 durability_return_min = 0.7 ; при ремонте:
 durability_return_max = 0.9 ; durability_max = durability_max * rand(durability_return_min, durability_return_max)
 
-;разброс
-fire_dispersion_base       	= 0.33    ;угол (в градусах) базовой дисперсии оружия (оружия, зажатого в тисках)
 
 ;отдача
 cam_return					= 0
diff --git a/proj/sxgame/vs2013/sxgame.vcxproj b/proj/sxgame/vs2013/sxgame.vcxproj
index a0ebed554..e33751a9b 100644
--- a/proj/sxgame/vs2013/sxgame.vcxproj
+++ b/proj/sxgame/vs2013/sxgame.vcxproj
@@ -97,6 +97,7 @@
     <ClCompile Include="..\..\..\source\game\BaseSilencer.cpp" />
     <ClCompile Include="..\..\..\source\game\BaseWeaponAddon.cpp" />
     <ClCompile Include="..\..\..\source\game\BaseTrigger.cpp" />
+    <ClCompile Include="..\..\..\source\game\CBaseCharacter.cpp" />
     <ClCompile Include="..\..\..\source\game\crosshair.cpp" />
     <ClCompile Include="..\..\..\source\game\CrosshairManager.cpp" />
     <ClCompile Include="..\..\..\source\game\EntityFactory.cpp" />
@@ -133,6 +134,7 @@
     <ClInclude Include="..\..\..\source\game\BaseSilencer.h" />
     <ClInclude Include="..\..\..\source\game\BaseWeaponAddon.h" />
     <ClInclude Include="..\..\..\source\game\BaseTrigger.h" />
+    <ClInclude Include="..\..\..\source\game\CBaseCharacter.h" />
     <ClInclude Include="..\..\..\source\game\crosshair.h" />
     <ClInclude Include="..\..\..\source\game\CrosshairManager.h" />
     <ClInclude Include="..\..\..\source\game\EntityFactory.h" />
diff --git a/proj/sxgame/vs2013/sxgame.vcxproj.filters b/proj/sxgame/vs2013/sxgame.vcxproj.filters
index 55022f88c..144db71d3 100644
--- a/proj/sxgame/vs2013/sxgame.vcxproj.filters
+++ b/proj/sxgame/vs2013/sxgame.vcxproj.filters
@@ -49,6 +49,18 @@
     <Filter Include="Source Files\ents\triggers">
       <UniqueIdentifier>{a19af9a9-9698-4f6e-94fc-fc12afaa10a2}</UniqueIdentifier>
     </Filter>
+    <Filter Include="Header Files\ents\characters">
+      <UniqueIdentifier>{dd25ca33-fbd9-40fb-878e-4d2f1531565f}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Header Files\ents\characters\npc">
+      <UniqueIdentifier>{befd7b49-c663-45c4-87cf-9d481da7fb90}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Source Files\ents\characters">
+      <UniqueIdentifier>{9a873af0-2663-4675-9e2e-ce30a5bfc8ea}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Source Files\ents\characters\npc">
+      <UniqueIdentifier>{474c6cbf-9b16-4a74-876b-edd6fc116cbc}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\..\source\game\sxgame_dll.cpp">
@@ -75,9 +87,6 @@
     <ClCompile Include="..\..\..\source\game\SXplayerSpawn.cpp">
       <Filter>Source Files\ents</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\source\game\SXplayer.cpp">
-      <Filter>Source Files\ents</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\..\source\game\SXpointCamera.cpp">
       <Filter>Source Files\ents</Filter>
     </ClCompile>
@@ -111,12 +120,6 @@
     <ClCompile Include="..\..\..\source\game\SXbaseWeapon.cpp">
       <Filter>Source Files\ents\items\tools</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\source\game\NPCBase.cpp">
-      <Filter>Source Files\ents</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\..\source\game\NPCZombie.cpp">
-      <Filter>Source Files\ents</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\..\source\game\LightDirectional.cpp">
       <Filter>Source Files\ents</Filter>
     </ClCompile>
@@ -153,6 +156,18 @@
     <ClCompile Include="..\..\..\source\game\SXbaseSupply.cpp">
       <Filter>Source Files\ents\items</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\..\source\game\NPCZombie.cpp">
+      <Filter>Source Files\ents\characters\npc</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\..\source\game\NPCBase.cpp">
+      <Filter>Source Files\ents\characters</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\..\source\game\SXplayer.cpp">
+      <Filter>Source Files\ents\characters</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\..\source\game\CBaseCharacter.cpp">
+      <Filter>Source Files\ents\characters</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\..\source\game\sxgame.h">
@@ -167,9 +182,6 @@
     <ClInclude Include="..\..\..\source\game\SXbaseAnimating.h">
       <Filter>Header Files\ents</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\..\source\game\SXplayer.h">
-      <Filter>Header Files\ents</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\..\source\game\SXpointEntity.h">
       <Filter>Header Files\ents</Filter>
     </ClInclude>
@@ -221,12 +233,6 @@
     <ClInclude Include="..\..\..\source\game\SXbaseWeapon.h">
       <Filter>Header Files\ents\items\tools</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\..\source\game\NPCBase.h">
-      <Filter>Header Files\ents</Filter>
-    </ClInclude>
-    <ClInclude Include="..\..\..\source\game\NPCZombie.h">
-      <Filter>Header Files\ents</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\..\source\game\LightDirectional.h">
       <Filter>Header Files\ents</Filter>
     </ClInclude>
@@ -263,5 +269,17 @@
     <ClInclude Include="..\..\..\source\game\SXbaseSupply.h">
       <Filter>Header Files\ents\items</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\..\source\game\SXplayer.h">
+      <Filter>Header Files\ents\characters</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\..\source\game\NPCBase.h">
+      <Filter>Header Files\ents\characters</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\..\source\game\NPCZombie.h">
+      <Filter>Header Files\ents\characters\npc</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\..\source\game\CBaseCharacter.h">
+      <Filter>Header Files\ents\characters</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/source/game/CBaseCharacter.cpp b/source/game/CBaseCharacter.cpp
new file mode 100644
index 000000000..9fc3897da
--- /dev/null
+++ b/source/game/CBaseCharacter.cpp
@@ -0,0 +1,246 @@
+
+#include "CBaseCharacter.h"
+#include "GameData.h"
+#include "SXbaseTool.h"
+#include "SXbaseWeapon.h"
+
+/*! \skydocent base_character
+������� ����� ���������
+*/
+
+BEGIN_PROPTABLE(CBaseCharacter)
+	// empty
+END_PROPTABLE()
+
+REGISTER_ENTITY_NOLISTING(CBaseCharacter, base_character);
+
+class btKinematicClosestNotMeRayResultCallback: public btCollisionWorld::ClosestRayResultCallback
+{
+public:
+	btKinematicClosestNotMeRayResultCallback(btCollisionObject* me, const btVector3&	rayFromWorld, const btVector3&	rayToWorld): btCollisionWorld::ClosestRayResultCallback(rayFromWorld, rayToWorld)
+	{
+		m_me = me;
+		m_shapeInfo = {-1, -1};
+	}
+
+	virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace)
+	{
+		if(rayResult.m_collisionObject == m_me)
+			return 1.0;
+		if(rayResult.m_localShapeInfo)
+		{
+			m_shapeInfo = *rayResult.m_localShapeInfo;
+		}
+		return ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace);
+	}
+	btCollisionWorld::LocalShapeInfo m_shapeInfo;
+protected:
+	btCollisionObject* m_me;
+};
+
+CBaseCharacter::CBaseCharacter(EntityManager * pMgr):
+	BaseClass(pMgr),
+	m_uMoveDir(PM_OBSERVER),
+	m_vPitchYawRoll(float3_t(0, 0, 0)),
+	m_pActiveTool(NULL),
+	m_fCurrentSpread(0.0f)
+{
+	btTransform startTransform;
+	startTransform.setIdentity();
+	startTransform.setOrigin(F3_BTVEC(m_vPosition));
+	//startTransform.setOrigin(btVector3(0, 12, 10));
+
+	m_pGhostObject = new btPairCachingGhostObject();
+	m_pGhostObject->setWorldTransform(startTransform);
+	//sweepBP->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback());
+	m_pCollideShape = new btCapsuleShape(0.4f, 1.0f);
+	m_pGhostObject->setCollisionShape(m_pCollideShape);
+	m_pGhostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT);
+	m_pGhostObject->setUserPointer(this);
+
+	btScalar stepHeight = 0.4f;
+	m_pCharacter = new btKinematicCharacterController(m_pGhostObject, (btConvexShape*)m_pCollideShape, stepHeight, btVector3(0.0f, 1.0f, 0.0f));
+	m_pCharacter->setMaxJumpHeight(0.60f);
+	m_pCharacter->setJumpSpeed(3.50f);
+	//m_pCharacter->setJumpSpeed(3.5f);
+	m_pCharacter->setGravity(btVector3(0, -10.0f, 0));
+	//m_pCharacter->setGravity(1.0f);
+	m_pCharacter->setFallSpeed(300.0f);
+	//m_pCharacter->setFallSpeed(30.0f);
+
+	SXPhysics_GetDynWorld()->addCollisionObject(m_pGhostObject, btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::AllFilter & ~btBroadphaseProxy::DebrisFilter);
+
+	m_pGhostObject->setCollisionFlags(m_pGhostObject->getCollisionFlags() | btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT);
+
+	SXPhysics_GetDynWorld()->addAction(m_pCharacter);
+
+
+	m_flashlight = (CLightDirectional*)CREATE_ENTITY("light_directional", m_pMgr);
+	//m_flashlight->SetPos(GetPos() + float3(0.f, 0.1f, 0.f));
+	m_flashlight->SetPos(GetPos() + float3(0.f, 0.2f, 0.1f));
+	m_flashlight->SetOrient(GetOrient() * SMQuaternion(SM_PIDIV2, 'x'));
+	m_flashlight->SetParent(this);
+	m_flashlight->setDist(20.f);
+	m_flashlight->setAngle(SMToRadian(60));
+	m_flashlight->setColor(float3(3.5, 3.5, 3.5));
+	//m_flashlight->setShadowType(-1);
+	m_flashlight->setShadowType(1);
+
+	m_idTaskSpread = SET_INTERVAL(updateSpread, 1.0f / 30.0f);
+}
+
+CBaseCharacter::~CBaseCharacter()
+{
+	CLEAR_INTERVAL(m_idTaskSpread);
+	REMOVE_ENTITY(m_flashlight);
+}
+
+
+void CBaseCharacter::Attack(BOOL state)
+{
+	if(m_uMoveDir & PM_OBSERVER)
+	{
+		return;
+	}
+	if(m_pActiveTool)
+	{
+		m_pActiveTool->PrimaryAction(state);
+	}
+}
+
+void CBaseCharacter::Attack2(BOOL state)
+{
+	if(m_uMoveDir & PM_OBSERVER)
+	{
+		return;
+	}
+	if(m_pActiveTool)
+	{
+		m_pActiveTool->SecondaryAction(state);
+	}
+}
+
+void CBaseCharacter::Reload()
+{
+	if(m_uMoveDir & PM_OBSERVER)
+	{
+		return;
+	}
+	if(m_pActiveTool)
+	{
+		m_pActiveTool->Reload();
+	}
+}
+
+void CBaseCharacter::ToggleFlashlight()
+{
+	m_flashlight->toggleEnable();
+}
+
+void CBaseCharacter::nextFireMode()
+{
+	if(m_uMoveDir & PM_OBSERVER)
+	{
+		return;
+	}
+	if(m_pActiveTool)
+	{
+		//@FIXME: Add correct call
+		//m_pActiveTool->nextFireMode();
+	}
+}
+
+bool CBaseCharacter::onGround()
+{
+	return(m_pCharacter->onGround());
+}
+
+void CBaseCharacter::playFootstepsSound()
+{
+	if(!(m_uMoveDir & PM_OBSERVER))
+	{
+		if(onGround())
+		{
+			float3 start = GetPos(),
+				end = start + float3(0.0f, -2.0f, 0.0f);
+			btKinematicClosestNotMeRayResultCallback cb(m_pGhostObject, F3_BTVEC(start), F3_BTVEC(end));
+			SXPhysics_GetDynWorld()->rayTest(F3_BTVEC(start), F3_BTVEC(end), cb);
+
+			if(cb.hasHit() && cb.m_shapeInfo.m_shapePart == 0 && cb.m_shapeInfo.m_triangleIndex >= 0)
+			{
+				MTLTYPE_PHYSIC type = (MTLTYPE_PHYSIC)SXPhysics_GetMtlType(cb.m_collisionObject, &cb.m_shapeInfo);
+				g_pGameData->playFootstepSound(type, BTVEC_F3(cb.m_hitPointWorld));
+			}
+		}
+	}
+}
+
+float CBaseCharacter::getMomentSpread()
+{
+	if(!m_pActiveTool || !m_pActiveTool->isWeapon())
+	{
+		return(0.0f);
+	}
+
+	SXbaseWeapon *pWpn = (SXbaseWeapon*)m_pActiveTool;
+
+	float fBaseSpread = pWpn->getBaseSpread();
+
+	const float fIdleSpreadBase = 1.0f, fIdleSpreadMult = pWpn->getSpreadCoeff(SPREAD_COEFF_IDLE), // ����
+		fCrouchSpreadBase = 1.0f,       fCrouchSpreadMult = pWpn->getSpreadCoeff(SPREAD_COEFF_CROUCH), // ����������
+		fLaySpreadBase = 1.0f,          fLaySpreadMult = pWpn->getSpreadCoeff(SPREAD_COEFF_CRAWL), // ����
+
+		fWalkSpreadBase = 1.0f,         fWalkSpreadMult = pWpn->getSpreadCoeff(SPREAD_COEFF_WALK), // � ������
+		fRunSpreadBase = 1.0f,          fRunSpreadMult = pWpn->getSpreadCoeff(SPREAD_COEFF_RUN), // � ����
+		fAirborneSpreadBase = 1.0f,     fAirborneSpreadMult = pWpn->getSpreadCoeff(SPREAD_COEFF_AIRBORNE), // � ������
+		fConditionSpreadBase = 1.0f,    fConditionSpreadMult = pWpn->getSpreadCoeff(SPREAD_COEFF_CONDITION), // ��������� ������
+		fArmSpreadBase = 1.0f,          fArmSpreadMult = pWpn->getSpreadCoeff(SPREAD_COEFF_ARM), // ��������� ���
+		fIronSightSpreadBase = 1.0f,    fIronSightSpreadMult = pWpn->getSpreadCoeff(SPREAD_COEFF_IRONSIGHT); // � ������������
+
+
+
+	float fMomentSpread = fBaseSpread * 
+		(fIdleSpreadBase + (!(m_uMoveDir & (PM_CROUCH | PM_CRAWL)) ? fIdleSpreadMult : 0.0f)) *
+		(fWalkSpreadBase + (((m_uMoveDir & (PM_FORWARD | PM_BACKWARD | PM_LEFT | PM_RIGHT)) && !(m_uMoveDir & PM_RUN)) ? fWalkSpreadMult : 0.0f)) *
+		(fCrouchSpreadBase + ((m_uMoveDir & PM_CROUCH) ? fCrouchSpreadMult : 0.0f)) *
+		(fRunSpreadBase + ((m_uMoveDir & PM_RUN) ? fRunSpreadMult : 0.0f)) *
+		(fLaySpreadBase + ((m_uMoveDir & PM_CRAWL) ? fLaySpreadMult : 0.0f)) *
+		(fAirborneSpreadBase + (!onGround() ? fAirborneSpreadMult : 0.0f)) *
+		(fConditionSpreadBase + (fConditionSpreadMult * (1.0f - pWpn->getCondition()))) *
+		// (fArmSpreadBase + (fArmSpreadMult * (1.0f - getArmCondition()))) *
+		(fIronSightSpreadBase + (pWpn->isIronSight() ? fIronSightSpreadMult : 0.0f))
+	;
+
+	//printf("%5.3f => %5.3f\n", fMomentSpread, fBaseSpread);
+	if(fMomentSpread < fBaseSpread)
+	{
+		fMomentSpread = fBaseSpread;
+	}
+	return(fMomentSpread);
+}
+
+void CBaseCharacter::updateSpread(float dt)
+{
+	float fMomentSpread = getMomentSpread();
+	float fWeaponMass = m_pActiveTool ? m_pActiveTool->getWeight() : 0.0f;
+	//printf("%5.3f => %5.3f\n", fMomentSpread, m_fCurrentSpread);
+	if(m_fCurrentSpread < fMomentSpread)
+	{
+		m_fCurrentSpread += fMomentSpread * (3.0f * dt);
+	}
+	else
+	{
+		float fDivider = 5.0f;
+		float fCoeff = (3.0f * dt) * (fDivider / (fWeaponMass + (fDivider / 0.9f)) + 0.1f);
+		if(fCoeff > 1.0f)
+		{
+			fCoeff = 1.0f;
+		}
+		m_fCurrentSpread -= (m_fCurrentSpread - fMomentSpread) * fCoeff;
+	}
+}
+
+float CBaseCharacter::getCurrentSpread()
+{
+	return(m_fCurrentSpread);
+}
diff --git a/source/game/CBaseCharacter.h b/source/game/CBaseCharacter.h
new file mode 100644
index 000000000..8070cc03f
--- /dev/null
+++ b/source/game/CBaseCharacter.h
@@ -0,0 +1,106 @@
+
+/******************************************************
+Copyright � Vitaliy Buturlin, Evgeny Danilovich, 2017
+See the license in LICENSE
+******************************************************/
+
+/*!
+\file
+������� ����� ���������
+*/
+
+/*! \ingroup cbaseanimating
+@{
+*/
+
+#ifndef _CBaseCharacter_H_
+#define _CBaseCharacter_H_
+
+#include "SXbaseAnimating.h"
+#include "LightDirectional.h"
+
+class SXbaseTool;
+
+//! ���� �������� ������
+enum PLAYER_MOVE
+{
+	PM_NONE = 0,
+	PM_FORWARD = 0x01,   //!< ������
+	PM_BACKWARD = 0x02,  //!< �����
+	PM_LEFT = 0x04,      //!< �����
+	PM_RIGHT = 0x08,     //!< ������
+	PM_CROUCH = 0x10,    //!< ��������
+	PM_JUMP = 0x20,      //!< ��������
+	PM_RUN = 0x40,       //!< ������
+	PM_CRAWL = 0x80,     //!< ������
+	PM_OBSERVER = 0x100, //!< �����������
+
+	PM_STOP = 0xFFFF
+};
+
+//! ����� ������  \ingroup cbaseanimating
+class CBaseCharacter: public SXbaseAnimating
+{
+	DECLARE_CLASS(CBaseCharacter, SXbaseAnimating);
+	DECLARE_PROPTABLE();
+public:
+	CBaseCharacter(EntityManager * pMgr);
+	~CBaseCharacter();
+
+	//! ���������/������������� ��������� �����
+	void Attack(BOOL state);
+	//! ���������/������������� ��������� �����
+	void Attack2(BOOL state);
+	//! ��������� ����������� ��������� ������
+	void Reload();
+	//! ��������/��������� ������
+	void ToggleFlashlight();
+	//! ����������� ����� �������� ��������� ������
+	void nextFireMode();
+
+	//! ��������� �� ����� �� �����
+	bool onGround();
+
+	//! ������������� ���� ����� � ������ ��������� �� ������� ����� �����
+	void playFootstepsSound();
+
+
+	//! �������� ������������ ��� �������� ������ ����������� �������� (� ������ �������� ��������)
+	float getCurrentSpread();
+
+protected:
+	//! �������
+	CLightDirectional* m_flashlight;
+
+	//! ������� ��������
+	UINT m_uMoveDir;
+
+	//! ������� ���������� � �����
+	SXbaseTool * m_pActiveTool;
+
+	//! ��� ������ @{
+	btCollisionShape * m_pCollideShape;
+	btRigidBody * m_pRigidBody;
+	btPairCachingGhostObject * m_pGhostObject;
+	btKinematicCharacterController * m_pCharacter;
+	//! @}
+
+	//! ���� �������� ������
+	float3_t m_vPitchYawRoll;
+
+	//! ���������� �������� ������������ ��������
+	float getMomentSpread();
+
+	//! ������ ���������� ��������
+	ID m_idTaskSpread;
+
+	//! ��������� �������� ��������
+	virtual void updateSpread(float dt);
+
+	//! ����������� �������� ��������
+	float m_fCurrentSpread;
+};
+
+#endif
+
+//! @}
diff --git a/source/game/SXbaseItem.cpp b/source/game/SXbaseItem.cpp
index 2374bca2d..78e585bd6 100644
--- a/source/game/SXbaseItem.cpp
+++ b/source/game/SXbaseItem.cpp
@@ -30,3 +30,8 @@ SXbaseItem::SXbaseItem(EntityManager * pMgr):
 	m_bPickable(true)
 {
 }
+
+float SXbaseItem::getWeight()
+{
+	return(m_iInvWeight);
+}
diff --git a/source/game/SXbaseItem.h b/source/game/SXbaseItem.h
index c0ce2ecd9..a6a8a1f88 100644
--- a/source/game/SXbaseItem.h
+++ b/source/game/SXbaseItem.h
@@ -32,6 +32,10 @@ public:
 	int m_iInvStackMaxSize; //!< Максимальное количество итемов в стеке
 	float m_iInvWeight; //!< Масса объекта
 	bool m_bPickable; //!< Можно ли поднять объект
+
+
+	//! Масса объекта
+	virtual float getWeight();
 };
 
 #endif
diff --git a/source/game/SXbaseTool.cpp b/source/game/SXbaseTool.cpp
index 9b7ce26c3..50aa20e32 100644
--- a/source/game/SXbaseTool.cpp
+++ b/source/game/SXbaseTool.cpp
@@ -59,7 +59,8 @@ SXbaseTool::SXbaseTool(EntityManager * pMgr):
 	m_iSoundAction2(-1),
 	m_iMuzzleFlash(-1),
 	m_iMuzzleFlash2(-1),
-	m_fMaxDistance(1000.0f)
+	m_fMaxDistance(1000.0f),
+	m_bIsWeapon(false)
 {
 	m_bInvStackable = false;
 
@@ -267,3 +268,13 @@ void SXbaseTool::_Rezoom()
 		((SXplayer*)m_pOwner)->GetCamera()->GetCamera()->SetFOV(SMToRadian(vlerp(*r_default_fov, *r_default_fov - 10.0f, m_fZoomProgress)));
 	}
 }
+
+bool SXbaseTool::isWeapon() const
+{
+	return(m_bIsWeapon);
+}
+
+float SXbaseTool::getCondition() const
+{
+	return(1.0f);
+}
diff --git a/source/game/SXbaseTool.h b/source/game/SXbaseTool.h
index 4a34d6f65..3fa7ffcd3 100644
--- a/source/game/SXbaseTool.h
+++ b/source/game/SXbaseTool.h
@@ -58,6 +58,12 @@ public:
 
 	void SetParent(SXbaseEntity * pEnt, int attachment = -1);
 
+	//! Этот инструмент - оружие
+	bool isWeapon() const;
+
+	//! Состояние: 1 - целое; 0 - сломанное
+	float getCondition() const;
+
 protected:
 
 	bool m_bInPrimaryAction;
@@ -105,6 +111,9 @@ protected:
 	const char * m_szUsableAmmos;
 
 	float m_fMaxDistance;
+
+	//! Этот инструмент - оружие
+	bool m_bIsWeapon;
 };
 
 #endif
diff --git a/source/game/SXbaseWeapon.cpp b/source/game/SXbaseWeapon.cpp
index f68fc039f..d8000cbcb 100644
--- a/source/game/SXbaseWeapon.cpp
+++ b/source/game/SXbaseWeapon.cpp
@@ -51,6 +51,28 @@ BEGIN_PROPTABLE(SXbaseWeapon)
 	DEFINE_FIELD_INT(m_iCapacity, PDFF_NOEDIT | PDFF_NOEXPORT, "capacity", "", EDITOR_NONE)
 	//! Текущая загрузка без учета магазина
 	DEFINE_FIELD_INT(m_iCurrentLoad, PDFF_NOEDIT, "current_load", "", EDITOR_NONE)
+
+
+	//! угол (в градусах) базовой дисперсии оружия (оружия, зажатого в тисках)
+	DEFINE_FIELD_FLOAT(m_fBaseSpread, PDFF_NOEDIT | PDFF_NOEXPORT, "spread_base", "", EDITOR_NONE)
+	//! коэффициент разброса в стоя
+	DEFINE_FIELD_FLOAT(m_fSpreadIdle, PDFF_NOEDIT | PDFF_NOEXPORT, "spread_idle", "", EDITOR_NONE)
+	//! коэффициент разброса пригнувшись
+	DEFINE_FIELD_FLOAT(m_fSpreadCrouch, PDFF_NOEDIT | PDFF_NOEXPORT, "spread_crouch", "", EDITOR_NONE)
+	//! коэффициент разброса лежа
+	DEFINE_FIELD_FLOAT(m_fSpreadCrawl, PDFF_NOEDIT | PDFF_NOEXPORT, "spread_crawl", "", EDITOR_NONE)
+	//! коэффициент разброса в ходьбе
+	DEFINE_FIELD_FLOAT(m_fSpreadWalk, PDFF_NOEDIT | PDFF_NOEXPORT, "spread_walk", "", EDITOR_NONE)
+	//! коэффициент разброса в беге
+	DEFINE_FIELD_FLOAT(m_fSpreadRun, PDFF_NOEDIT | PDFF_NOEXPORT, "spread_run", "", EDITOR_NONE)
+	//! коэффициент разброса в полете (прыжок)
+	DEFINE_FIELD_FLOAT(m_fSpreadAirborne, PDFF_NOEDIT | PDFF_NOEXPORT, "spread_airborne", "", EDITOR_NONE)
+	//! коэффициент разброса от состояния оружия
+	DEFINE_FIELD_FLOAT(m_fSpreadCondition, PDFF_NOEDIT | PDFF_NOEXPORT, "spread_condition", "", EDITOR_NONE)
+	//! коэффициент разброса от состояния рук
+	DEFINE_FIELD_FLOAT(m_fSpreadArm, PDFF_NOEDIT | PDFF_NOEXPORT, "spread_arm", "", EDITOR_NONE)
+	//! коэффициент разброса в прицеливании
+	DEFINE_FIELD_FLOAT(m_fSpreadIronSight, PDFF_NOEDIT | PDFF_NOEXPORT, "spread_ironsight", "", EDITOR_NONE)
 END_PROPTABLE()
 
 REGISTER_ENTITY_NOLISTING(SXbaseWeapon, base_weapon);
@@ -72,8 +94,21 @@ SXbaseWeapon::SXbaseWeapon(EntityManager * pMgr):
 	m_idSndSwitch(-1),
 
 	m_iCapacity(1),
-	m_iCurrentLoad(0)
-{}
+	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_bIsWeapon = true;
+}
 
 void SXbaseWeapon::OnPostLoad()
 {
@@ -254,3 +289,49 @@ bool SXbaseWeapon::canShoot()
 {
 	return(m_iCurrentLoad > 0 || (m_pMag && m_pMag->getLoad() > 0));
 }
+
+float SXbaseWeapon::getWeight()
+{
+	return(m_iInvWeight +
+		(m_pHandle ? m_pHandle->getWeight() : 0.0f) +
+		(m_pScope ? m_pScope->getWeight() : 0.0f) +
+		(m_pMag ? m_pMag->getWeight() : 0.0f) +
+		(m_pSilencer ? m_pSilencer->getWeight() : 0.0f)
+	);
+}
+
+float SXbaseWeapon::getBaseSpread() const
+{
+	return(m_fBaseSpread);
+}
+
+bool SXbaseWeapon::isIronSight() const
+{
+	return(m_iZoomable && m_bInSecondaryAction);
+}
+
+float SXbaseWeapon::getSpreadCoeff(SPREAD_COEFF what) const
+{
+	switch(what)
+	{
+	case SPREAD_COEFF_IDLE:
+		return(m_fSpreadIdle);
+	case SPREAD_COEFF_CROUCH:
+		return(m_fSpreadCrouch);
+	case SPREAD_COEFF_CRAWL:
+		return(m_fSpreadCrawl);
+	case SPREAD_COEFF_WALK:
+		return(m_fSpreadWalk);
+	case SPREAD_COEFF_RUN:
+		return(m_fSpreadRun);
+	case SPREAD_COEFF_AIRBORNE:
+		return(m_fSpreadAirborne);
+	case SPREAD_COEFF_CONDITION:
+		return(m_fSpreadCondition);
+	case SPREAD_COEFF_ARM:
+		return(m_fSpreadArm);
+	case SPREAD_COEFF_IRONSIGHT:
+		return(m_fSpreadIronSight);
+	}
+	return(1.0f);
+}
diff --git a/source/game/SXbaseWeapon.h b/source/game/SXbaseWeapon.h
index 7f46533db..8f8ecfe3f 100644
--- a/source/game/SXbaseWeapon.h
+++ b/source/game/SXbaseWeapon.h
@@ -28,6 +28,20 @@ enum FIRE_MODE
 };
 #define FIRE_MODE_COUNT 3
 
+//! Идентификаторы для получения коэффициентов разброса
+enum SPREAD_COEFF
+{
+	SPREAD_COEFF_IDLE, //!< стоя
+	SPREAD_COEFF_CROUCH, //!< пригувшись
+	SPREAD_COEFF_CRAWL, //!< лежа
+	SPREAD_COEFF_WALK, //!< в ходьбе
+	SPREAD_COEFF_RUN, //!<  в беге
+	SPREAD_COEFF_AIRBORNE, //!< в прыжке
+	SPREAD_COEFF_CONDITION, //!< состояние оружия
+	SPREAD_COEFF_ARM, //!< состояние рук
+	SPREAD_COEFF_IRONSIGHT, //!< в прицеливании
+};
+
 /*! Оружие
 \ingroup cbaseitem
 */
@@ -50,6 +64,19 @@ public:
 
 	bool canShoot();
 
+	//! Масса объекта
+	float getWeight();
+
+
+	//! угол (в градусах) базовой дисперсии оружия (оружия, зажатого в тисках)
+	float getBaseSpread() const;
+
+	//! в прицеливании
+	bool isIronSight() const;
+
+	//! Коэффициент разброса
+	float getSpreadCoeff(SPREAD_COEFF what) const;
+
 protected:
 
 	// Compatible addons
@@ -94,6 +121,18 @@ protected:
 	// Without mag
 	int m_iCapacity;
 	int m_iCurrentLoad;
+
+	// 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;
 };
 
 #endif
diff --git a/source/game/SXplayer.cpp b/source/game/SXplayer.cpp
index 40a8d7bc9..76e7fdf34 100644
--- a/source/game/SXplayer.cpp
+++ b/source/game/SXplayer.cpp
@@ -17,40 +17,13 @@ END_PROPTABLE()
 
 REGISTER_ENTITY(SXplayer, player);
 
-class btKinematicClosestNotMeRayResultCallback: public btCollisionWorld::ClosestRayResultCallback
-{
-public:
-	btKinematicClosestNotMeRayResultCallback(btCollisionObject* me, const btVector3&	rayFromWorld, const btVector3&	rayToWorld): btCollisionWorld::ClosestRayResultCallback(rayFromWorld, rayToWorld)
-	{
-		m_me = me;
-		m_shapeInfo = {-1, -1};
-	}
-
-	virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace)
-	{
-		if(rayResult.m_collisionObject == m_me)
-			return 1.0;
-		if(rayResult.m_localShapeInfo)
-		{
-			m_shapeInfo = *rayResult.m_localShapeInfo;
-		}
-		return ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace);
-	}
-	btCollisionWorld::LocalShapeInfo m_shapeInfo;
-protected:
-	btCollisionObject* m_me;
-};
-
 SXplayer::SXplayer(EntityManager * pMgr):
 	BaseClass(pMgr),
-	m_uMoveDir(PM_OBSERVER),
-	m_vPitchYawRoll(float3_t(0, 0, 0)),
 	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_pActiveTool(NULL),
 	m_iDSM(DSM_NONE)
 {
 	m_pCamera = (SXpointCamera*)CREATE_ENTITY("point_camera", pMgr);
@@ -58,38 +31,7 @@ SXplayer::SXplayer(EntityManager * pMgr):
 
 	m_iUpdIval = SET_INTERVAL(UpdateInput, 0);
 
-	btTransform startTransform;
-	startTransform.setIdentity();
-	startTransform.setOrigin(F3_BTVEC(m_vPosition));
-	//startTransform.setOrigin(btVector3(0, 12, 10));
 
-	m_pGhostObject = new btPairCachingGhostObject();
-	m_pGhostObject->setWorldTransform(startTransform);
-	//sweepBP->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback());
-	m_pCollideShape = new btCapsuleShape(0.4f, 1.0f);
-	m_pGhostObject->setCollisionShape(m_pCollideShape);
-	m_pGhostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT);
-	m_pGhostObject->setUserPointer(this);
-
-	btScalar stepHeight = 0.4f;
-	m_pCharacter = new btKinematicCharacterController(m_pGhostObject, (btConvexShape*)m_pCollideShape, stepHeight, btVector3(0.0f, 1.0f, 0.0f));
-	m_pCharacter->setMaxJumpHeight(0.60f);
-	m_pCharacter->setJumpSpeed(3.50f);
-	//m_pCharacter->setJumpSpeed(3.5f);
-	m_pCharacter->setGravity(btVector3(0, -10.0f, 0));
-	//m_pCharacter->setGravity(1.0f);
-	m_pCharacter->setFallSpeed(300.0f);
-	//m_pCharacter->setFallSpeed(30.0f);
-
-	SXPhysics_GetDynWorld()->addCollisionObject(m_pGhostObject, btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::AllFilter & ~btBroadphaseProxy::DebrisFilter);
-
-	m_pGhostObject->setCollisionFlags(m_pGhostObject->getCollisionFlags() | btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT);
-
-	SXPhysics_GetDynWorld()->addAction(m_pCharacter);
-
-
-
-/*
 	m_pActiveTool = (SXbaseTool*)CREATE_ENTITY("weapon_ak74", m_pMgr);
 	m_pActiveTool->SetOwner(this);
 	m_pActiveTool->AttachHands();
@@ -97,19 +39,6 @@ SXplayer::SXplayer(EntityManager * pMgr):
 	m_pActiveTool->SetPos(GetPos() + float3(1.0f, 0.0f, 1.0f));
 	m_pActiveTool->SetOrient(GetOrient());
 	m_pActiveTool->SetParent(this);
-	*/
-
-
-	m_flashlight = (CLightDirectional*)CREATE_ENTITY("light_directional", m_pMgr);
-	//m_flashlight->SetPos(GetPos() + float3(0.f, 0.1f, 0.f));
-	m_flashlight->SetPos(GetPos() + float3(0.f, 0.2f, 0.1f));
-	m_flashlight->SetOrient(GetOrient() * SMQuaternion(SM_PIDIV2, 'x'));
-	m_flashlight->SetParent(this);
-	m_flashlight->setDist(20.f);
-	m_flashlight->setAngle(SMToRadian(60));
-	m_flashlight->setColor(float3(3.5, 3.5, 3.5));
-	//m_flashlight->setShadowType(-1);
-	m_flashlight->setShadowType(1);
 
 	m_idQuadCurr = -1;
 
@@ -123,26 +52,6 @@ SXplayer::~SXplayer()
 	REMOVE_ENTITY(m_pCamera);
 }
 
-void SXplayer::playFootstepsSound()
-{
-	if(!(m_uMoveDir & PM_OBSERVER))
-	{
-		if(onGround())
-		{
-			float3 start = GetPos(),
-				end = start + float3(0.0f, -2.0f, 0.0f);
-			btKinematicClosestNotMeRayResultCallback cb(m_pGhostObject, F3_BTVEC(start), F3_BTVEC(end));
-			SXPhysics_GetDynWorld()->rayTest(F3_BTVEC(start), F3_BTVEC(end), cb);
-
-			if(cb.hasHit() && cb.m_shapeInfo.m_shapePart == 0 && cb.m_shapeInfo.m_triangleIndex >= 0)
-			{
-				MTLTYPE_PHYSIC type = (MTLTYPE_PHYSIC)SXPhysics_GetMtlType(cb.m_collisionObject, &cb.m_shapeInfo);
-				g_pGameData->playFootstepSound(type, BTVEC_F3(cb.m_hitPointWorld));
-			}
-		}
-	}
-}
-
 void SXplayer::UpdateInput(float dt)
 {
 	int x, y;
@@ -436,60 +345,6 @@ void SXplayer::SetPos(const float3 & pos)
 	m_pGhostObject->getWorldTransform().setOrigin(F3_BTVEC(pos));
 }
 
-void SXplayer::Attack(BOOL state)
-{
-	if(m_uMoveDir & PM_OBSERVER)
-	{
-		return;
-	}
-	if(m_pActiveTool)
-	{
-		m_pActiveTool->PrimaryAction(state);
-	}
-}
-
-void SXplayer::Attack2(BOOL state)
-{
-	if(m_uMoveDir & PM_OBSERVER)
-	{
-		return;
-	}
-	if(m_pActiveTool)
-	{
-		m_pActiveTool->SecondaryAction(state);
-	}
-}
-
-void SXplayer::Reload()
-{
-	if(m_uMoveDir & PM_OBSERVER)
-	{
-		return;
-	}
-	if(m_pActiveTool)
-	{
-		m_pActiveTool->Reload();
-	}
-}
-
-void SXplayer::ToggleFlashlight()
-{
-	m_flashlight->toggleEnable();
-}
-
-void SXplayer::nextFireMode()
-{
-	if(m_uMoveDir & PM_OBSERVER)
-	{
-		return;
-	}
-	if(m_pActiveTool)
-	{
-		//@FIXME: Add correct call
-		//m_pActiveTool->nextFireMode();
-	}
-}
-
 void SXplayer::_ccmd_slot_on(int argc, const char ** argv)
 {
 	if(argc != 2)
@@ -530,7 +385,11 @@ float3_t & SXplayer::GetWeaponDeltaAngles()
 	return(m_vWpnShakeAngles);
 }
 
-bool SXplayer::onGround()
+void SXplayer::updateSpread(float dt)
 {
-	return(m_pCharacter->onGround());
+	BaseClass::updateSpread(dt);
+	if(m_pCrosshair)
+	{
+		m_pCrosshair->SetSize(getCurrentSpread() * 0.1f);
+	}
 }
diff --git a/source/game/SXplayer.h b/source/game/SXplayer.h
index 1abb17615..d0812e233 100644
--- a/source/game/SXplayer.h
+++ b/source/game/SXplayer.h
@@ -16,34 +16,14 @@ See the license in LICENSE
 #ifndef _SXplayer_H_
 #define _SXplayer_H_
 
-#include "SXbaseAnimating.h"
+#include "CBaseCharacter.h"
 #include "SXpointCamera.h"
-#include "LightDirectional.h"
 #include "crosshair.h"
 
-//! Типы движения игрока
-enum PLAYER_MOVE
-{
-	PM_NONE = 0,
-	PM_FORWARD = 0x01,   //!< вперед
-	PM_BACKWARD = 0x02,  //!< назад
-	PM_LEFT = 0x04,      //!< влево
-	PM_RIGHT = 0x08,     //!< вправо
-	PM_CROUCH = 0x10,    //!< присесть
-	PM_JUMP = 0x20,      //!< прыгнуть
-	PM_RUN = 0x40,       //!< бежать
-	PM_CRAWL = 0x80,     //!< лежать
-	PM_OBSERVER = 0x100, //!< наблюдатель
-
-	PM_STOP = 0xFFFF
-};
-
-class SXbaseTool;
-
 //! Класс игрока  \ingroup cbaseanimating
-class SXplayer: public SXbaseAnimating
+class SXplayer: public CBaseCharacter
 {
-	DECLARE_CLASS(SXplayer, SXbaseAnimating);
+	DECLARE_CLASS(SXplayer, CBaseCharacter);
 	DECLARE_PROPTABLE();
 public:
 	SXplayer(EntityManager * pMgr);
@@ -73,18 +53,7 @@ public:
 
 	//! Устанавливает положение в мире
 	void SetPos(const float3 & pos);
-
-	//! Запускает/останавливает первичную атаку
-	void Attack(BOOL state);
-	//! Запускает/останавливает вторичную атаку
-	void Attack2(BOOL state);
-	//! Запускает перезарядку активного оружия
-	void Reload();
-	//! Включает/выключает фонарь
-	void ToggleFlashlight();
-	//! Переключает режим стрельбы активного оружия
-	void nextFireMode();
-
+	
 	/*! Возаращает мировую позицию для модели оружия
 		\note Устарело?
 	*/
@@ -99,37 +68,13 @@ public:
 	//! Получает объект перекрестия
 	Crosshair * GetCrosshair();
 
-	//! Находится ли игрок на земле
-	bool onGround();
-
-	//! Воспроизводит звук шагов с учетом материала на котором стоит игрок
-	void playFootstepsSound();
-
 protected:
-	//! Фонарик
-	CLightDirectional* m_flashlight;
 	//! Камера
 	SXpointCamera * m_pCamera;
 
-	//! Текущее движение
-	UINT m_uMoveDir;
-
 	//! ID интервала обновления
 	ID m_iUpdIval;
 
-	//! Углы вращения игрока
-	float3_t m_vPitchYawRoll;
-
-	//! Для физики @{
-	btCollisionShape * m_pCollideShape;
-	btRigidBody * m_pRigidBody;
-	btPairCachingGhostObject * m_pGhostObject;
-	btKinematicCharacterController * m_pCharacter;
-	//! @}
-
-	//! Текущий инструмент в руках
-	SXbaseTool * m_pActiveTool;
-
 	//! Может ли прыгать
 	bool m_canJump;
 
@@ -146,6 +91,9 @@ protected:
 	Crosshair * m_pCrosshair;
 
 	ID m_idQuadCurr;	//!< текущий квад аи сетки на котором стоит игрок
+
+	//! Обновляет разброса значение
+	virtual void updateSpread(float dt);
 };
 
 #endif
diff --git a/source/game/crosshair.cpp b/source/game/crosshair.cpp
index aa3abddf4..77d9950a9 100644
--- a/source/game/crosshair.cpp
+++ b/source/game/crosshair.cpp
@@ -67,8 +67,8 @@ void Crosshair::Update()
 		static const int *r_win_height = GET_PCVAR_INT("r_win_height");
 
 		//build new buffer
-		float fScreenWidth = *r_win_width;
-		float fScreenHeight = *r_win_height;
+		float fScreenWidth = (float)*r_win_width;
+		float fScreenHeight = (float)*r_win_height;
 		float fTexWidth = m_f2TexSize.x;
 		float fTexHeight = m_f2TexSize.y;
 		float fXradius = fTexWidth / fScreenWidth * 0.5f;
@@ -359,6 +359,15 @@ void Crosshair::Render()
 	SGCore_ShaderUnBind();
 	m_pDev->SetTexture(0, m_pTexture);
 	m_pDev->SetRenderState(D3DRS_ZWRITEENABLE, D3DZB_FALSE);
+
+	// Использовать альфа-канал в качестве источника альфа-компонент
+	m_pDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
+	m_pDev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
+
+	// Устанавливаем коэффициенты смешивания таким образом,
+	// чтобы альфа-компонента определяла прозрачность
+	m_pDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
+	m_pDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
 	
 	//m_pDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC);
 	//m_pDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC);
-- 
GitLab