float GetQuatAbsAngle(const Quat& q)
{
	//float fwd = q.GetColumn1().y;
	float fwd = q.GetFwdY();
	fwd = clamp_tpl(fwd, -1.0f, 1.0f);
	return acos_tpl(fwd);
}
Esempio n. 2
0
inline float AngleBetweenVectors( const Vec3 &v1,const Vec3 &v2 )
{
	float a = acos_tpl(v1.Dot(v2));
	Vec3 r = v1.Cross(v2);
	if (r.z < 0)
		a = -a;
	return a;
}
Esempio n. 3
0
//------------------------------------------------------------------------
bool CGunTurret::GetTargetAngles(const Vec3 &targetPos, float &z, float &x) const
{
	// turret rotation reachability check
	Vec3 weaponPos = GetWeaponPos();
	Vec3 targetDir = targetPos - weaponPos;

	if(targetDir.len2() < minLenSqr)
		return false;

	// local dir to target
	Vec3 targetDirLocal = GetEntity()->GetWorldTM().GetInverted().TransformVector(targetDir);

	// angle around z
	Vec3 targetDirZ(targetDirLocal.x, targetDirLocal.y, 0.f);

	if(targetDirZ.len2() < minLenSqr)
		z = 0.f;
	else
	{
		targetDirZ.Normalize();
		float cosZ = max(-1.f, min(1.f, FORWARD_DIRECTION * targetDirZ));
		z = acos_tpl(cosZ) * -sgnnz(targetDirZ.x);

		if(z<0.0f)
			z+=gf_PI2;
	}

	// angle around x
	Vec3 targetDirX(targetDirLocal);
	Vec3 targetDirBase(targetDirLocal.x, targetDirLocal.y, 0);

	if(targetDirBase.len2() < minLenSqr)
		x = 0.0f;
	else
	{
		targetDirX.Normalize();
		targetDirBase.Normalize();

		float cosX = max(-1.f, min(1.f, targetDirBase * targetDirX));
		x = acos_tpl(cosX) * sgnnz(targetDirX.z);
	}

	return true;
}
Esempio n. 4
0
	bool operator() (const SSpectacularKillAnimation& killAnim) const
	{
		const SSpectacularKillCVars& skCVars = g_pGameCVars->g_spectacularKill;
		const CActor* pOwner = m_spectacularKill.m_pOwner;

		// 0. the anim shouldn't be redundant
		if (((gEnv->pTimer->GetFrameStartTime().GetSeconds() - s_lastKillInfo.timeStamp) <= skCVars.minTimeBetweenSameKills) &&
			(killAnim.killerAnimation.compare(s_lastKillInfo.killerAnim)))
		{
			SK_DEBUG_LOG("GetValidAnim - %s is not valid: This animation was last played %.1f ago, a minimum time of %.1f is required", 
				killAnim.killerAnimation.c_str(), (gEnv->pTimer->GetFrameStartTime().GetSeconds() - s_lastKillInfo.timeStamp), skCVars.minTimeBetweenSameKills);

			return true;
		}


		// 1. the killer needs to be within a certain distance from the target
		IEntity* pTargetEntity = m_pTarget->GetEntity();
		IEntity* pKillerEntity = pOwner->GetEntity();

		const QuatT& killerTransform = pOwner->GetAnimatedCharacter()->GetAnimLocation();
		const QuatT& targetTransform = m_pTarget->GetAnimatedCharacter()->GetAnimLocation();
		const Vec3& vKillerPos = killerTransform.t;
		const Vec3& vTargetPos = targetTransform.t;

		Vec2 vKillerToTarget = Vec2(vTargetPos) - Vec2(vKillerPos);
		float distance = vKillerToTarget.GetLength();

		const float optimalDistance = killAnim.optimalDist;
		if ((optimalDistance > 0.0f) && (fabs_tpl(distance - optimalDistance) > skCVars.maxDistanceError))
		{
#ifndef _RELEASE
			if (g_pGameCVars->g_spectacularKill.debug > 1)
			{
				// visually shows why it failed
				IPersistantDebug* pPersistantDebug = m_spectacularKill.BeginPersistantDebug();
				const float fConeHeight = killAnim.optimalDist + skCVars.maxDistanceError;
				pPersistantDebug->AddPlanarDisc(vTargetPos, killAnim.optimalDist - skCVars.maxDistanceError, killAnim.optimalDist + skCVars.maxDistanceError, Col_Coral, 6.0f);
				pPersistantDebug->AddLine(vKillerPos, vKillerPos + Vec3(0.f, 0.f, 5.0f), Col_Red, 6.f);
			}

			SK_DEBUG_LOG("GetValidAnim - %s is not valid: Distance between actors should be %.2f, is %.2f (max error is %f)", 
				killAnim.killerAnimation.c_str(), optimalDistance, distance, skCVars.maxDistanceError);
#endif

			return true;
		}


		// 2. The killer needs to be facing the target within cosLookToConeHalfAngleRadians angle
		Vec2 vKillerDir(killerTransform.GetColumn1()); // In decoupled catchup mode we need the animated character's orientation
		vKillerDir.Normalize();
		if (vKillerToTarget.GetNormalizedSafe().Dot(vKillerDir) <= skCVars.minKillerToTargetDotProduct)
		{
			SK_DEBUG_LOG("GetValidAnim - %s is not valid: Killer is not looking within %.2f degrees towards the target", 
				killAnim.killerAnimation.c_str(), RAD2DEG(acos_tpl(skCVars.minKillerToTargetDotProduct) * 2.0f));

			return true;
		}


		// 3. If specified, the killer needs to be within a certain angle range from a given reference orientation from the target
		// e.g. Specifying referenceAngle 180 means using the back of the target as the center of the angle range 
		// (imagine it as a cone) where the killer has to be for the kill to be valid
		if (killAnim.targetToKillerAngle >= 0.f)
		{
			const float referenceAngle = killAnim.targetToKillerAngle;

			// Find the reference vector which will be the center of the allowed angle range
			Vec2 vTargetDir(targetTransform.GetColumn1());
			vTargetDir.Normalize();

			// 2D rotation
			Vec2 vReferenceDir((vTargetDir.x * cosf(referenceAngle)) - (vTargetDir.y * sinf(referenceAngle)), 
				(vTargetDir.y * cosf(referenceAngle)) + (vTargetDir.x * sinf(referenceAngle)));

			if (vKillerToTarget.GetNormalizedSafe().Dot(-vReferenceDir) <= killAnim.targetToKillerMinDot)
			{
#ifndef _RELEASE
				if (g_pGameCVars->g_spectacularKill.debug > 1)
				{
					// visually shows why it failed
					IPersistantDebug* pPersistantDebug = m_spectacularKill.BeginPersistantDebug();
					const float fConeHeight = killAnim.optimalDist + skCVars.maxDistanceError;
					pPersistantDebug->AddCone(vTargetPos + (vReferenceDir * fConeHeight), -vReferenceDir, killAnim.targetToKillerMinDot * fConeHeight * 2.0f, fConeHeight, Col_Coral, 6.f);
					pPersistantDebug->AddLine(vKillerPos, vKillerPos + Vec3(0.f, 0.f, 5.0f), Col_Red, 6.f);
				}

				float targetToKillerDot = vTargetDir.GetNormalizedSafe().Dot(-vKillerToTarget);
				SK_DEBUG_LOG("GetValidAnim - %s is not valid: Killer is not within a %.2f degrees cone centered on the target's %.2f degrees. Killer is at %.2f angles respect the target", 
					killAnim.killerAnimation.c_str(), RAD2DEG(acos_tpl(killAnim.targetToKillerMinDot) * 2.0f), RAD2DEG(killAnim.targetToKillerAngle), RAD2DEG(acos_tpl(targetToKillerDot)));
#endif

				return true;
			}
		}

		SK_DEBUG_LOG("GetValidAnim - %s is valid", killAnim.killerAnimation.c_str());
		return false;
	}
