Skip to content
Snippets Groups Projects
BaseTool.cpp 11.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • 
    /***********************************************************
    Copyright © Vitaliy Buturlin, Evgeny Danilovich, 2017, 2018
    See the license in LICENSE
    ***********************************************************/
    
    
    #include "BaseTool.h"
    
    D-AIRY's avatar
    D-AIRY committed
    #include <particles/sxparticles.h>
    
    #include "Player.h"
    
    D-AIRY's avatar
    D-AIRY committed
    /*! \skydocent base_tool
    Базовый класс для инструмента (в т.ч оружие). То, что игрок может взять в руки и использовать
    */
    
    
    
    BEGIN_PROPTABLE(CBaseTool)
    
    D-AIRY's avatar
    D-AIRY committed
    	//! Время перезарядки, с
    
    	DEFINE_FIELD_FLOAT(m_fReloadTime, PDFF_NOEDIT | PDFF_NOEXPORT, "reload_time", "", EDITOR_NONE)
    
    D-AIRY's avatar
    D-AIRY committed
    	//! Время прицеливания, с
    
    D-AIRY's avatar
    D-AIRY committed
    	DEFINE_FIELD_FLOAT(m_fZoomTime, PDFF_NOEDIT | PDFF_NOEXPORT, "zoom_time", "", EDITOR_NONE)
    
    D-AIRY's avatar
    D-AIRY committed
    	//! Смещение визуальной модели
    
    D-AIRY's avatar
    D-AIRY committed
    	DEFINE_FIELD_VECTOR(m_vSlotPos, PDFF_NOEDIT | PDFF_NOEXPORT, "slot_offset", "", EDITOR_NONE)
    
    D-AIRY's avatar
    D-AIRY committed
    	//! Вращение визуальной модели
    
    D-AIRY's avatar
    D-AIRY committed
    	DEFINE_FIELD_ANGLES(m_qSlotRot, PDFF_NOEDIT | PDFF_NOEXPORT, "slot_rotation", "", EDITOR_NONE)
    
    D-AIRY's avatar
    D-AIRY committed
    	//! Смещение визуальной модели в прицеливании
    
    D-AIRY's avatar
    D-AIRY committed
    	DEFINE_FIELD_VECTOR(m_vSlotPosAim, PDFF_NOEDIT | PDFF_NOEXPORT, "slot_offset_aim", "", EDITOR_NONE)
    
    D-AIRY's avatar
    D-AIRY committed
    	//! Вращение визуальной модели в прицеливании
    
    D-AIRY's avatar
    D-AIRY committed
    	DEFINE_FIELD_ANGLES(m_qSlotRotAim, PDFF_NOEDIT | PDFF_NOEXPORT, "slot_rotation_aim", "", EDITOR_NONE)
    
    D-AIRY's avatar
    D-AIRY committed
    	//! Смещение визуальной модели при приближении к стене
    	DEFINE_FIELD_VECTOR(m_vSlotPosClose, PDFF_NOEDIT | PDFF_NOEXPORT, "slot_offset_close", "", EDITOR_NONE)
    	//! Вращение визуальной модели при приближении к стене
    	DEFINE_FIELD_ANGLES(m_qSlotRotClose, PDFF_NOEDIT | PDFF_NOEXPORT, "slot_rotation_close", "", EDITOR_NONE)
    
    	//! Расстояние от центра модели до кончика ствола
    	DEFINE_FIELD_FLOAT(m_fCenterLength, PDFF_NOEDIT | PDFF_NOEXPORT, "center_length", "", EDITOR_NONE)
    
    D-AIRY's avatar
    D-AIRY committed
    	
    
    D-AIRY's avatar
    D-AIRY committed
    	//! Разрешить прицеливание
    
    D-AIRY's avatar
    D-AIRY committed
    	DEFINE_FIELD_INT(m_iZoomable, PDFF_NOEDIT | PDFF_NOEXPORT, "zoomable", "", EDITOR_NONE)
    
    
    D-AIRY's avatar
    D-AIRY committed
    	//! Звук первичного действия
    
    D-AIRY's avatar
    D-AIRY committed
    	DEFINE_FIELD_STRING(m_szPrimaryActionSound, PDFF_NOEDIT | PDFF_NOEXPORT, "action1_sound", "", EDITOR_NONE)
    
    D-AIRY's avatar
    D-AIRY committed
    	//! Звук вторичного действия
    
    D-AIRY's avatar
    D-AIRY committed
    	DEFINE_FIELD_STRING(m_szSecondaryActionSound, PDFF_NOEDIT | PDFF_NOEXPORT, "action2_sound", "", EDITOR_NONE)
    
    D-AIRY's avatar
    D-AIRY committed
    	//! Эффект первичного действия
    
    D-AIRY's avatar
    D-AIRY committed
    	DEFINE_FIELD_STRING(m_szPrimaryActionMuzzleflash, PDFF_NOEDIT | PDFF_NOEXPORT, "action1_muzzle", "", EDITOR_NONE)
    
    D-AIRY's avatar
    D-AIRY committed
    	//! Эффект вторичного действия
    
    D-AIRY's avatar
    D-AIRY committed
    	DEFINE_FIELD_STRING(m_szSecondaryActionMuzzleflash, PDFF_NOEDIT | PDFF_NOEXPORT, "action2_muzzle", "", EDITOR_NONE)
    	
    
    D-AIRY's avatar
    D-AIRY committed
    	//! Максимальная дальность
    
    D-AIRY's avatar
    D-AIRY committed
    	DEFINE_FIELD_FLOAT(m_fMaxDistance, PDFF_NOEDIT | PDFF_NOEXPORT, "max_distance", "", EDITOR_NONE)
    
    D-AIRY's avatar
    D-AIRY committed
    	//! Подходящие типы припасов, классы, через запятую
    
    D-AIRY's avatar
    D-AIRY committed
    	DEFINE_FIELD_STRING(m_szUsableAmmos, PDFF_NOEDIT | PDFF_NOEXPORT, "ammos", "", EDITOR_NONE)
    
    D-AIRY's avatar
    D-AIRY committed
    	//! Класс заряженного в данный момент припаса
    	DEFINE_FIELD_STRING(m_szLoadedAmmo, PDFF_NOEDIT | PDFF_NOEXPORT, "loaded_ammo", "", EDITOR_NONE)
    
    D-AIRY's avatar
    D-AIRY committed
    
    
    END_PROPTABLE()
    
    
    REGISTER_ENTITY_NOLISTING(CBaseTool, base_tool);
    
    D-AIRY's avatar
    D-AIRY committed
    
    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;
    };
    
    
    CBaseTool::CBaseTool(CEntityManager * pMgr):
    
    	BaseClass(pMgr),
    	m_bInPrimaryAction(false),
    	m_bInSecondaryAction(false),
    	m_bWorldModel(false),
    	m_bCanUse(true),
    	m_fZoomTime(0.0f),
    
    D-AIRY's avatar
    D-AIRY committed
    	m_fReloadTime(0.0f),
    
    D-AIRY's avatar
    D-AIRY committed
    	m_iZoomable(1),
    	m_iSoundAction1(-1),
    	m_iSoundAction2(-1),
    	m_iMuzzleFlash(-1),
    	m_iMuzzleFlash2(-1),
    
    D-AIRY's avatar
    D-AIRY committed
    	m_bIsWeapon(false),
    	m_pLoadedAmmo(NULL)
    
    {
    	m_bInvStackable = false;
    
    	m_iIvalUpdate = SET_INTERVAL(_update, 0);
    
    CBaseTool::~CBaseTool()
    
    D-AIRY's avatar
    D-AIRY committed
    {
    	CLEAR_INTERVAL(m_iIvalUpdate);
    
    void CBaseTool::onPostLoad()
    
    D-AIRY's avatar
    D-AIRY committed
    {
    
    	BaseClass::onPostLoad();
    
    D-AIRY's avatar
    D-AIRY committed
    
    	if(m_szPrimaryActionSound[0])
    	{
    
    		m_iSoundAction1 = SSCore_SndCreate3dInst(m_szPrimaryActionSound, SX_SOUND_CHANNEL_GAME, 100);
    
    D-AIRY's avatar
    D-AIRY committed
    	}
    	if(m_szSecondaryActionSound[0])
    	{
    
    		m_iSoundAction2 = SSCore_SndCreate3dInst(m_szSecondaryActionSound, SX_SOUND_CHANNEL_GAME, 100);
    
    D-AIRY's avatar
    D-AIRY committed
    	}
    	if(m_szPrimaryActionMuzzleflash[0])
    	{
    		m_iMuzzleFlash = SPE_EffectInstanceByName(m_szPrimaryActionMuzzleflash);
    	}
    	if(m_szSecondaryActionMuzzleflash[0])
    	{
    		m_iMuzzleFlash2 = SPE_EffectInstanceByName(m_szSecondaryActionMuzzleflash);
    	}
    }
    
    
    void CBaseTool::setNextUse(float time)
    
    {
    	m_bCanUse = false;
    
    	SET_TIMEOUT(_allowUse, time);
    
    bool CBaseTool::canUse()
    
    D-AIRY's avatar
    D-AIRY committed
    	return(m_bCanUse && !m_bInPrimaryAction);
    
    void CBaseTool::primaryAction(BOOL st)
    
    {
    	m_bInPrimaryAction = st != FALSE;
    
    D-AIRY's avatar
    D-AIRY committed
    	if(st)
    	{
    
    		playAnimation("shoot1");
    
    D-AIRY's avatar
    D-AIRY committed
    		if(ID_VALID(m_iMuzzleFlash))
    		{
    
    D-AIRY's avatar
    D-AIRY committed
    		}
    		if(ID_VALID(m_iSoundAction1))
    		{
    
    D-AIRY's avatar
    D-AIRY committed
    		}
    
    
    		//((CPlayer*)m_pOwner)->is
    
    		float3 start = getPos();
    		float3 dir = m_pParent->getOrient() * float3(0.0f, 0.0f, 1.0f);
    
    D-AIRY's avatar
    D-AIRY committed
    		float3 end = start + dir * m_fMaxDistance;
    
    		btCollisionWorld::ClosestRayResultCallback cb(F3_BTVEC(start), F3_BTVEC(end));
    
    		SPhysics_GetDynWorld()->rayTest(F3_BTVEC(start), F3_BTVEC(end), cb);
    
    
    		if(cb.hasHit())
    		{
    			//shoot decal
    			SXDecals_ShootDecal(DECAL_TYPE_CONCRETE, BTVEC_F3(cb.m_hitPointWorld), BTVEC_F3(cb.m_hitNormalWorld));
    
    			SPE_EffectPlayByName("fire", &BTVEC_F3(cb.m_hitPointWorld), &BTVEC_F3(cb.m_hitNormalWorld));
    
    			if(!cb.m_collisionObject->isStaticOrKinematicObject())
    			{
    				((btRigidBody*)cb.m_collisionObject)->applyCentralImpulse(F3_BTVEC(dir * 10.0f));
    				cb.m_collisionObject->activate();
    			}
    		}
    
    void CBaseTool::secondaryAction(BOOL st)
    
    {
    	m_bInSecondaryAction = st != FALSE;
    
    D-AIRY's avatar
    D-AIRY committed
    	if(m_iZoomable)
    	{
    
    		((CPlayer*)m_pOwner)->getCrosshair()->enable(!st);
    
    D-AIRY's avatar
    D-AIRY committed
    	}
    
    void CBaseTool::setIsWorldModel(bool b)
    
    {
    	m_bWorldModel = b;
    }
    
    
    void CBaseTool::reload()
    
    	if(canUse())
    
    		setNextUse(m_fReloadTime);
    		playAnimation("reload");
    
    void CBaseTool::dbgMove(int dir, float dy)
    
    D-AIRY's avatar
    D-AIRY committed
    {
    	switch(dir)
    	{
    	case DSM_POS_X:
    
    D-AIRY's avatar
    D-AIRY committed
    		m_vSlotPosResult.x += dy;
    
    D-AIRY's avatar
    D-AIRY committed
    		break;
    	case DSM_POS_Y:
    
    D-AIRY's avatar
    D-AIRY committed
    		m_vSlotPosResult.y += dy;
    
    D-AIRY's avatar
    D-AIRY committed
    		break;
    	case DSM_POS_Z:
    
    D-AIRY's avatar
    D-AIRY committed
    		m_vSlotPosResult.z += dy;
    
    D-AIRY's avatar
    D-AIRY committed
    		break;
    	case DSM_ROT_X:
    
    D-AIRY's avatar
    D-AIRY committed
    		m_qSlotRotResult = m_qSlotRotResult * SMQuaternion(dy, 'x');
    
    D-AIRY's avatar
    D-AIRY committed
    		break;
    	case DSM_ROT_Y:
    
    D-AIRY's avatar
    D-AIRY committed
    		m_qSlotRotResult = m_qSlotRotResult * SMQuaternion(dy, 'y');
    
    D-AIRY's avatar
    D-AIRY committed
    		break;
    	case DSM_ROT_Z:
    
    D-AIRY's avatar
    D-AIRY committed
    		m_qSlotRotResult = m_qSlotRotResult * SMQuaternion(dy, 'z');
    
    D-AIRY's avatar
    D-AIRY committed
    		break;
    
    D-AIRY's avatar
    D-AIRY committed
    	case DSM_LEN:
    		m_fCenterLength += dy;
    		break;
    
    D-AIRY's avatar
    D-AIRY committed
    
    	case DSM_PRINT:
    
    D-AIRY's avatar
    D-AIRY committed
    		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
    
    D-AIRY's avatar
    D-AIRY committed
    			, m_vOffsetPos.x, m_vOffsetPos.y, m_vOffsetPos.z
    
    D-AIRY's avatar
    D-AIRY committed
    			, m_qSlotRotResult.x, m_qSlotRotResult.y, m_qSlotRotResult.z, m_qSlotRotResult.w
    			, m_fCenterLength);
    
    void CBaseTool::onSync()
    
    D-AIRY's avatar
    D-AIRY committed
    	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;
    	}
    
    D-AIRY's avatar
    D-AIRY committed
    	m_vOffsetPos = m_vSlotPosResult;
    
    	BaseClass::onSync();
    
    D-AIRY's avatar
    D-AIRY committed
    	if(m_pModel && m_pModel->asAnimatedModel())
    
    D-AIRY's avatar
    D-AIRY committed
    		//SPE_EffectPlayByID
    
    D-AIRY's avatar
    D-AIRY committed
    		float3 pos = m_pModel->asAnimatedModel()->getBoneTransformPos(m_pModel->asAnimatedModel()->getBoneId("muzzle_rifle1"));
    
    		//pos = m_vOrientation * float3(0, 0, 1);
    
    void CBaseTool::_update(float dt)
    
    D-AIRY's avatar
    D-AIRY committed
    	if(m_inventoryMode == IIM_EQUIPPED && m_fCenterLength > 0.4f /* player capsule radius */) 
    	{
    		// raycast towards to check if
    		float3 start = m_pParent->getPos();
    		float3 dir = m_pParent->getOrient() * float3(0.0f, 0.0f, 1.0f);
    		float3 end = start + dir * m_fCenterLength;
    
    D-AIRY's avatar
    D-AIRY committed
    		btKinematicClosestNotMeRayResultCallback cb(((CBaseCharacter*)m_pOwner)->getBtCollisionObject(), F3_BTVEC(start), F3_BTVEC(end));
    
    D-AIRY's avatar
    D-AIRY committed
    		SPhysics_GetDynWorld()->rayTest(F3_BTVEC(start), F3_BTVEC(end), cb);
    
    		m_isClose = cb.hasHit();
    	}
    
    	bool needRezoom = false;
    
    D-AIRY's avatar
    D-AIRY committed
    	float speed = 1.0f / m_fZoomTime;
    	if(m_bInSecondaryAction && m_iZoomable)
    
    D-AIRY's avatar
    D-AIRY committed
    	{
    		if(m_fZoomProgress < 1.0f)
    		{
    
    D-AIRY's avatar
    D-AIRY committed
    			m_fZoomProgress += dt * speed;
    
    D-AIRY's avatar
    D-AIRY committed
    			if(m_fZoomProgress > 1.0f)
    			{
    				m_fZoomProgress = 1.0f;
    			}
    
    D-AIRY's avatar
    D-AIRY committed
    			needRezoom = true;
    
    D-AIRY's avatar
    D-AIRY committed
    		}
    	}
    	else
    	{
    		if(m_fZoomProgress > 0.0f)
    		{
    
    D-AIRY's avatar
    D-AIRY committed
    			m_fZoomProgress -= dt * speed;
    
    D-AIRY's avatar
    D-AIRY committed
    			if(m_fZoomProgress < 0.0f)
    			{
    				m_fZoomProgress = 0.0f;
    			}
    
    D-AIRY's avatar
    D-AIRY committed
    			needRezoom = true;
    		}
    	}
    
    	if(m_isClose)
    	{
    		if(m_fCloseProgress < 1.0f)
    		{
    			m_fCloseProgress += dt * speed;
    			if(m_fCloseProgress > 1.0f)
    			{
    				m_fCloseProgress = 1.0f;
    			}
    			needRezoom = true;
    
    D-AIRY's avatar
    D-AIRY committed
    	else
    	{
    		if(m_fCloseProgress > 0.0f)
    		{
    			m_fCloseProgress -= dt * speed;
    			if(m_fCloseProgress < 0.0f)
    			{
    				m_fCloseProgress = 0.0f;
    			}
    			needRezoom = true;
    		}
    	}
    
    	if(needRezoom)
    	{
    		_rezoom();
    	}
    
    void CBaseTool::setParent(CBaseEntity * pEnt, int attachment)
    
    	BaseClass::setParent(pEnt, attachment);
    
    void CBaseTool::_rezoom()
    
    	const float * r_default_fov = GET_PCVAR_FLOAT("r_default_fov");
    
    D-AIRY's avatar
    D-AIRY committed
    	m_vSlotPosResult = (float3)vlerp(vlerp(m_vSlotPos, m_vSlotPosClose, m_fCloseProgress), m_vSlotPosAim, m_fZoomProgress);
    
    D-AIRY's avatar
    D-AIRY committed
    	//m_vWpnShakeAngles
    
    D-AIRY's avatar
    D-AIRY committed
    	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)));
    
    bool CBaseTool::isWeapon() const
    
    float CBaseTool::getCondition() const
    
    D-AIRY's avatar
    D-AIRY committed
    
    CBaseSupply *CBaseTool::getAmmo() const
    {
    	return(m_pLoadedAmmo);
    }
    
    void CBaseTool::chargeAmmo(CBaseSupply *pAmmo)
    {
    	if(!pAmmo || !isValidAmmo(pAmmo))
    	{
    		return;
    	}
    	if(getAmmo())
    	{
    		uncharge();
    	}
    	m_pLoadedAmmo = pAmmo;
    	m_pLoadedAmmo->setParent(this);
    	_setStrVal(&m_szLoadedAmmo, m_pLoadedAmmo->getClassName());
    }
    
    void CBaseTool::uncharge()
    {
    	if(!getAmmo())
    	{
    		return;
    	}
    	_setStrVal(&m_szLoadedAmmo, "");
    	m_pLoadedAmmo->setParent(NULL);
    	//getOwner()->getInventory()->put(getAmmo());
    	m_pLoadedAmmo = NULL;
    }
    
    bool CBaseTool::isValidAmmo(CBaseSupply *pAmmo)
    {
    	const char * str = strstr(m_szUsableAmmos, pAmmo->getClassName());
    	if(str)
    	{
    		char chr = str[strlen(pAmmo->getClassName())];
    		return(chr == ',' || chr == 0);
    	}
    	return(false);
    }
    
    float CBaseTool::getMaxDistance() const
    {
    	return(m_fMaxDistance);
    }
    
    D-AIRY's avatar
    D-AIRY committed
    
    void CBaseTool::updateHUDinfo()
    {
    }