//------------------------------------------------------------------------
void CGameRulesMPDamageHandling::SvOnExplosion(const ExplosionInfo &explosionInfo, const CGameRules::TExplosionAffectedEntities& affectedEntities)
{
	// SinglePlayer.lua 1721

	IActorSystem* pActorSystem = g_pGame->GetIGameFramework()->GetIActorSystem();
	float totalDamage = 0.f;

	// calculate damage for each entity
	CGameRules::TExplosionAffectedEntities::const_iterator it = affectedEntities.begin();
	for (; it != affectedEntities.end(); ++it)
	{
		bool success = false;
		IEntity* entity = it->first;
		float obstruction = 1.0f - it->second;

		bool incone=true;
		if (explosionInfo.angle > 0 && explosionInfo.angle < 2*3.1415f)
		{
			Vec3 explosionEntityPos = entity->GetWorldPos();
			Vec3 entitypos = explosionEntityPos;
			float ha = explosionInfo.angle * 0.5f;
			Vec3 edir = entitypos - explosionInfo.pos;
			edir.normalize();
			float dot = 1;

			if (edir != Vec3(ZERO))
			{
				dot = edir.dot(explosionInfo.dir);
			}

			float angle = abs(acos_tpl(dot));
			if (angle > ha)
			{
				incone = false;
			}
		}

		if (incone && gEnv->bServer)
		{
			float damage = explosionInfo.damage;
			damage = floor_tpl(0.5f + CalcExplosionDamage(entity, explosionInfo, obstruction));	

			bool dead = false;

			HitInfo explHit;

			Vec3 dir = entity->GetWorldPos() - explosionInfo.pos;

			explHit.pos = explosionInfo.pos;
			explHit.radius = explosionInfo.radius;
			explHit.partId = -1;

			dir.Normalize();

			explHit.targetId = entity->GetId();
			explHit.weaponId = explosionInfo.weaponId;
			explHit.shooterId = explosionInfo.shooterId;
			explHit.projectileId = explosionInfo.projectileId;
			explHit.projectileClassId = explosionInfo.projectileClassId;

			uint16 weaponClass = ~uint16(0);
			const IEntity* pWeaponEntity = gEnv->pEntitySystem->GetEntity(explosionInfo.weaponId);
			if (pWeaponEntity)
			{
				g_pGame->GetIGameFramework()->GetNetworkSafeClassId(weaponClass, pWeaponEntity->GetClass()->GetName());
			}
			explHit.weaponClassId = weaponClass;

			explHit.material = 0;
			explHit.damage = damage;
			explHit.type = explosionInfo.type;
			explHit.hitViaProxy = explosionInfo.explosionViaProxy;

			explHit.dir = dir;
			explHit.normal = -dir; //set normal to reverse of  direction to avoid backface cull of damage

			if (explHit.damage > 0.0f || explosionInfo.damage == 0.f)
			{
				CActor* pActor = static_cast<CActor*>(pActorSystem->GetActor(entity->GetId()));

				if (pActor)
				{
					const float damageMultiplier = pActor->GetBodyExplosionDamageMultiplier(explHit);
					explHit.damage *= damageMultiplier; 

					// Protect players who are currently shielded
					if(pActor->IsPlayer() && static_cast<CPlayer*>(pActor)->ShouldFilterOutExplosion(explHit))
					{
						explHit.damage = 0.0f;
					}
				}
				else
				{
					CInteractiveObjectEx* pInteractiveObject = static_cast<CInteractiveObjectEx*>(g_pGame->GetIGameFramework()->QueryGameObjectExtension(entity->GetId(), "InteractiveObjectEx"));
					if(pInteractiveObject)
					{
						pInteractiveObject->OnExploded(explHit.pos);
					}
				}
			
				if(!explosionInfo.explosionViaProxy) 
				{
					if(pActor)
					{
						if(!pActor->IsFriendlyEntity(explHit.shooterId))
						{
							totalDamage += damage;
						}
					}
					else
					{
						IVehicle* pVehicle = g_pGame->GetIGameFramework()->GetIVehicleSystem()->GetVehicle(entity->GetId());

						if(pVehicle)
						{
							IActor* pDriver = pVehicle->GetDriver();
							int seatNum = 0;
							int numSeats = pVehicle->GetSeatCount();

							while(!pDriver && seatNum < numSeats)
							{
								IVehicleSeat* pSeat = pVehicle->GetSeatById(seatNum++);

								EntityId passengerId = pSeat ? pSeat->GetPassenger(true) : 0;
								pDriver = pActorSystem->GetActor(passengerId);
							}

							if(pDriver)
							{
								CActor* pDriverActor = static_cast<CActor*>(pDriver);
								if(!pDriverActor->IsFriendlyEntity(explHit.shooterId))
								{
									totalDamage += damage;
								}
							}
						}
					}
				}
				
				m_pGameRules->ServerHit(explHit);
			}
		}
	}

	if (totalDamage > 0.f)
	{
		IGameRulesPlayerStatsModule*  pPlayStatsMod = m_pGameRules->GetPlayerStatsModule();

		if(pPlayStatsMod)
		{
			pPlayStatsMod->ProcessSuccessfulExplosion(explosionInfo.shooterId, totalDamage, explosionInfo.projectileClassId);
		}
	}
}
Esempio n. 6
0
void CHUD::AutoSnap()
{
	const float fRadius = 25.0f;
	static Vec2 s_vCursor = Vec2(0,0);
	if(fabsf(m_fAutosnapCursorControllerX)>0.1 || fabsf(m_fAutosnapCursorControllerY)>0.1)
	{
		s_vCursor.x = m_fAutosnapCursorControllerX * 30.0f;
		s_vCursor.y = m_fAutosnapCursorControllerY * 30.0f;
	}
	else
	{
		s_vCursor.x = m_fAutosnapCursorRelativeX;
		s_vCursor.y = m_fAutosnapCursorRelativeY;
	}
	if(m_bOnCircle && s_vCursor.GetLength() < fRadius*0.5f)
	{
		m_fAutosnapCursorRelativeX = 0;
		m_fAutosnapCursorRelativeY = 0;
		m_bOnCircle = false;
	}
	if(s_vCursor.GetLength() > fRadius)
	{
		s_vCursor.NormalizeSafe();
		m_fAutosnapCursorRelativeX = s_vCursor.x*fRadius;
		m_fAutosnapCursorRelativeY = s_vCursor.y*fRadius;
		m_bOnCircle = true;
	}


	const char* autosnapItem = "Center";

	if(m_bOnCircle)
	{
		Vec2 vCursor = s_vCursor;
		vCursor.NormalizeSafe();

		float fAngle;
		if(vCursor.y < 0)
		{
			fAngle = RAD2DEG(acos_tpl(vCursor.x));
		}
		else
		{
			fAngle = RAD2DEG(gf_PI2-acos_tpl(vCursor.x));
		}

		char szAngle[32];
		sprintf(szAngle,"%f",-fAngle+90.0f);

/*
		ColorB col(255,255,255,255);
		int iW=m_pRenderer->GetWidth();
		int iH=m_pRenderer->GetHeight();
		m_pRenderer->Set2DMode(true,iW,iH);
		m_pRenderer->GetIRenderAuxGeom()->DrawLine(Vec3(iW/2,iH/2,0),col,Vec3(iW/2+vCursor.x*100,iH/2+vCursor.y*100,0),col,5);
		m_pRenderer->Set2DMode(false,0,0);
*/

		m_animQuickMenu.CheckedSetVariable("Root.QuickMenu.Circle.Indicator._rotation",szAngle);

		if(fAngle >= 342 || fAngle < 52)
		{
			autosnapItem = "Strength";
		}
		else if(fAngle >= 52 && fAngle < 128)
		{
			autosnapItem = "Speed";
		}
		else if(fAngle >= 128 && fAngle < 205)
		{
			autosnapItem = "Defense";
		}
		else if(fAngle >= 205 && fAngle < 260)
		{
			autosnapItem = "Weapon";
		}
		else if(fAngle >= 260 && fAngle < 342)
		{
			autosnapItem = "Cloak";
		}
	}

	m_animQuickMenu.CheckedInvoke("Root.QuickMenu.setAutosnapItem", autosnapItem);
}
Esempio n. 7
0
void CHUD::UpdateMissionObjectiveIcon(EntityId objective, int friendly, FlashOnScreenIcon iconType, bool forceNoOffset, Vec3 rotationTarget)
{
	IEntity *pObjectiveEntity = GetISystem()->GetIEntitySystem()->GetEntity(objective);
	if(!pObjectiveEntity) return;

	AABB box;
	pObjectiveEntity->GetWorldBounds(box);
	Vec3 vWorldPos = Vec3(0,0,0);

	SEntitySlotInfo info;
	int slotCount = pObjectiveEntity->GetSlotCount();
	for(int i=0; i<slotCount; ++i)
	{
		if (pObjectiveEntity->GetSlotInfo(i, info))
		{
			if (info.pCharacter)
			{
				int16 id = info.pCharacter->GetISkeletonPose()->GetJointIDByName("objectiveicon");
				if (id >= 0)
				{
					//vPos = pCharacter->GetISkeleton()->GetHelperPos(helper);
					vWorldPos = info.pCharacter->GetISkeletonPose()->GetAbsJointByID(id).t;
					if (!vWorldPos.IsZero())
					{
						vWorldPos = pObjectiveEntity->GetSlotWorldTM(i).TransformPoint(vWorldPos);
						break;
					}
				}
			}
		}
	}
	if(vWorldPos == Vec3(0,0,0))
		vWorldPos = pObjectiveEntity->GetWorldPos();

	if(!forceNoOffset)
		vWorldPos.z += 2.0f;

	Vec3 vEntityScreenSpace;
	m_pRenderer->ProjectToScreen(	vWorldPos.x, vWorldPos.y,	vWorldPos.z, &vEntityScreenSpace.x, &vEntityScreenSpace.y, &vEntityScreenSpace.z);
	Vec3 vEntityTargetSpace;
	bool useTarget = false;
	if(!rotationTarget.IsZero())
	{
		m_pRenderer->ProjectToScreen(	rotationTarget.x, rotationTarget.y,	rotationTarget.z, &vEntityTargetSpace.x, &vEntityTargetSpace.y, &vEntityTargetSpace.z);
		useTarget = true;
	}

	CActor *pActor = (CActor*)(gEnv->pGame->GetIGameFramework()->GetClientActor());
	bool bBack = false;
	if (IMovementController *pMV = pActor->GetMovementController())
	{
		SMovementState state;
		pMV->GetMovementState(state);
		Vec3 vLook = state.eyeDirection;
		Vec3 vDir = vWorldPos - pActor->GetEntity()->GetWorldPos();
		float fDot = vLook.Dot(vDir);
		if(fDot<0.0f)
			bBack = true;
	}

	bool bLeft(false), bRight(false), bTop(false), bBottom(false);

	if(vEntityScreenSpace.z > 1.0f && bBack)
	{
		Vec2 vCenter(50.0f, 50.0f);
		Vec2 vTarget(-vEntityScreenSpace.x, -vEntityScreenSpace.y);
		Vec2 vScreenDir = vTarget - vCenter;
		vScreenDir = vCenter + (100.0f * vScreenDir.NormalizeSafe());
		vEntityScreenSpace.y = vScreenDir.y;
		vEntityScreenSpace.x = vScreenDir.x;
		useTarget = false;
	}
	if(vEntityScreenSpace.x < 2.0f)
	{
		bLeft = true;
		vEntityScreenSpace.x = 2.0f;
		useTarget = false;
	}
	if(vEntityScreenSpace.x > 98.0f)
	{
		bRight = true;
		vEntityScreenSpace.x = 98.0f;
		useTarget = false;
	}
	if(vEntityScreenSpace.y < 2.01f)
	{
		bTop = true;
		vEntityScreenSpace.y = 2.0f;
		useTarget = false;
	}
	if(vEntityScreenSpace.y > 97.99f)
	{
		bBottom = true;
		vEntityScreenSpace.y = 98.0f;
		useTarget = false;
	}

	float fScaleX = 0.0f;
	float fScaleY = 0.0f;
	float fHalfUselessSize = 0.0f;
	GetProjectionScale(&m_animMissionObjective,&fScaleX,&fScaleY,&fHalfUselessSize);

	if(bLeft && bTop)
	{
		iconType = eOS_TopLeft;
	}
	else if(bLeft && bBottom)
	{
		iconType = eOS_BottomLeft;
	}
	else if(bRight && bTop)
	{
		iconType = eOS_TopRight;
	}
	else if(bRight && bBottom)
	{
		iconType = eOS_BottomRight;
	}
	else if(bLeft)
	{
		iconType = eOS_Left;
	}
	else if(bRight)
	{
		iconType = eOS_Right;
	}
	else if(bTop)
	{
		iconType = eOS_Top;
	}
	else if(bBottom)
	{
		iconType = eOS_Bottom;
	}

	float rotation = 0.0f;
	if(useTarget)
	{
		float diffX = (vEntityScreenSpace.x*fScaleX+fHalfUselessSize+16.0f) - (vEntityTargetSpace.x*fScaleX+fHalfUselessSize+16.0f);
		float diffY = (vEntityScreenSpace.y*fScaleY) - (vEntityTargetSpace.y*fScaleY);
		Vec2 dir(diffX, diffY);
		dir.NormalizeSafe();

		float fAngle;
		if(dir.y < 0)
		{
			fAngle = RAD2DEG(acos_tpl(dir.x));
		}
		else
		{
			fAngle = RAD2DEG(gf_PI2-acos_tpl(dir.x));
		}
		rotation = fAngle - 90.0f;
	}

	int		iMinDist = g_pGameCVars->hud_onScreenNearDistance;
	int		iMaxDist = g_pGameCVars->hud_onScreenFarDistance;
	float	fMinSize = g_pGameCVars->hud_onScreenNearSize;
	float	fMaxSize = g_pGameCVars->hud_onScreenFarSize;

	CActor *pPlayerActor = static_cast<CActor *>(gEnv->pGame->GetIGameFramework()->GetClientActor());

	float	fDist = (vWorldPos-pPlayerActor->GetEntity()->GetWorldPos()).len();
	float fSize = 1.0;
	if(fDist<=iMinDist)
	{
		fSize = fMinSize;
	}
	else if(fDist>=iMaxDist)
	{
		fSize = fMaxSize;
	}
	else if(iMaxDist>iMinDist)
	{
		float fA = ((float)iMaxDist - fDist);
		float fB = (float)(iMaxDist - iMinDist);
		float fC = (fMinSize - fMaxSize);
		fSize = ((fA / fB) * fC) + fMaxSize;
	}

	float centerX = 50.0;
	float centerY = 50.0;

	m_missionObjectiveNumEntries += FillUpMOArray(&m_missionObjectiveValues, objective, vEntityScreenSpace.x*fScaleX+fHalfUselessSize+16.0f, vEntityScreenSpace.y*fScaleY, iconType, friendly, (int)fDist, fSize*fSize, -rotation);
	bool nearCenter = (pow(centerX-vEntityScreenSpace.x+1.5f,2.0f)+pow(centerY-vEntityScreenSpace.y+2.5f,2.0f))<16.0f;
	if(nearCenter && (gEnv->bMultiplayer || m_pHUDScopes->IsBinocularsShown()))
	{
		m_objectiveNearCenter = objective;
	}
}
Esempio n. 8
0
//------------------------------------------------------------------
void CLam::UpdateTPLaser(float frameTime, CItem* parent)
{
    FUNCTION_PROFILER(GetISystem(), PROFILE_GAME);

    const int frameId = gEnv->pRenderer->GetFrameID();

    if (s_lastUpdateFrameId != frameId)
    {
        // Check how many LAMs to update this frame.
        float dt = frameTime; // + s_laserUpdateTimeError;

        const int n = s_lasers.size();

        int nActive = 0;
        for (int i = 0; i < n; ++i)
        {
            if (!s_lasers[i]->IsLaserActivated() && !s_lasers[i]->IsLightActivated())
                continue;
            nActive++;
        }

        float updatedPerSecond = (nActive / LASER_UPDATE_TIME) + s_laserUpdateTimeError;
        int updateCount = (int)floorf(updatedPerSecond * dt);
        if(dt==0.0f)
            s_laserUpdateTimeError = 0.0f;
        else
            s_laserUpdateTimeError = updatedPerSecond - updateCount/dt;

        s_curLaser %= n;
        for (int i = 0, j = 0; i < n && j < updateCount ; ++i)
        {
            s_curLaser = (s_curLaser + 1) % n;
            if (!s_lasers[s_curLaser]->IsLaserActivated() && !s_lasers[s_curLaser]->IsLightActivated())
                continue;
            s_lasers[s_curLaser]->SetAllowUpdate();
            ++j;
        }

        s_lastUpdateFrameId = frameId;
    }

    IEntity* pRootEnt = GetEntity();
    if (!pRootEnt)
        return;

    IEntity *pLaserEntity = m_pEntitySystem->GetEntity(m_pLaserEntityId);
//	if(!pLaserEntity)
//		return;

    const CCamera& camera = gEnv->pRenderer->GetCamera();

    Vec3   lamPos = pRootEnt->GetWorldPos(); //pLaserEntity->GetParent()->GetWorldPos();
    Vec3   dir = pRootEnt->GetWorldRotation().GetColumn1(); //pLaserEntity->GetParent()->GetWorldRotation().GetColumn1();

    bool charNotVisible = false;

    float  dsg1Scale = 1.0f;

    //If character not visible, laser is not correctly updated
    if(parent)
    {
        if(CActor* pOwner = parent->GetOwnerActor())
        {
            ICharacterInstance* pCharacter = pOwner->GetEntity()->GetCharacter(0);
            if(pCharacter && !pCharacter->IsCharacterVisible())
                charNotVisible = true;
        }
        if(parent->GetEntity()->GetClass()==CItem::sDSG1Class)
            dsg1Scale = 3.0f;
    }

//	if (!pLaserEntity->GetParent())
//		return;

    Vec3 hitPos(0,0,0);
    float laserLength = 0.0f;

    // HACK??: Use player movement controller locations, or else the laser
    // pops all over the place when character out of the screen.
    CActor *pActor = parent->GetOwnerActor();
    if (pActor && (!pActor->IsPlayer() || charNotVisible))
    {
        if (IMovementController* pMC = pActor->GetMovementController())
        {
            SMovementState state;
            pMC->GetMovementState(state);
            if(!charNotVisible)
                lamPos = state.weaponPosition;
            else
            {
                float oldZPos = lamPos.z;
                lamPos = state.weaponPosition;
                if(m_lastZPos>0.0f)
                    lamPos.z = m_lastZPos; //Stabilize somehow z position (even if not accurate)
                else
                    lamPos.z = oldZPos;
            }
            const float angleMin = DEG2RAD(3.0f);
            const float angleMax = DEG2RAD(7.0f);
            const float thr = cosf(angleMax);
            float dot = dir.Dot(state.aimDirection);
            if (dot > thr)
            {
                float a = acos_tpl(dot);
                float u = 1.0f - clamp((a - angleMin) / (angleMax - angleMin), 0.0f, 1.0f);
                dir = dir + u * (state.aimDirection - dir);
                dir.Normalize();
            }
        }
    }

    if(!charNotVisible)
        m_lastZPos = lamPos.z;

    lamPos += (dir*0.10f);

    if (m_allowUpdate)
    {
        m_allowUpdate = false;

        IPhysicalEntity* pSkipEntity = NULL;
        if(parent->GetOwner())
            pSkipEntity = parent->GetOwner()->GetPhysics();

        const float range = m_lamparams.laser_range[eIGS_ThirdPerson]*dsg1Scale;

        // Use the same flags as the AI system uses for visbility.
        const int objects = ent_terrain|ent_static|ent_rigid|ent_sleeping_rigid|ent_independent; //ent_living;
        const int flags = (geom_colltype_ray << rwi_colltype_bit) | rwi_colltype_any | (10 & rwi_pierceability_mask) | (geom_colltype14 << rwi_colltype_bit);

        ray_hit hit;
        if (gEnv->pPhysicalWorld->RayWorldIntersection(lamPos, dir*range, objects, flags,
                &hit, 1, &pSkipEntity, pSkipEntity ? 1 : 0))
        {
            laserLength = hit.dist;
            m_lastLaserHitPt = hit.pt;
            m_lastLaserHitSolid = true;
        }
        else
        {
            m_lastLaserHitSolid = false;
            m_lastLaserHitPt = lamPos + dir * range;
            laserLength = range + 0.1f;
        }

        // Hit near plane
        if (dir.Dot(camera.GetViewdir()) < 0.0f)
        {
            Plane nearPlane;
            nearPlane.SetPlane(camera.GetViewdir(), camera.GetPosition());
            nearPlane.d -= camera.GetNearPlane()+0.15f;
            Ray ray(lamPos, dir);
            Vec3 out;
            m_lastLaserHitViewPlane = false;
            if (Intersect::Ray_Plane(ray, nearPlane, out))
            {
                float dist = Distance::Point_Point(lamPos, out);
                if (dist < laserLength)
                {
                    laserLength = dist;
                    m_lastLaserHitPt = out;
                    m_lastLaserHitSolid = true;
                    m_lastLaserHitViewPlane = true;
                }
            }
        }

        hitPos = m_lastLaserHitPt;
    }
    else
    {
        laserLength = Distance::Point_Point(m_lastLaserHitPt, lamPos);
        hitPos = lamPos + dir * laserLength;
    }

    if (m_smoothLaserLength < 0.0f)
        m_smoothLaserLength = laserLength;
    else
    {
        if (laserLength < m_smoothLaserLength)
            m_smoothLaserLength = laserLength;
        else
            m_smoothLaserLength += (laserLength - m_smoothLaserLength) * min(1.0f, 10.0f * frameTime);
    }

    float laserAIRange = 0.0f;
    if (m_laserActivated && pLaserEntity)
    {
        // Orient the laser towards the point point.
        Matrix34 parentTMInv;
        parentTMInv = pRootEnt->GetWorldTM().GetInverted();

        Vec3 localDir = parentTMInv.TransformPoint(hitPos);
        float finalLaserLen = localDir.NormalizeSafe();
        Matrix33 rot;
        rot.SetIdentity();
        rot.SetRotationVDir(localDir);
        pLaserEntity->SetLocalTM(rot);

        laserAIRange = finalLaserLen;

        const float assetLength = 2.0f;
        finalLaserLen = CLAMP(finalLaserLen,0.01f,m_lamparams.laser_max_len*dsg1Scale);
        float scale = finalLaserLen / assetLength;

        // Scale the laser based on the distance.
        if (m_laserEffectSlot >= 0)
        {
            Matrix33 scl;
            scl.SetIdentity();
            scl.SetScale(Vec3(1,scale,1));
            pLaserEntity->SetSlotLocalTM(m_laserEffectSlot, scl);
        }

        if (m_dotEffectSlot >= 0)
        {
            if (m_lastLaserHitSolid)
            {
                Matrix34 mt = Matrix34::CreateTranslationMat(Vec3(0,finalLaserLen,0));
                if(m_lastLaserHitViewPlane)
                    mt.Scale(Vec3(0.2f,0.2f,0.2f));
                pLaserEntity->SetSlotLocalTM(m_dotEffectSlot, mt);
            }
            else
            {
                Matrix34 scaleMatrix;
                scaleMatrix.SetIdentity();
                scaleMatrix.SetScale(Vec3(0.001f,0.001f,0.001f));
                pLaserEntity->SetSlotLocalTM(m_dotEffectSlot, scaleMatrix);
            }
        }
    }

    float lightAIRange = 0.0f;
    if (m_lightActivated)
    {
        float range = clamp(m_smoothLaserLength, 0.5f, m_lamparams.light_range[eIGS_ThirdPerson]);
        lightAIRange = range * 1.5f;

        if (m_lightID[eIGS_ThirdPerson] && m_smoothLaserLength > 0.0f)
        {
            CItem* pLightEffect = this;
            if (IItem *pOwnerItem = m_pItemSystem->GetItem(GetParentId()))
                pLightEffect = (CItem *)pOwnerItem;
            pLightEffect->SetLightRadius(range, m_lightID[eIGS_ThirdPerson]);
        }
    }


    if (laserAIRange > 0.0001f || lightAIRange > 0.0001f)
        UpdateAILightAndLaser(lamPos, dir, lightAIRange, m_lamparams.light_fov[eIGS_ThirdPerson], laserAIRange);

}
void CMountedGunController::Update(EntityId mountedGunID, float frameTime)
{
	CRY_ASSERT_MESSAGE(m_pControlledPlayer, "Controlled player not initialized");

	CItem* pMountedGun = static_cast<CItem*>(gEnv->pGame->GetIGameFramework()->GetIItemSystem()->GetItem(mountedGunID));

	bool canUpdateMountedGun = (pMountedGun != NULL) && (pMountedGun->GetStats().mounted);

	if (canUpdateMountedGun)
	{
		IMovementController * pMovementController = m_pControlledPlayer->GetMovementController();
		assert(pMovementController);

		SMovementState info;
		pMovementController->GetMovementState(info);

		IEntity* pMountedGunEntity = pMountedGun->GetEntity();
		const Matrix34& lastMountedGunWorldTM = pMountedGunEntity->GetWorldTM();

		Vec3 desiredAimDirection = info.aimDirection.GetNormalized();

		// AI can switch directions too fast, prevent snapping
		if(!m_pControlledPlayer->IsPlayer())
		{
			const Vec3 currentDir = lastMountedGunWorldTM.GetColumn1();
			const float dot = clamp_tpl(currentDir.Dot(desiredAimDirection), -1.0f, 1.0f);
			const float reqAngle = acos_tpl(dot);
			const float maxRotSpeed = 2.0f;
			const float maxAngle = frameTime * maxRotSpeed;
			if(fabs(reqAngle) > maxAngle)
			{
				const Vec3 axis = currentDir.Cross(desiredAimDirection);
				if(axis.GetLengthSquared() > 0.001f) // current dir and new dir are enough different
				{
					desiredAimDirection = currentDir.GetRotated(axis.GetNormalized(),sgn(reqAngle)*maxAngle);
				}
			}
		}				
		
		bool isUserClient = m_pControlledPlayer->IsClient();
		
		IEntity* pMountedGunParentEntity = pMountedGunEntity->GetParent();
		IVehicle *pVehicle = NULL;
		if(pMountedGunParentEntity && m_pControlledPlayer)
			pVehicle = m_pControlledPlayer->GetLinkedVehicle();

		CRecordingSystem* pRecordingSystem = g_pGame->GetRecordingSystem();

		//For client update always, for others only when there is notable change
		if (!pVehicle && (isUserClient || (!desiredAimDirection.IsEquivalent(lastMountedGunWorldTM.GetColumn1(), 0.003f)))) 
		{
			Quat rotation = Quat::CreateRotationVDir(desiredAimDirection, 0.0f);
			pMountedGunEntity->SetRotation(rotation);

			if (isUserClient && pRecordingSystem)
			{
				// Only record the gun position if you're using the gun.
				pRecordingSystem->OnMountedGunRotate(pMountedGunEntity, rotation);
			}
		}

		const Vec3 vInitialAimDirection = GetMountDirection(pMountedGun, pMountedGunParentEntity);
		assert( vInitialAimDirection.IsUnit() );

		//Adjust gunner position and animations
		UpdateGunnerLocation(pMountedGun, pMountedGunParentEntity, vInitialAimDirection);

		const float aimrad = Ang3::CreateRadZ(Vec2(vInitialAimDirection),Vec2(-desiredAimDirection));
		const float pitchLimit = sin_tpl(DEG2RAD(30.0f));
		const float animHeight = fabs_tpl(clamp_tpl(desiredAimDirection.z * (float)fres(pitchLimit), -1.0f, 1.0f));

		const float aimUp = (float)fsel(-desiredAimDirection.z, 0.0f, animHeight); 
		const float aimDown = (float)fsel(desiredAimDirection.z, 0.0f, animHeight);

		if (pRecordingSystem)
		{
			pRecordingSystem->OnMountedGunUpdate(m_pControlledPlayer, aimrad, aimUp, aimDown);
		}

		if(!m_pControlledPlayer->IsThirdPerson())
		{
			UpdateFirstPersonAnimations(pMountedGun, desiredAimDirection);
		}

		if(m_pMovementAction)
		{
			const float aimUpParam = aimUp;
			const float aimDownParam = aimDown;
			const float aimMovementParam = CalculateAnimationTime(aimrad);

			m_pMovementAction->SetParam(MountedGunCRCs.aimUpParam, aimUpParam);
			m_pMovementAction->SetParam(MountedGunCRCs.aimDownParam, aimDownParam);
			m_pMovementAction->SetParam(MountedGunCRCs.aimMovementParam, aimMovementParam);
		}

		UpdateIKMounted(pMountedGun);
	}
}
Esempio n. 10
0
void CPlayerRotation::TargetAimAssistance(CWeapon* pWeapon, float& followH, float& followV, float& scale, float& _fZoomAmount, const Vec3 playerView[4])
{
	FUNCTION_PROFILER(GetISystem(), PROFILE_GAME);

	CRY_ASSERT(m_player.IsClient());

	followH = 0.0f;
	followV = 0.0f;
	scale = 1.0f;
	float bestScale = 1.0f;

	const Vec3 playerFwd = playerView[1];
	const Vec3 playerRgt = playerView[0];
	const Vec3 playerUp = playerView[2];
	const Vec3 playerPos = playerView[3];

	Vec3 follow_target_pos(ZERO);
	float follow_vote_leader = 0.0f;
	float snap_vote_leader = 0.0f;
	Vec3 follow_target_dir(ZERO);
	Vec3 snap_target_dir(ZERO);
	EntityId follow_target_id = 0;
	EntityId snap_target_id = 0;

	CGameRules * pGameRules = g_pGame->GetGameRules();
	float distance_follow_threshold_near	= max(0.0f, g_pGameCVars->aim_assistMinDistance);
	float distance_follow_threshold_far		= max(20.0f, g_pGameCVars->aim_assistMaxDistance);
	int playerTeam = pGameRules->GetTeam(m_player.GetEntity()->GetId());
	float cloakedPlayerMultiplier = g_pGameCVars->pl_aim_cloaked_multiplier;
	const bool multipleTeams = pGameRules->GetTeamCount() > 0;
	const float fFollowFalloffDist = g_pGameCVars->aim_assistFalloffDistance + FLT_EPSILON*g_pGameCVars->aim_assistFalloffDistance;
	const bool playerIsScoped = m_player.GetActorStats()->isScoped;

	float minTurnScale, fAimAssistStrength, fMaxDistMult;

	if(pWeapon)
	{
		const float fZoomAmount = pWeapon->GetZoomTransition();
		_fZoomAmount = fZoomAmount;
		
		const float fStrength						= g_pGameCVars->aim_assistStrength;
		const float fStrengthIronSight              = playerIsScoped ? g_pGameCVars->aim_assistStrength_SniperScope : g_pGameCVars->aim_assistStrength_IronSight;
		const float fDiff								= fStrengthIronSight - fStrength;
		fAimAssistStrength							= fStrength + (fZoomAmount * fDiff);
		
		const float fMinTurn						= g_pGameCVars->aim_assistMinTurnScale;
		const float fMinTurnIronSight               = playerIsScoped ? g_pGameCVars->aim_assistMinTurnScale_SniperScope : g_pGameCVars->aim_assistMinTurnScale_IronSight;
		const float fMinTurnDiff				= fMinTurnIronSight - fMinTurn;
		minTurnScale										= fMinTurn + (fZoomAmount * fMinTurnDiff);

		const float fMaxAssistDist			= g_pGameCVars->aim_assistMaxDistance;
		const float fMaxAssistDist_Iron             = playerIsScoped ? g_pGameCVars->aim_assistMaxDistance_SniperScope : g_pGameCVars->aim_assistMaxDistance_IronSight;
		const float fMaxAssistDistDiff	= (fMaxAssistDist_Iron - fMaxAssistDist) * fZoomAmount;
		fMaxDistMult                                = (fMaxAssistDist + fMaxAssistDistDiff) * __fres(fMaxAssistDist);
	}
	else
	{
		_fZoomAmount = 0.0f;
		fMaxDistMult = 1.0f;
		fAimAssistStrength = g_pGameCVars->aim_assistStrength;
		minTurnScale = g_pGameCVars->aim_assistMinTurnScale;
	}

	const float falloffStartDistance = g_pGameCVars->aim_assistSlowFalloffStartDistance;
	const float falloffPerMeter = 1.0f / (g_pGameCVars->aim_assistSlowDisableDistance - falloffStartDistance);

	const TAutoaimTargets& aaTargets = g_pGame->GetAutoAimManager().GetAutoAimTargets();
	const int targetCount = aaTargets.size();
	float fBestTargetDistance = FLT_MAX;

#if DBG_AUTO_AIM
	SAuxGeomRenderFlags oldFlags = gEnv->pRenderer->GetIRenderAuxGeom()->GetRenderFlags();
	SAuxGeomRenderFlags newFlags = e_Def3DPublicRenderflags;
	newFlags.SetAlphaBlendMode(e_AlphaBlended);
	newFlags.SetDepthTestFlag(e_DepthTestOff);
	newFlags.SetCullMode(e_CullModeNone); 
	gEnv->pRenderer->GetIRenderAuxGeom()->SetRenderFlags(newFlags);
#endif

	for (int i = 0; i < targetCount; ++i)
	{
		const SAutoaimTarget& target = aaTargets[i];

		CRY_ASSERT(target.entityId != m_player.GetEntityId());

		//Skip friendly ai
		if(gEnv->bMultiplayer)
		{
			if(multipleTeams &&  (pGameRules->GetTeam(target.entityId) == playerTeam))
			{
				continue;
			}

		}
		else 
		{		
			if (target.HasFlagSet(eAATF_AIHostile) == false)
				continue;

			distance_follow_threshold_far = fMaxDistMult * (target.HasFlagSet(eAATF_AIRadarTagged) ? g_pGameCVars->aim_assistMaxDistanceTagged : g_pGameCVars->aim_assistMaxDistance);
		}
		
		Vec3 targetPos = target.primaryAimPosition;
		Vec3 targetDistVec = (targetPos - playerPos);
		float distance = targetDistVec.GetLength();
		
		if (distance <= 0.1f)
			continue;

		Vec3 dirToTarget = targetDistVec / distance;

		// fast reject everything behind player, too far away or too near from line of view
		// sort rest by angle to crosshair and distance from player
		float alignment = playerFwd * dirToTarget;
		if (alignment <= 0.0f)
			continue;

		if ((distance < distance_follow_threshold_near) || (distance > distance_follow_threshold_far))
			continue;

		const int kAutoaimVisibilityLatency = 2;
		CPlayerVisTable::SVisibilityParams visParams(target.entityId);
		visParams.queryParams = eVQP_IgnoreGlass;
		if (!g_pGame->GetPlayerVisTable()->CanLocalPlayerSee(visParams, kAutoaimVisibilityLatency))
		{
			// Since both player and target entities are ignored, and the ray still intersected something, there's something in the way.
			// Need to profile this and see if it's faster to do the below checks before doing the linetest. It's fairly expensive but
			// linetests generally are as well... - Richard
			continue;
		}

#if DBG_AUTO_AIM
		const ColorB green(0,255,0,255);
		const ColorB darkgreen(0,155,0,225);
		gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine( playerPos, darkgreen, targetPos, green);
#endif

		const float angleDot = dirToTarget.dot(-playerRgt);
		const float angle = (RAD2DEG(acos_tpl(angleDot)) - 90.f);
		const float absAngle = fabsf(angle);

		const float angleDotV = playerUp.dot(dirToTarget);
		const float angleToTargetV = (RAD2DEG(acos_tpl(angleDotV)) - 90.f);
		const float absAngleV = fabsf(angleToTargetV);

		const float slowModifiedDistance = distance * g_pGameCVars->aim_assistSlowDistanceModifier;
		const float radius_slow_threshold_inner = 0.5f;
		const float radius_slow_threshold_outer = g_pGameCVars->aim_assistSlowThresholdOuter;
		const float angle_slow_threshold_inner = RAD2DEG(atan_tpl(radius_slow_threshold_inner / slowModifiedDistance));
		const float angle_slow_threshold_outer = RAD2DEG(atan_tpl(radius_slow_threshold_outer / slowModifiedDistance));
		float angle_slow_fractionH = clamp_tpl((absAngle - angle_slow_threshold_inner) / (angle_slow_threshold_outer - angle_slow_threshold_inner), 0.0f, 1.0f);
		float angle_slow_fractionV = clamp_tpl((absAngleV - angle_slow_threshold_inner) / (angle_slow_threshold_outer - angle_slow_threshold_inner), 0.0f, 1.0f);

		float angle_slow_fraction = max(angle_slow_fractionH, angle_slow_fractionV);

		const float distance_follow_fraction = clamp_tpl((distance - fFollowFalloffDist) / (distance_follow_threshold_far - fFollowFalloffDist), 0.0f, 1.0f);
		const float radius_follow_threshold_inner = target.innerRadius;
		const float radius_follow_threshold_outer = target.outerRadius;
		const float radius_snap = target.HasFlagSet(eAATF_AIRadarTagged) ?	target.snapRadiusTagged * g_pGameCVars->aim_assistSnapRadiusTaggedScale : 
																			target.snapRadius * g_pGameCVars->aim_assistSnapRadiusScale;
		const float angle_follow_threshold_inner = RAD2DEG(atan_tpl(radius_follow_threshold_inner / distance));
		const float angle_follow_threshold_outer = RAD2DEG(atan_tpl(radius_follow_threshold_outer / distance));
		const float angle_follow_fraction = clamp_tpl((absAngle - angle_follow_threshold_inner) / (angle_follow_threshold_outer - angle_follow_threshold_inner), 0.0f, 1.0f);
		const float angle_follow_fractionV = clamp_tpl((absAngleV - angle_follow_threshold_inner) / (angle_follow_threshold_outer - angle_follow_threshold_inner), 0.0f, 1.0f);
		const float worst_follow_fraction = (float)__fsel(angle_follow_fraction - angle_follow_fractionV, angle_follow_fraction, angle_follow_fractionV);
		float follow_fraction = ((1.0f - worst_follow_fraction) * (1.0f - distance_follow_fraction));
		float follow_vote = follow_fraction;

		//clamp the lower bound of the distance_slow_modifier so it can't be lower than the angle slow fraction
		//  which prevents close but off-centre targets slowing us too much
		const float distance_slow_modifier = clamp_tpl( 1.0f - ((distance - falloffStartDistance) * falloffPerMeter), angle_slow_fraction, 1.0f);


		const float fCombinedModifier = angle_slow_fraction * distance_slow_modifier;
		fBestTargetDistance = (float)__fsel(fCombinedModifier - bestScale, fBestTargetDistance, distance);
		bestScale = min(fCombinedModifier, bestScale);		

		if (follow_vote > follow_vote_leader)
		{
			follow_vote_leader = follow_vote;

			//m_follow_target_id only gets set after the loop -> this won't get hit when a target is selected
			// as a follow target for the first time. This doesn't need to be in the loop.
			if ( m_follow_target_id == target.entityId)
			{
				const Vec3 follow_target_dir_local = m_follow_target_dir;
				Vec3 target_rgt = playerRgt;
				Vec3 target_up = target_rgt.cross(follow_target_dir_local);
				target_rgt = follow_target_dir_local.cross(target_up);
				target_rgt.Normalize();
				target_up.Normalize();
				
				float alignH = dirToTarget * -target_rgt;
				float alignV = dirToTarget.z - follow_target_dir_local.z;
				float angleH = min(fabsf(alignH * fAimAssistStrength), fabsf(angleDot));
				float angleV = min(fabsf(alignV * fAimAssistStrength), fabsf(angleDotV));

				followH = follow_fraction * (float)__fsel(angleDot, angleH, -angleH);
				followV = follow_fraction * (float)__fsel(angleDotV, angleV, -angleV);	
								
				follow_vote_leader += 0.05f; // anti oscillation between different targets
				follow_target_pos = targetPos;
			}

			follow_target_id = target.entityId;
			snap_target_id = target.entityId;
			follow_target_dir = dirToTarget;
			snap_target_dir = PickBestSnapDirection(playerPos, playerFwd, target);

		}
		else if (!follow_target_id && (radius_snap > 0.0f))
		{
			Lineseg lineSegment;
			lineSegment.start = playerPos;
			lineSegment.end = playerPos + (playerFwd * (distance + radius_snap));
			Sphere sphere;
			sphere.center = targetPos;
			sphere.radius = radius_snap;
			Vec3 intersectionPoint;

			if (Intersect::Lineseg_SphereFirst(lineSegment, sphere, intersectionPoint))
			{
				float t = 0.0f;
				const float snap_fraction = 1.0f - (Distance::Point_Lineseg(targetPos, lineSegment, t) * (float)__fres(radius_snap));

				if (snap_fraction > snap_vote_leader)
				{
					snap_vote_leader = snap_fraction;
					snap_target_id = target.entityId;
					snap_target_dir = PickBestSnapDirection(playerPos, playerFwd, target);
				}
			}
		}
	}

#if DBG_AUTO_AIM
	if ((!follow_target_pos.IsZeroFast()) && (g_pGameCVars->pl_targeting_debug != 0))
	{
		float radius_inner = 0.30f;
		float radius_outer = 0.33f;
		ColorB colorInner(255,255,0,0x40);
		ColorB colorOuter(255,255,0,0x40);
		DrawDisc(follow_target_pos, follow_target_dir, radius_inner, radius_outer, colorInner, colorOuter);
	}

	gEnv->pRenderer->GetIRenderAuxGeom()->SetRenderFlags(oldFlags);
#endif

	m_follow_target_id  = follow_target_id;
	m_follow_target_dir = follow_target_dir;

	//IMPORTANT: Apply the minimum-distance scaling of the slowdown _after_ calculating the slowdown for the best target
	//						as we want to help the player aim at the nearest target, and modifying the slowdown multiplier prior to this
	//						could result in a different target being selected

	const float fSlowDownProximityFadeInBand = (g_pGameCVars->aim_assistSlowStopFadeinDistance - g_pGameCVars->aim_assistSlowStartFadeinDistance) + FLT_EPSILON;
	float fSlowDownProximityScale = (fBestTargetDistance - g_pGameCVars->aim_assistSlowStartFadeinDistance) / fSlowDownProximityFadeInBand; 
	Limit(fSlowDownProximityScale, 0.0f, 1.0f);
	float fInvBestScale = (1.0f - bestScale) * fSlowDownProximityScale;
	bestScale = 1.0f - fInvBestScale;

	scale = minTurnScale + ((1.0f - minTurnScale) * bestScale);

	UpdateCurrentSnapTarget(snap_target_id, snap_target_dir);
}
Esempio n. 11
0
static void GetTalosInput(CPlayerRotation * pPlayerRotation, const CPlayer& rPlayer, float& x, float& z, const Vec3 playerView[4], float fFrameTime)
{
	//Do I need to reproject the view to actually get the positioning correct? Shouldn't be.
	const Vec3 playerFwd = playerView[1];
	const Vec3 playerRgt = playerView[0];
	const Vec3 playerUp = playerView[2];
	const Vec3 playerViewPos = playerView[3];


	Vec3 playerPos = playerViewPos;

	IPhysicalEntity * pPhysicalEntity = rPlayer.GetEntity()->GetPhysics();
	if(pPhysicalEntity)
	{
		pe_status_dynamics dyn_status;
		pPhysicalEntity->GetStatus(&dyn_status);		
		playerPos = playerViewPos + (dyn_status.v * fFrameTime * 2.0f);
	}

	Vec3 follow_target_dir(ZERO);

	EntityId follow_target_id = 0;
	static EntityId s_follow_target_id = 0;

	CGameRules * pGameRules = g_pGame->GetGameRules();
	int playerTeam = pGameRules->GetTeam(rPlayer.GetEntity()->GetId());
	float cloakedPlayerMultiplier = g_pGameCVars->pl_aim_cloaked_multiplier;
	const bool multipleTeams = pGameRules->GetTeamCount() > 0;

	const TAutoaimTargets& aaTargets = g_pGame->GetAutoAimManager().GetAutoAimTargets();
	const int targetCount = aaTargets.size();
	float fBestTargetDistance = FLT_MAX;

	for (int i = 0; i < targetCount; ++i)
	{
		const SAutoaimTarget& target = aaTargets[i];

		if(multipleTeams &&  (pGameRules->GetTeam(target.entityId) == playerTeam))
		{
			continue;
		}

		Vec3 targetPos = target.secondaryAimPosition;
		
		IEntity * pEntity = gEnv->pEntitySystem->GetEntity(target.entityId);
		if(pEntity)
		{
			IPhysicalEntity * pPhysicalEntity2 = pEntity->GetPhysics();
			if(pPhysicalEntity2)
			{
				pe_status_dynamics dyn_status;
				pPhysicalEntity2->GetStatus(&dyn_status);		
				targetPos = targetPos + (dyn_status.v * fFrameTime);
			}
		}

		Vec3 targetDistVec = (targetPos - playerPos);
		float distance = targetDistVec.GetLength();

		if (distance <= 0.01f)
			continue;

		Vec3 dirToTarget = targetDistVec / distance;

		// fast reject everything behind player, too far away or too near from line of view
		// sort rest by angle to crosshair and distance from player

		const int kAutoaimVisibilityLatency = 1;
		if (!g_pGame->GetPlayerVisTable()->CanLocalPlayerSee(target.entityId, kAutoaimVisibilityLatency))
		{
			// Since both player and target entities are ignored, and the ray still intersected something, there's something in the way.
			// Need to profile this and see if it's faster to do the below checks before doing the linetest. It's fairly expensive but
			// linetests generally are as well... - Richard
			continue;
		}

		const float angleDot = dirToTarget.dot(-playerRgt);
		const float angle = (RAD2DEG(acos_tpl(angleDot)) - 90.f);
		const float absAngle = fabsf(angle);

		const float angleDotV = playerUp.dot(dirToTarget);
		const float angleToTargetV = (RAD2DEG(acos_tpl(angleDotV)) - 90.f);
		const float absAngleV = fabsf(angleToTargetV);

		if ( s_follow_target_id == target.entityId )
		{
			follow_target_id = target.entityId;
			follow_target_dir = dirToTarget;
			break;
		}
		else if(distance < fBestTargetDistance)
		{
			fBestTargetDistance = distance;
			follow_target_id = target.entityId;
			follow_target_dir = dirToTarget;
		}
	}

	if(follow_target_id != 0)
	{
		//Player up is the normal of the plane that we are rotating around - (Correct? Or do we want to project both the player direction and the target direction onto the X/Y plane?)
		Vec3 vProjectedTargetHorz = playerUp.cross(follow_target_dir.cross(playerUp));
		Vec3 vProjectedTargetVert = playerRgt.cross(follow_target_dir.cross(playerRgt));

		float horzDot = vProjectedTargetHorz.GetNormalized().dot(playerFwd);
		float vertDot = vProjectedTargetVert.GetNormalized().dot(playerFwd);

		const float directionDotHorz = follow_target_dir.dot(playerRgt);
		const float directionDotVert = follow_target_dir.dot(playerUp);
		
		const float angle						= acos_tpl(horzDot);
		const float angleToTargetV	= acos_tpl(vertDot);		

		const float fHorzFinalAngle = (float)__fsel(directionDotHorz, -angle, angle);
		const float fVertFinalAngle = (float)__fsel(directionDotVert, angleToTargetV, -angleToTargetV);

		//CryWatch("Angle to target: %.6f", RAD2DEG(angle));
		//CryWatch("Final Angle to target: %.6f", RAD2DEG(fHorzFinalAngle));

		x = x + fVertFinalAngle;
		z = z + fHorzFinalAngle;
	}

	s_follow_target_id  = follow_target_id;

	return;
}
//------------------------------------------------------------------------
void CScriptControlledPhysics::OnPostStep(EventPhysPostStep *pPostStep)
{
	pe_action_set_velocity av;

	const bool moving = m_moving;
	const bool rotating = m_rotating;

	const float deltaTime = pPostStep->dt;

	if (m_moving)
	{
		const Vec3 current = pPostStep->pos;
		const Vec3 target = m_moveTarget;
		const Vec3 delta = target - current;
		const float distanceSq = delta.len2();

		if (distanceSq <= sqr(0.025f) || (delta.dot(m_lastVelocity) < 0.0f))
		{
			m_speed = 0.0f;
			m_moving = false;
			m_lastVelocity.zero();

			pPostStep->pos = target;

			av.v = ZERO;
		}
		else
		{
			float velocity = m_speed;
			float acceleration = m_acceleration;
			Vec3 direction = delta;
			const float distanceToEnd = direction.NormalizeSafe();

			// Accelerate
			velocity = std::min(velocity + acceleration * deltaTime, m_maxSpeed);

			// Calculate acceleration and time needed to stop
			const float accelerationNeededToStop = (-(velocity*velocity) / distanceToEnd) / 2;
			if (fabsf(accelerationNeededToStop) > 0.0f)
			{
				const float timeNeededToStop = sqrtf((distanceToEnd / 0.5f) / fabsf(accelerationNeededToStop));

				if (timeNeededToStop < m_stopTime)
				{
					acceleration = accelerationNeededToStop;
				}
			}

			// Prevent overshooting
			if ((velocity * deltaTime) > distanceToEnd)
			{
				const float multiplier = distanceToEnd / fabsf(velocity * deltaTime);
				velocity *= multiplier;
				acceleration *= multiplier;
			}

			m_acceleration = acceleration;
			m_speed = velocity;

			m_lastVelocity = direction * velocity;
			av.v = direction * velocity;
		}
	}

	if (m_rotating)
	{
		Quat current=pPostStep->q;
		Quat target=m_rotationTarget;

		Quat rotation=target*!current;
		float angle=acos_tpl(CLAMP(rotation.w, -1.0f, 1.0f))*2.0f;
		float original=angle;
		if (angle>gf_PI)
			angle=angle-gf_PI2;
		else if (angle<-gf_PI)
			angle=angle+gf_PI2;

		if (fabs_tpl(angle)<0.01f)
		{
			m_rotationSpeed=0.0f;
			m_rotating=false;
			pPostStep->q=m_rotationTarget;
			av.w=ZERO;
		}
		else
		{
			float a=m_rotationSpeed/m_rotationStopTime;
			float d=m_rotationSpeed*m_stopTime-0.5f*a*m_rotationStopTime*m_rotationStopTime;

			if (fabs_tpl(angle)<d+0.001f)
				m_rotationAcceleration=(angle-m_rotationSpeed*m_rotationStopTime)/(m_rotationStopTime*m_rotationStopTime);

			m_rotationSpeed=m_rotationSpeed+sgn(angle)*m_rotationAcceleration*deltaTime;
			if (fabs_tpl(m_rotationSpeed*deltaTime)>fabs_tpl(angle))
				m_rotationSpeed=angle/deltaTime;
			else if (fabs_tpl(m_rotationSpeed)<0.001f)
				m_rotationSpeed=sgn(m_rotationSpeed)*0.001f;
			else if (fabs_tpl(m_rotationSpeed)>=m_rotationMaxSpeed)
			{
				m_rotationSpeed=sgn(m_rotationSpeed)*m_rotationMaxSpeed;
				m_rotationAcceleration=0.0f;
			}
		}

		if(fabs_tpl(angle)>=0.001f)
			av.w=(rotation.v/sin_tpl(original*0.5f)).normalized();
		av.w*=m_rotationSpeed;
	}

	if (moving || rotating)
	{
		if (IPhysicalEntity *pPE=GetEntity()->GetPhysics())
			pPE->Action(&av, 1);
	}
/*
	if ((moving && !m_moving) || (rotating && !m_rotating))
		GetEntity()->SetWorldTM(Matrix34::Create(GetEntity()->GetScale(), pPostStep->q, pPostStep->pos));
*/
}
Esempio n. 13
0
void CNetPlayerInput::UpdateMoveRequest()
{
	CMovementRequest moveRequest;
	SMovementState moveState;
	m_pPlayer->GetMovementController()->GetMovementState(moveState);
	Quat worldRot = m_pPlayer->GetBaseQuat(); // m_pPlayer->GetEntity()->GetWorldRotation();
	Vec3 deltaMovement = worldRot.GetInverted().GetNormalized() * m_curInput.deltaMovement;
	// absolutely ensure length is correct
	deltaMovement = deltaMovement.GetNormalizedSafe(ZERO) * m_curInput.deltaMovement.GetLength();
	moveRequest.AddDeltaMovement( deltaMovement );
	if( IsDemoPlayback() )
	{
		Vec3 localVDir(m_pPlayer->GetViewQuatFinal().GetInverted() * m_curInput.lookDirection);
		Ang3 deltaAngles(asinf(localVDir.z),0,atan2_tpl(-localVDir.x,localVDir.y));
		moveRequest.AddDeltaRotation(deltaAngles*gEnv->pTimer->GetFrameTime());
	}
	
	const float fNetAimLerpFactor = g_pGameCVars->pl_netAimLerpFactor;

	//Vector slerp produces artifacts here, using a per-component lerp instead
	Vec3 vCurrentRight			= m_lookDir.cross(Vec3Constants<float>::fVec3_OneZ);
	Vec3 vCurrentProjected = -(vCurrentRight.cross(Vec3Constants<float>::fVec3_OneZ));
	vCurrentRight.Normalize();
	vCurrentProjected.Normalize();

	Vec3 vNewRight					= m_curInput.lookDirection.cross(Vec3Constants<float>::fVec3_OneZ);
	Vec3 vNewProjected			= -(vNewRight.cross(Vec3Constants<float>::fVec3_OneZ));
	vNewProjected.Normalize();

	float fRotZDirDot	= vNewProjected.dot(vCurrentRight);
	float fRotZDot		= vNewProjected.dot(vCurrentProjected);
	float fRotZ				= acos_tpl(fRotZDot);

	fRotZ = AngleWrap_PI(fRotZ);

	float fRotZFinal	= -fsgnf(fRotZDirDot) * fRotZ * fNetAimLerpFactor;

	float fCurrentAngle = acos_tpl(Vec3Constants<float>::fVec3_OneZ.dot(m_lookDir));
	float fNewAngle			= acos_tpl(Vec3Constants<float>::fVec3_OneZ.dot(m_curInput.lookDirection));

	float fRotXFinal = (fNewAngle - fCurrentAngle) * -fNetAimLerpFactor;

	//Rotate around X first, as we have already generated the right vector
	Vec3 vNewLookDir = m_lookDir.GetRotated(vCurrentRight, fRotXFinal);

	m_lookDir = vNewLookDir.GetRotated(Vec3Constants<float>::fVec3_OneZ, fRotZFinal);

	Vec3 distantTarget = moveState.eyePosition + 1000.0f * m_lookDir;
	Vec3 lookTarget = distantTarget;

	if (m_curInput.usinglookik)
		moveRequest.SetLookTarget( lookTarget );
	else
		moveRequest.ClearLookTarget();

	if (m_curInput.aiming)
		moveRequest.SetAimTarget( lookTarget );
	else
		moveRequest.ClearAimTarget();

	if (m_curInput.deltaMovement.GetLengthSquared() > sqr(0.02f)) // 0.2f is almost stopped
		moveRequest.SetBodyTarget( distantTarget );
	else
		moveRequest.ClearBodyTarget();

	moveRequest.SetAllowStrafing(m_curInput.allowStrafing);

	moveRequest.SetPseudoSpeed(CalculatePseudoSpeed());

	moveRequest.SetStance( (EStance)m_curInput.stance );

	m_pPlayer->GetMovementController()->RequestMovement(moveRequest);

	if (m_curInput.sprint)
		m_pPlayer->m_actions |= ACTION_SPRINT;
	else
		m_pPlayer->m_actions &= ~ACTION_SPRINT;

#if 0
	if (m_pPlayer->m_netSetPosition)
	{
		SPredictedCharacterStates charStates;
		charStates.states[0].position		 = m_pPlayer->GetEntity()->GetPos();
		charStates.states[0].orientation = m_pPlayer->GetEntity()->GetRotation();
		charStates.states[0].deltatime	 = 0.0f;

		charStates.states[1].position		 = m_pPlayer->m_netCurrentLocation;
		charStates.states[1].orientation = m_pPlayer->GetEntity()->GetRotation();
		charStates.states[1].deltatime	 = gEnv->pTimer->GetFrameTime();

		charStates.states[2].position		 = m_pPlayer->m_netDesiredLocation;
		charStates.states[2].orientation = m_pPlayer->GetEntity()->GetRotation();
		charStates.states[2].deltatime	 = m_pPlayer->m_netLerpTime;
		charStates.nStates = 3;

		moveRequest.SetPrediction(charStates);
	}
#endif //0

#if !defined(_RELEASE)
	// debug..
	if (g_pGameCVars->g_debugNetPlayerInput & 2)
	{
		IPersistantDebug * pPD = gEnv->pGame->GetIGameFramework()->GetIPersistantDebug();
		pPD->Begin( string("update_player_input_") + m_pPlayer->GetEntity()->GetName(), true );
		Vec3 wp = m_pPlayer->GetEntity()->GetWorldPos();
		wp.z += 2.0f;
		pPD->AddSphere( moveRequest.GetLookTarget(), 0.5f, ColorF(1,0,1,0.3f), 1.0f );
		//		pPD->AddSphere( moveRequest.GetMoveTarget(), 0.5f, ColorF(1,1,0,0.3f), 1.0f );
		pPD->AddDirection( m_pPlayer->GetEntity()->GetWorldPos() + Vec3(0,0,2), 1, m_curInput.deltaMovement, ColorF(1,0,0,0.3f), 1.0f );
	}
#endif

	//m_curInput.deltaMovement.zero();
} 
//////////////////////////////////////////////////////////////////////////
// NOTE: This function must be thread-safe. Before adding stuff contact MarcoC.
void CVehicleMovementStdBoat::ProcessAI(const float deltaTime)
{
	FUNCTION_PROFILER( GetISystem(), PROFILE_GAME );

	float dt = max( deltaTime, 0.005f);
	SVehiclePhysicsStatus* physStatus = &m_physStatus[k_physicsThread];

	// It is copyed from CVehicleMoventTank::ProcessAI
	m_movementAction.brake = false;
	m_movementAction.rotateYaw = 0.0f;
	m_movementAction.power = 0.0f;

	float inputSpeed = 0.0f;
	{
		if (m_aiRequest.HasDesiredSpeed())
			inputSpeed = m_aiRequest.GetDesiredSpeed();
		Limit(inputSpeed, -(m_maxSpeed*m_factorMaxSpeed), m_maxSpeed*m_factorMaxSpeed);
	}

	Vec3 vMove(ZERO);
	{
		if (m_aiRequest.HasMoveTarget())
			vMove = ( m_aiRequest.GetMoveTarget() - m_pEntity->GetWorldPos() ).GetNormalizedSafe();
	}

	//start calculation
	if ( fabsf( inputSpeed ) < 0.0001f )
	{
		m_movementAction.brake = true;
		if ( physStatus->v.GetLength() > 1.0f )
		{
			m_movementAction.power =-1.0f;
		}

	}
	else
	{
		Matrix33 entRotMatInvert( physStatus->q );
		entRotMatInvert.Invert();
		float currentAngleSpeed = RAD2DEG(-physStatus->w.z);

		const static float maxSteer = RAD2DEG(gf_PI/4.f); // fix maxsteer, shouldn't change  
		Vec3 vVel = physStatus->v;
		Vec3 vVelR = entRotMatInvert * vVel;
		float currentSpeed =vVel.GetLength();
		vVelR.NormalizeSafe();
		if ( vVelR.Dot( FORWARD_DIRECTION ) < 0 )
			currentSpeed *= -1.0f;

		// calculate pedal
		static float accScale = 0.5f;
		m_movementAction.power = (inputSpeed - currentSpeed) * accScale;
		Limit( m_movementAction.power, -1.0f, 1.0f);

		// calculate angles
		Vec3 vMoveR = entRotMatInvert * vMove;
		Vec3 vFwd	= FORWARD_DIRECTION;

		vMoveR.z =0.0f;
		vMoveR.NormalizeSafe();

		if ( inputSpeed < 0.0f )	// when going back
		{
			vFwd *= -1.0f;
			vMoveR *= -1.0f;
			currentAngleSpeed *=-1.0f;
		}

		float cosAngle = vFwd.Dot(vMoveR);
		float angle = RAD2DEG(acos_tpl(cosAngle));
		if ( vMoveR.Dot( Vec3( 1.0f,0.0f,0.0f ) )< 0 )
			 angle = -angle;

		//int step =0;
		m_movementAction.rotateYaw = angle * 1.75f/ maxSteer; 

		// implementation 1. if there is enough angle speed, we don't need to steer more
		if ( fabsf(currentAngleSpeed) > fabsf(angle) && angle*currentAngleSpeed > 0.0f )
		{
			m_movementAction.rotateYaw = m_movementAction.rotateYaw*0.995f; //step =1;
		}

		// implementation 2. if we can guess we reach the distination angle soon, start counter steer.
		float predictDelta = inputSpeed < 0.0f ? 0.1f : 0.1f;
		float dict = angle + predictDelta * ( angle - m_prevAngle) / dt ;
		if ( dict*currentAngleSpeed<0.0f )
		{
			if ( fabsf( angle ) < 2.0f )
			{
				m_movementAction.rotateYaw = angle* 1.75f/ maxSteer;// ; step =3;
			}
			else
			{
				m_movementAction.rotateYaw = currentAngleSpeed < 0.0f ? 1.0f : -1.0f;// step =2;
			}
		}

		if ( fabsf( angle ) > 20.0f && currentSpeed > 3.0f ) 
		{
			m_movementAction.power = 0.1f ;
			//step =4;
		}

		m_prevAngle =  angle;
		//CryLog("steering	%4.2f	%4.2f %4.2f	%4.2f	%4.2f	%4.2f	%d", deltaTime,inputSpeed - currentSpeed,angle,currentAngleSpeed, m_movementAction.rotateYaw,currentAngleSpeed-m_prevAngle,step);

	}

}
Esempio n. 15
0
//----------------------------------------------------------------------------
void CHomingMissile::UpdateCruiseMissile(float frameTime)
{

	IRenderer* pRenderer = gEnv->pRenderer;
	IRenderAuxGeom* pGeom = pRenderer->GetIRenderAuxGeom();
	float color[4] = {1,1,1,1};
	const static float step = 15.f;  
	float y = 20.f;    

	bool bDebug = g_pGameCVars->i_debug_projectiles > 0;

	if (m_targetId)
	{
		IEntity* pTarget = gEnv->pEntitySystem->GetEntity(m_targetId);
		if (pTarget)
		{
			AABB box;
			pTarget->GetWorldBounds(box);
			SetDestination( box.GetCenter() );

			//if (bDebug)
				//pRenderer->Draw2dLabel(5.0f, y+=step, 1.5f, color, false, "Target Entity: %s", pTarget->GetName());
		}    
	}
	else 
	{
		// update destination pos from weapon
		static IItemSystem* pItemSystem = g_pGame->GetIGameFramework()->GetIItemSystem();
		IItem* pItem = pItemSystem->GetItem(m_weaponId);
		if (pItem && pItem->GetIWeapon())
		{
			const Vec3& dest = pItem->GetIWeapon()->GetDestination();
			SetDestination( dest );

			//if (bDebug)
				//pRenderer->Draw2dLabel(5.0f, y+=step, 1.5f, color, false, "Weapon Destination: (%.1f %.1f %.1f)", dest.x, dest.y, dest.z);
		}
	}

	pe_status_dynamics status;
	if (!GetEntity()->GetPhysics()->GetStatus(&status))
		return;

	float currentSpeed = status.v.len();
	Vec3 currentPos = GetEntity()->GetWorldPos();
	Vec3 goalDir(ZERO);

	if (!m_destination.IsZero())
	{

		if((currentPos-m_destination).len2()<(m_detonationRadius*m_detonationRadius))
		{
			Explode(true, true, m_destination, -status.v.normalized(), status.v, m_targetId);
			return;
		}

		if (bDebug)
			pGeom->DrawCone(m_destination, Vec3(0,0,-1), 2.5f, 7.f, ColorB(255,0,0,255));

		float heightDiff = (m_cruiseAltitude-m_alignAltitude) - currentPos.z;

		if (!m_isCruising && heightDiff * sgn(status.v.z) > 0.f)
		{
			// if heading towards align altitude (but not yet reached) accelerate to max speed    
			if (bDebug)
				pRenderer->Draw2dLabel(5.0f,  y+=step,   1.5f, color, false, "[HomingMissile] accelerating (%.1f / %.1f)", currentSpeed, m_maxSpeed);    
		}
		else if (!m_isCruising && heightDiff * sgnnz(status.v.z) < 0.f && (status.v.z<0 || status.v.z>0.25f))
		{
			// align to cruise
			if (currentSpeed != 0)
			{
				goalDir = status.v;
				goalDir.z = 0;
				goalDir.normalize();
			}    

			if (bDebug)
				pRenderer->Draw2dLabel(5.0f,  y+=step, 1.5f, color, false, "[HomingMissile] aligning"); 
		}
		else
		{
			if (bDebug)
				pRenderer->Draw2dLabel(5.0f,  y+=step, 1.5f, color, false, "[HomingMissile] cruising..."); 

			// cruise
			m_isCruising = true;

			if (!m_destination.IsZero())
			{
				float groundDistSq = m_destination.GetSquaredDistance2D(currentPos);
				float distSq = m_destination.GetSquaredDistance(currentPos);
				float descendDistSq = sqr(m_descendDistance);

				if (m_isDescending || groundDistSq <= descendDistSq)
				{
					if (bDebug)
						pRenderer->Draw2dLabel(5.0f,  y+=step, 1.5f, color, false, "[HomingMissile] descending!"); 

					if (distSq != 0)
						goalDir = (m_destination - currentPos).normalized();
					else 
						goalDir.zero();

					m_isDescending = true;
				}              
				else
				{
					Vec3 airPos = m_destination;
					airPos.z = currentPos.z;          
					goalDir = airPos - currentPos;
					if (goalDir.len2() != 0)
						goalDir.Normalize();
				}    
			}
		}
	}  

	float desiredSpeed = currentSpeed;
	if (currentSpeed < m_maxSpeed-0.1f)
	{
		desiredSpeed = min(m_maxSpeed, desiredSpeed + m_accel*frameTime);
	}

	Vec3 currentDir = status.v.GetNormalizedSafe(FORWARD_DIRECTION);
	Vec3 dir = currentDir;

	if (!goalDir.IsZero())
	{ 
		float cosine = max(min(currentDir.Dot(goalDir), 0.999f), -0.999f);
		float goalAngle = RAD2DEG(acos_tpl(cosine));
		float maxAngle = m_turnSpeed * frameTime;

		if (bDebug)
		{ 
			pGeom->DrawCone( currentPos, goalDir, 0.4f, 12.f, ColorB(255,0,0,255) );
			pRenderer->Draw2dLabel(5.0f,  y+=step, 1.5f, color, false, "[HomingMissile] goalAngle: %.2f", goalAngle); 

		}

		if (goalAngle > maxAngle+0.05f)    
			dir = (Vec3::CreateSlerp(currentDir, goalDir, maxAngle/goalAngle)).normalize();
		else //if (goalAngle < 0.005f)
			dir = goalDir;
	}

	pe_action_set_velocity action;
	action.v = dir * desiredSpeed;
	GetEntity()->GetPhysics()->Action(&action);

	if (bDebug)
	{
		pGeom->DrawCone( currentPos, dir, 0.4f, 12.f, ColorB(128,128,0,255) );  
		pRenderer->Draw2dLabel(5.0f,  y+=step, 1.5f, color, false, "[HomingMissile] currentSpeed: %.1f (max: %.1f)", currentSpeed, m_maxSpeed); 
	}
}
//////////////////////////////////////////////////////////////////////////
// NOTE: This function must be thread-safe. Before adding stuff contact MarcoC.
void CVehicleMovementTank::ProcessAI(const float deltaTime)
{
	FUNCTION_PROFILER( GetISystem(), PROFILE_GAME );

	float dt = max( deltaTime, 0.005f);

	m_movementAction.brake = false;
	m_movementAction.rotateYaw = 0.0f;
	m_movementAction.power = 0.0f;

	float inputSpeed = 0.0f;
	{
		if (m_aiRequest.HasDesiredSpeed())
			inputSpeed = m_aiRequest.GetDesiredSpeed();
		Limit(inputSpeed, -m_maxSpeed, m_maxSpeed);
	}

	Vec3 vMove(ZERO);
	{
		if (m_aiRequest.HasMoveTarget())
			vMove = ( m_aiRequest.GetMoveTarget() - m_PhysPos.pos ).GetNormalizedSafe();
	}

	//start calculation
	if ( fabsf( inputSpeed ) < 0.0001f || m_tireBlownTimer > 1.5f )
	{
		// only the case to use a hand break
		m_movementAction.brake = true;
	}
	else
	{

		Matrix33 entRotMatInvert( m_PhysPos.q );
		entRotMatInvert.Invert();
		float currentAngleSpeed = RAD2DEG(-m_PhysDyn.w.z);

		const static float maxSteer = RAD2DEG(gf_PI/4.f); // fix maxsteer, shouldn't change  
		Vec3 vVel = m_PhysDyn.v;
		Vec3 vVelR = entRotMatInvert * vVel;
		float currentSpeed =vVel.GetLength();
		vVelR.NormalizeSafe();
		if ( vVelR.Dot( FORWARD_DIRECTION ) < 0 )
			currentSpeed *= -1.0f;

		// calculate pedal
		static float accScale = 0.5f;
		m_movementAction.power = (inputSpeed - currentSpeed) * accScale;
		Limit( m_movementAction.power, -1.0f, 1.0f);

		// calculate angles
		Vec3 vMoveR = entRotMatInvert * vMove;
		Vec3 vFwd	= FORWARD_DIRECTION;

		vMoveR.z =0.0f;
		vMoveR.NormalizeSafe();

		if ( inputSpeed < 0.0 )	// when going back
		{
			vFwd *= -1.0f;
			vMoveR *= -1.0f;
			currentAngleSpeed *=-1.0f;
		}

		float cosAngle = vFwd.Dot(vMoveR);
		float angle = RAD2DEG( acos_tpl(cosAngle));
		if ( vMoveR.Dot( Vec3( 1.0f,0.0f,0.0f ) )< 0 )
			angle = -angle;

		//		int step =0;
		m_movementAction.rotateYaw = angle * 1.75f/ maxSteer; 

		// implementation 1. if there is enough angle speed, we don't need to steer more
		if ( fabsf(currentAngleSpeed) > fabsf(angle) && angle*currentAngleSpeed > 0.0f )
		{
			m_movementAction.rotateYaw = m_currSteer*0.995f; 
			//			step =1;
		}

		// implementation 2. if we can guess we reach the distination angle soon, start counter steer.
		float predictDelta = inputSpeed < 0.0f ? 0.1f : 0.07f;
		float dict = angle + predictDelta * ( angle - m_prevAngle) / dt ;
		if ( dict*currentAngleSpeed<0.0f )
		{
			if ( fabsf( angle ) < 2.0f )
			{
				m_movementAction.rotateYaw = angle* 1.75f/ maxSteer; 
				//				step =3;
			}
			else
			{
				m_movementAction.rotateYaw = currentAngleSpeed < 0.0f ? 1.0f : -1.0f; 
				//				step =2;
			}
		}

		// implementation 3. tank can rotate at a point
		if ( fabs( angle )> 20.0f ) 
		{
			m_movementAction.power *=0.1f;
			//			step =4;
		}

		//		char buf[1024];
		//		sprintf(buf, "steering	%4.2f	%4.2f	%4.2f	%d\n", deltaTime,currentAngleSpeed, angle - m_prevAngle, step);
		//		OutputDebugString( buf );
		m_prevAngle =  angle;

	}

}
Esempio n. 17
0
void CPlayerRotation::GetStanceAngleLimits(float &minAngle,float &maxAngle)
{
	EStance stance = m_player.GetStance();

	switch(stance)
	{
	default:
	case STANCE_CROUCH:
	case STANCE_STAND:
		minAngle = -80.0f;
		maxAngle = 80.0f;
		break;

	case STANCE_PRONE:
		minAngle = -35.0f;
		maxAngle = 45.0f;
		break;
	}

	//Limit camera rotation on ladders(to prevent clipping)
	if(m_player.m_stats.isOnLadder)
	{
		minAngle = -40.0f;
		maxAngle = 80.0f;
	}

	if(m_stats.grabbedHeavyEntity!=0)
	{
		minAngle = -35.0f;  //Limit angle to prevent clipping, throw objects at feet, etc...
	}

	// SNH: additional restriction based on weapon type if prone.
	if(m_player.GetStance() == STANCE_PRONE && g_pGameCVars->g_proneAimAngleRestrict_Enable != 0)
	{
		float dist = 0.0f;
		CItem *pItem = (CItem *)(m_player.GetCurrentItem());

		if(pItem)
			dist = pItem->GetParams().raise_distance;

		SMovementState movestate;
		m_player.m_pMovementController->GetMovementState(movestate);

		// try a cylinder intersection test
		IPhysicalEntity *pIgnore[2];
		pIgnore[0] = m_player.GetEntity()->GetPhysics();
		pIgnore[1] = pItem ? pItem->GetEntity()->GetPhysics() : NULL;

		primitives::cylinder cyl;
		cyl.r = 0.05f;
		cyl.axis = movestate.aimDirection;
		cyl.hh = dist;
		cyl.center = movestate.weaponPosition + movestate.aimDirection*cyl.hh;

		//gEnv->pRenderer->GetIRenderAuxGeom()->DrawCylinder(cyl.center, cyl.axis, cyl.r, cyl.hh, ColorF(0.4f,1.0f,0.6f, 0.2f));

		float n = 0.0f;
		geom_contact *contacts;
		intersection_params params;
		WriteLockCond lockContacts;
		params.bStopAtFirstTri = false;
		params.bSweepTest = false;
		params.bNoBorder = true;
		params.bNoAreaContacts = true;
		n = gEnv->pPhysicalWorld->PrimitiveWorldIntersection(primitives::cylinder::type, &cyl, Vec3(0,0,2),
				ent_static|ent_terrain, &contacts, 0,
				geom_colltype_player, &params, 0, 0, pIgnore, pIgnore[1]?2:1), lockContacts;
		int ret = (int)n;

		geom_contact *currentc = contacts;

		for(int i=0; i<ret; i++)
		{
			geom_contact *contact = currentc;

			if(contact && (fabs_tpl(contact->n.z)>0.2f))
			{
				Vec3 dir = contact->pt - movestate.weaponPosition;
				dir.NormalizeSafe();
				Vec3 horiz = dir;
				horiz.z = 0.0f;
				horiz.NormalizeSafe();
				float cosangle = dir.Dot(horiz);
				Limit(cosangle, -1.0f, 1.0f);
				float newMin = acos_tpl(cosangle);
				newMin = -newMin * 180.0f / gf_PI;
				//float col[] = {1,1,1,1};
				//gEnv->pRenderer->Draw2dLabel(100,100, 1.0f, col, false, "minangle: %.2f", newMin);
				//gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere(contact->pt, 0.03f, ColorF(1,0,0,1));
				minAngle = MAX(newMin, minAngle);
			}

			++currentc;
		}
	}

	minAngle *= gf_PI/180.0f;
	maxAngle *= gf_PI/180.0f;
}
Esempio n. 18
0
bool CDialogActorContext::DoLocalPlayerChecks(const float dt)
{
	// don't check this every frame, but only every .2 secs
	m_checkPlayerTimeOut-=dt;
	if (m_checkPlayerTimeOut <= 0.0f)
	{
		do // a dummy loop to use break
		{
			float awareDistance;
			float awareDistanceSq;
			float awareAngle;
			m_pSession->GetPlayerAwarenessValues(awareDistance, awareAngle);
			awareDistanceSq=awareDistance*awareDistance;

			m_checkPlayerTimeOut = PLAYER_CHECKTIME;
			const float spotAngleCos = cos_tpl(DEG2RAD(awareAngle));
	
			const CDialogSession::TActorContextMap& contextMap = m_pSession->GetAllContexts();
			if (contextMap.size() == 1 && contextMap.begin()->first == m_actorID)
			{
				m_bIsAware = true;
				break;
			}
	
			// early out, when we don't have to do any checks
			if (awareDistance <= 0.0f && awareAngle <= 0.0f)
			{
				m_bIsAware = true;
				break;
			}

			IEntity* pThisEntity = m_pSession->GetActorEntity(m_actorID);
			if (!pThisEntity)
			{
				assert (false);
				m_bIsAware = true;
				break;
			}
			IMovementController* pMC = (m_pIActor != NULL) ? m_pIActor->GetMovementController() : NULL;
			if (!pMC)
			{
				assert (false);
				m_bIsAware = true;
				break;
			}
			SMovementState moveState;
			pMC->GetMovementState(moveState);
			Vec3 viewPos = moveState.eyePosition;
			Vec3 viewDir = moveState.eyeDirection;
			viewDir.z = 0.0f;
			viewDir.NormalizeSafe();
	
			// check the player's position
			// check the player's view direction
			AABB groupBounds;
			groupBounds.Reset();

			CDialogSession::TActorContextMap::const_iterator iter = contextMap.begin();
			CDialogScript::SActorSet lookingAt = 0;
			while (iter != contextMap.end())
			{
				if (iter->first != m_actorID)
				{
					IEntity* pActorEntity = m_pSession->GetActorEntity(iter->first);
					if (pActorEntity)
					{
						Vec3 vEntityPos = pActorEntity->GetWorldPos();
						AABB worldBounds;
						pActorEntity->GetWorldBounds(worldBounds);
						groupBounds.Add(worldBounds);
						// calc if we look at it somehow
						Vec3 vEntityDir = vEntityPos - viewPos;
						vEntityDir.z = 0.0f;
						vEntityDir.NormalizeSafe();
						if (viewDir.IsUnit() && vEntityDir.IsUnit())
						{
							const float dot = clamp_tpl(viewDir.Dot(vEntityDir),-1.0f,+1.0f); // clamping should not be needed
							if (spotAngleCos <= dot)
								lookingAt.SetActor(iter->first);
							DiaLOG::Log(DiaLOG::eDebugC, "Angle to actor %d is %f deg", iter->first, RAD2DEG(acos_tpl(dot)));
						}
					}
				}
				++iter;
			}

			const float distanceSq = pThisEntity->GetWorldPos().GetSquaredDistance(groupBounds.GetCenter());
			CCamera& camera=gEnv->pSystem->GetViewCamera();
			const bool bIsInAABB  = camera.IsAABBVisible_F(groupBounds);
			const bool bIsInRange = distanceSq <= awareDistanceSq;
			const bool bIsLooking = contextMap.empty() || lookingAt.NumActors() > 0;
			m_bIsAwareLooking = awareAngle <= 0.0f || (bIsInAABB || bIsLooking);
			m_bIsAwareInRange = awareDistance <= 0.0f || bIsInRange;
			m_bIsAware = m_bIsAwareLooking && m_bIsAwareInRange;

			DiaLOG::Log(DiaLOG::eDebugB, "[DIALOG] LPC: %s awDist=%f awAng=%f AABBVis=%d IsLooking=%d InRange=%d [Distance=%f LookingActors=%d] Final=%saware", 
				m_pSession->GetDebugName(), awareDistance, awareAngle, bIsInAABB, bIsLooking, bIsInRange, sqrt_tpl(distanceSq), lookingAt.NumActors(), m_bIsAware ? "" : "not ");
		
		} while (false);
	}

	if (m_bIsAware)
	{
		m_playerAwareTimeOut = m_pSession->GetPlayerAwarenessGraceTime();
	}
	else
	{
		m_playerAwareTimeOut-= dt;
		if (m_playerAwareTimeOut <= 0)
		{
			return false;
		}
	}

	return true;
}