void OnUpdate( SActivationInfo* pActInfo )
	{
		const Vec3 positionOffsetLocal = GetPortVec3( pActInfo, PORT_IN_POSITION_OFFSET_LOCAL );
		const float maxDistance = max( 0.f, GetPortFloat( pActInfo, PORT_IN_MAX_LENGTH ) );

		const CCamera& camera = GetISystem()->GetViewCamera();
		
		const Vec3 cameraDirection = camera.GetViewdir();
		const Vec3 cameraPositionWorld = camera.GetPosition();
		const Matrix33 cameraOrientation = Matrix33::CreateRotationVDir( cameraDirection );
		const Vec3 positionOffsetWorld = cameraOrientation * positionOffsetLocal;

		const Vec3 rayOriginWorld = cameraPositionWorld + positionOffsetWorld;
		const Vec3 raySegment = cameraDirection * maxDistance;


		IPhysicalWorld* pWorld = gEnv->pPhysicalWorld;

		const int objectTypes = ent_all;
		const unsigned int raycastFlags = rwi_stop_at_pierceable | rwi_colltype_any;

		ray_hit hit;
		const int hitCount = pWorld->RayWorldIntersection( rayOriginWorld, raySegment, objectTypes, raycastFlags, &hit, 1 );
		
		float hitDistance = maxDistance;
		if ( 0 < hitCount )
		{
			hitDistance = hit.dist;
		}

		const float timeDelta = 0.1f;
		const float smoothTime = max( 0.f, GetPortFloat( pActInfo, PORT_IN_SMOOTH_TIME ) );
		SmoothCD( m_smoothedHitDistance, m_hitDistanceChangeRate, timeDelta, hitDistance, smoothTime );
		
		ActivateOutput( pActInfo, PORT_OUT_FOCUS_DISTANCE, m_smoothedHitDistance );

		const float focusRangeFactor = max( 0.f, GetPortFloat( pActInfo, PORT_IN_FOCUS_RANGE_FACTOR ) );
		const float focusRange = focusRangeFactor * m_smoothedHitDistance;

		ActivateOutput( pActInfo, PORT_OUT_FOCUS_RANGE, focusRange );


		const bool drawDebugInfo = GetPortBool( pActInfo, PORT_IN_DEBUG_ENABLED );
		if ( ! drawDebugInfo )
		{
			return;
		}

		IRenderer* pRenderer = gEnv->pRenderer;
		IRenderAuxGeom* pRenderAuxGeom = pRenderer->GetIRenderAuxGeom();

		ColorB rayColor = ( 0 < hitCount ) ? ColorB( 255, 255, 0 ) : ColorB( 255, 0, 0 );
		pRenderAuxGeom->DrawSphere( hit.pt, 0.1f, rayColor );
		pRenderAuxGeom->DrawLine( rayOriginWorld, rayColor, hit.pt, rayColor );

	}
示例#2
0
void CLookAim_Helper::UpdateLook(CPlayer* pPlayer, ICharacterInstance* pCharacter, bool bEnabled, f32 FOV, const Vec3& targetGlobal,const f32 *customBlends /*= NULL*/)
{
		if (!m_initialized)
		{
				Init(pPlayer, pCharacter);
		}

		bool useLookAtComplex;
		bool useLookAtSimple;

		if (m_canUseLookAtComplex)
		{
				// for now just use the old 'complex' look at method until we sort out how to properly blend old and new look at
				useLookAtComplex = true;
				useLookAtSimple = false;
		}
		else
		{
				useLookAtComplex = true; // for backwards compatibility reasons we still update the old look-at even when m_canUseLookAtComplex is false
				useLookAtSimple = m_canUseLookAtSimple;
		}

		// ---------------------------
		// Complex (old style) Look-At
		// ---------------------------

		ISkeletonPose * pSkeletonPose = pCharacter->GetISkeletonPose();
		pSkeletonPose->SetLookIK(useLookAtComplex && bEnabled, FOV, targetGlobal, customBlends);

		// ---------------------------
		// Simple Head-Only Look-At
		// ---------------------------

		if (m_canUseLookAtSimple)
		{
				float frameTime = gEnv->pTimer->GetFrameTime();

				// Fade In/Out the Weight
				m_lookAtWeight = bEnabled ? CLAMP(m_lookAtWeight + (frameTime * m_lookAtFadeInSpeed), 0.0f, 1.0f) : CLAMP(m_lookAtWeight - (frameTime * m_lookAtFadeOutSpeed), 0.0f, 1.0f);

				// Blend To The Target
				if (targetGlobal.IsValid())
				{
						m_lookAtTargetGlobal = targetGlobal;
				}
				SmoothCD(m_lookAtInterpolatedTargetGlobal, m_lookAtTargetRate, frameTime, m_lookAtTargetGlobal, m_lookAtTargetSmoothTime);

				// Push the LookAtSimple PoseModifier
				if (useLookAtSimple && (m_lookAtWeight > 0.0f))
				{
						m_lookAtSimple->SetTargetGlobal(m_lookAtInterpolatedTargetGlobal);
						m_lookAtSimple->SetWeight(m_lookAtWeight);
						pCharacter->GetISkeletonAnim()->PushLayer(cryinterface_cast<IAnimationPoseModifier>(m_lookAtSimple));
				}
		}
}
void CAnimatedCharacter::SetDesiredLocalLocation( ISkeletonAnim* pSkeletonAnim, const QuatT& desiredLocalLocation, float fDeltaTime)
{
	CRY_ASSERT(desiredLocalLocation.IsValid());

	{
		uint32 NumAnimsInQueue = pSkeletonAnim->GetNumAnimsInFIFO(0);
		uint32 nMaxActiveInQueue=MAX_EXEC_QUEUE;
		if (nMaxActiveInQueue>NumAnimsInQueue)
			nMaxActiveInQueue=NumAnimsInQueue;
		if (NumAnimsInQueue>nMaxActiveInQueue)
			NumAnimsInQueue=nMaxActiveInQueue;

		uint32 active=0;
		for (uint32 a=0; a<NumAnimsInQueue; a++)
		{
			const CAnimation& anim = pSkeletonAnim->GetAnimFromFIFO(0,a);
			active += anim.IsActivated() ? 1 : 0;
		}

		if (active>nMaxActiveInQueue)
			active=nMaxActiveInQueue;
		nMaxActiveInQueue=active;

		const SParametricSampler *pLMG = NULL;
		for (int32 a=nMaxActiveInQueue-1; (a >= 0) && !pLMG; --a)
		{
			const CAnimation& anim = pSkeletonAnim->GetAnimFromFIFO(0,a);
			pLMG = anim.GetParametricSampler();
		}
	}

	const Vec3 dir = desiredLocalLocation.GetColumn1();
	float turnAngle = atan2f(-dir.x, dir.y);

	float turnSpeed = turnAngle / fDeltaTime;

	const Vec2 deltaVector(desiredLocalLocation.t.x, desiredLocalLocation.t.y);
	const float travelDist = deltaVector.GetLength();

	const Vec2 deltaDir = (travelDist > 0.0f) ? (deltaVector / travelDist) : Vec2(0,0);
	float travelAngle = (deltaDir.x == 0.0f && deltaDir.y == 0.0f  ? 0.0f : atan2f(-deltaDir.x, deltaDir.y));

	float travelSpeed;
	if (gEnv->bMultiplayer)
	{
		travelSpeed = travelDist / fDeltaTime;
	}
	else
	{
		const float cosGroundSlope = fabsf(cosf(m_fGroundSlopeMoveDirSmooth));
		travelSpeed = (cosGroundSlope > FLT_EPSILON) ? (travelDist / (fDeltaTime * cosGroundSlope)) : (travelDist / fDeltaTime);
	}

	// TravelAngle smoothing
	{
		const Vec2 newStrafe = Vec2(-sin_tpl(travelAngle), cos_tpl(travelAngle));
		if (CAnimationGraphCVars::Get().m_enableTurnAngleSmoothing)
		{
			SmoothCD(m_fDesiredStrafeSmoothQTX, m_fDesiredStrafeSmoothRateQTX, fDeltaTime, newStrafe, 0.10f);
		}
		else 
		{
			m_fDesiredStrafeSmoothQTX=newStrafe;
			m_fDesiredStrafeSmoothRateQTX.zero();
		}
		travelAngle = Ang3::CreateRadZ(Vec2(0,1),m_fDesiredStrafeSmoothQTX);
	}

	const bool modulateTurnSpeedByTravelAngle = true;
	if (modulateTurnSpeedByTravelAngle)
	{
		static float minimum = DEG2RAD(10.0f); // do not change turnSpeed when travelAngle is below this
		static float maximum = DEG2RAD(40.0f); // force turnspeed to zero when travelAngle is above this
		const float turnSpeedScale = 1.0f - clamp_tpl( fabsf(travelAngle) - minimum, 0.0f, maximum - minimum ) / ( maximum - minimum );
		turnSpeed *= turnSpeedScale;
	}

	// TurnSpeed smoothing
	{
		if (CAnimationGraphCVars::Get().m_enableTurnSpeedSmoothing)
		{
			SmoothCD(m_fDesiredTurnSpeedSmoothQTX, m_fDesiredTurnSpeedSmoothRateQTX, fDeltaTime, turnSpeed, 0.40f);
		}
		else
		{
			m_fDesiredTurnSpeedSmoothQTX = turnSpeed;
			m_fDesiredTurnSpeedSmoothRateQTX = 0.0f;
		}
	}

	// TravelSpeed smoothing
	{
		if (CAnimationGraphCVars::Get().m_enableTravelSpeedSmoothing)
		{
			SmoothCD(m_fDesiredMoveSpeedSmoothQTX, m_fDesiredMoveSpeedSmoothRateQTX, fDeltaTime, travelSpeed, 0.04f);
		}
		else
		{
			m_fDesiredMoveSpeedSmoothQTX = travelSpeed;
			m_fDesiredMoveSpeedSmoothRateQTX = 0.0f;
		}
	}

	SetMotionParam(pSkeletonAnim, eMotionParamID_TravelSpeed, m_fDesiredMoveSpeedSmoothQTX);
	SetMotionParam(pSkeletonAnim, eMotionParamID_TurnSpeed, m_fDesiredTurnSpeedSmoothQTX * CAnimationGraphCVars::Get().m_turnSpeedParamScale);
	SetMotionParam(pSkeletonAnim, eMotionParamID_TravelAngle, travelAngle);
	// eMotionParamID_TravelSlope
	SetMotionParam(pSkeletonAnim, eMotionParamID_TurnAngle, turnAngle);
	// eMotionParamID_TravelDist
	SetMotionParam(pSkeletonAnim, eMotionParamID_StopLeg, 0);
}
void SBasicReplayMovementParams::SetDesiredLocalLocation2( ISkeletonAnim* pSkeletonAnim, const QuatT& desiredLocalLocation, float lookaheadTime, float fDeltaTime, float turnSpeedMultiplier)
{
	QuatT m_desiredLocalLocationQTX			= desiredLocalLocation;
	assert(m_desiredLocalLocationQTX.q.IsValid());
	f32 m_desiredArrivalDeltaTimeQTX		= lookaheadTime;
	f32 m_desiredTurnSpeedMultiplierQTX = turnSpeedMultiplier;

	uint32 NumAnimsInQueue = pSkeletonAnim->GetNumAnimsInFIFO(0);
	uint32 nMaxActiveInQueue=MAX_EXEC_QUEUE;	
	if (nMaxActiveInQueue>NumAnimsInQueue)
		nMaxActiveInQueue=NumAnimsInQueue;
	if (NumAnimsInQueue>nMaxActiveInQueue)
		NumAnimsInQueue=nMaxActiveInQueue;

	uint32 active=0;
	for (uint32 a=0; a<NumAnimsInQueue; a++)
	{
		CAnimation& anim = pSkeletonAnim->GetAnimFromFIFO(0,a);
		active += anim.IsActivated() ? 1 : 0;
	}

	if (active>nMaxActiveInQueue)
		active=nMaxActiveInQueue;
	nMaxActiveInQueue=active;


	const QuatT &rDesiredLocation = m_desiredLocalLocationQTX;

	const SParametricSampler *pLMG = NULL;
	for (int32 a=nMaxActiveInQueue-1; (a >= 0) && !pLMG; --a)
	{
		const CAnimation& anim = pSkeletonAnim->GetAnimFromFIFO(0,a);
		pLMG = anim.GetParametricSampler();
	}

	Vec3 dir = rDesiredLocation.q * FORWARD_DIRECTION;
	Vec2 predictedDir( dir.x, dir.y );

	float predictedAngle = RAD2DEG(atan2f(-predictedDir.x, predictedDir.y));
	float turnSpeed = m_desiredTurnSpeedMultiplierQTX * DEG2RAD(predictedAngle) / max(0.1f, m_desiredArrivalDeltaTimeQTX);
	float turnAngle = DEG2RAD(predictedAngle);

	Vec2 deltaVector(rDesiredLocation.t.x, rDesiredLocation.t.y);
	float deltaDist = deltaVector.GetLength();

	const float thresholdDistMin = 0.05f;
	const float thresholdDistMax = 0.15f;
	f32 uniform_scale = 1.0f;//m_pInstance->CCharInstance::GetUniformScale();

	float travelDistScale = CLAMP((deltaDist - thresholdDistMin) / (thresholdDistMax - thresholdDistMin), 0.0f, 1.0f);
	pSkeletonAnim->SetDesiredMotionParam(eMotionParamID_TravelDistScale, travelDistScale/uniform_scale, fDeltaTime);

	Vec2 deltaDir = (deltaDist > 0.0f) ? (deltaVector / deltaDist) : Vec2(0,0);
	float deltaAngle = (deltaDir.x == 0.0f && deltaDir.y == 0.0f  ? 0.0f : RAD2DEG(atan2f(-deltaDir.x, deltaDir.y)) );
	float travelAngle = DEG2RAD(deltaAngle);

	// Update travel direction only if distance bigger (more secure) than thresholdDistMax.
	// Though, also update travel direction if distance is small enough to not have any visible effect (since distance scale is zero).
	bool initOnly = DO_INIT_ONLY_TEST && ((deltaDist > thresholdDistMin) && (deltaDist < thresholdDistMax));

	Vec2 newStrafe = Vec2(-cry_sinf(travelAngle), cry_cosf(travelAngle));
	if (pLMG) 
	{
		SmoothCD(m_desiredStrafeSmoothQTX, m_desiredStrafeSmoothRateQTX, fDeltaTime, newStrafe, 0.10f);
	}
	else 
	{
		//	CryFatalError("CryAnimation: no smooth");
		m_desiredStrafeSmoothQTX=newStrafe;
		m_desiredStrafeSmoothRateQTX.zero();
	}
	travelAngle=Ang3::CreateRadZ(Vec2(0,1),m_desiredStrafeSmoothQTX);
	pSkeletonAnim->SetDesiredMotionParam(eMotionParamID_TravelAngle, travelAngle, fDeltaTime);

	float curvingFraction = 0.0f;

	if (pLMG)
	{
		SmoothCD(m_fDesiredTurnSpeedSmoothQTX, m_fDesiredTurnSpeedSmoothRateQTX, fDeltaTime, turnSpeed, 0.40f);
	}
	else
	{
		m_fDesiredTurnSpeedSmoothQTX=turnSpeed;
		m_fDesiredTurnSpeedSmoothRateQTX = 0.0f;
	}
	pSkeletonAnim->SetDesiredMotionParam(eMotionParamID_TurnSpeed, m_fDesiredTurnSpeedSmoothQTX, fDeltaTime);
	pSkeletonAnim->SetDesiredMotionParam(eMotionParamID_TurnAngle, turnAngle, fDeltaTime);

	// Curving Distance	
	float div = cry_cosf(DEG2RAD(90.0f - predictedAngle));
	float curveRadius = (deltaDist / 2.0f);

	if( abs(div) > 0.0f )
		curveRadius = curveRadius / div;
	float circumference = curveRadius * 2.0f * gf_PI;
	float curveDist = circumference * (predictedAngle * 2.0f / 360.0f);
	curveDist = max(deltaDist, curveDist);

	// Travel Speed/Distance
	float travelDist = LERP(deltaDist, curveDist, curvingFraction);
	float travelSpeed = travelDist / max(0.1f, m_desiredArrivalDeltaTimeQTX);
	//travelDist *= travelDistScale;
	//travelSpeed *= travelDistScale;

	//	float fColDebug[4] = {1,0,0,1};
	//	g_pIRenderer->Draw2dLabel( 1,g_YLine, 2.6f, fColDebug, false,"qqqtravelSpeed: atime: %f", travelSpeed );	
	//	g_YLine+=26.0f;
	SmoothCD(m_fDesiredMoveSpeedSmoothQTX, m_fDesiredMoveSpeedSmoothRateQTX, fDeltaTime, travelSpeed, 0.04f);
	pSkeletonAnim->SetDesiredMotionParam(eMotionParamID_TravelSpeed, m_fDesiredMoveSpeedSmoothQTX, fDeltaTime);
	pSkeletonAnim->SetDesiredMotionParam(eMotionParamID_TravelDist, travelDist, fDeltaTime);
	pSkeletonAnim->SetDesiredMotionParam(eMotionParamID_Scale, uniform_scale, fDeltaTime);
}
void CVehicleMovementMPVTOL::SPathing::UpdatePathFollowing( const EntityId vtolId, const float dt, CVehicleMovementMPVTOL& rMovement, const SVehiclePhysicsStatus& physStatus, const Vec3& posNoise )
{
    //CryWatch("VTOL: id[%d] path[%p] loc[%f] error[%f] wait[%f]", vtolId, pCachedPathPtr, pathingData.location, networkError, waitTime );

    if(!pCachedPathPtr)
        return;

    networkError *= max(0.f, 1.f-(dt*2.0f));
    float networkAdj = networkError;

    if(waitTime > 0.f)
    {
        waitTime -= dt;
        if(waitTime < 0.f)
        {
            waitTime = 0.f;
            targetSpeed = defaultSpeed;
        }
        else
        {
            networkAdj = 0.f;
            targetSpeed = 0.0f;
        }
    }

    CWaypointPath::TNodeId currentInerpolatedNode = interpolatedNode;
    Vec3 targetPos;
    if(pCachedPathPtr->GetPosAfterDistance(currentNode, physStatus.centerOfMass, g_pGameCVars->g_VTOLPathingLookAheadDistance, targetPos, interpolatedNode, currentNode, pathingData.location, shouldLoop))
    {
        QuatT location;
        CWaypointPath::TNodeId locationNode = -1;
        pCachedPathPtr->GetPathLoc(pathingData.location, location, locationNode);
        const Vec3 forward(targetPos-location.t);
        const Vec3 side(forward.y, -forward.x, 0.f);
        Vec3 noise(side.GetNormalizedSafe(physStatus.q.GetColumn0())*posNoise.x);
        noise.z = posNoise.z;

        targetPos += noise;

        if(waitTime<=0.f && currentInerpolatedNode!=interpolatedNode)
        {
            float fValueOut = 0.f;
            CWaypointPath::E_NodeDataType dataTypeOut;
            if(pCachedPathPtr->HasDataAtNode(interpolatedNode, dataTypeOut, fValueOut))
            {
                if(dataTypeOut == CWaypointPath::ENDT_Speed)
                {
                    targetSpeed = fValueOut;
                }
                else if(dataTypeOut == CWaypointPath::ENDT_Wait && fValueOut > 0.f)
                {
                    targetSpeed = speed = 0.f;
                    waitTime = fValueOut;
                }
            }
            else
            {
                targetSpeed = defaultSpeed;
            }
        }

        SmoothCD(speed, accel, dt, targetSpeed, 0.2f);
        const float finalSpeed = max(0.f, speed + clamp( networkAdj, -speed, g_pGameCVars->v_MPVTOLNetworkCatchupSpeedLimit ));
        const float scalar = clamp( (speed>0.1f) ? finalSpeed/speed : 1.f, 1.f, 3.f );

        CMovementRequest movementRequest;
        movementRequest.SetDesiredSpeed(finalSpeed);
        movementRequest.SetMoveTarget(targetPos);
        movementRequest.SetBodyTarget(targetPos);
        movementRequest.SetLookTarget(targetPos);

        rMovement.RequestMovement(movementRequest);
        rMovement.SetYawResponseScalar(scalar);
    }
    else
    {
        pathComplete |= 0x1;
    }
}
void CVehicleMovementMPVTOL::Update(const float deltaTime)
{
    BaseClass::Update(deltaTime);

    //Update wing rotation based on linear and angular velocities
    if(m_pLeftWing && m_pRightWing)
    {
        const float angVelZ = m_physStatus[k_mainThread].w.z;
        const float speedRatio = min(1.f, __fres(m_maxAngleSpeed)*m_CurrentSpeed);

        //Move inside and outside wings (in terms of turning circle) at different speeds
        const bool leftWingIsInside = angVelZ > 0.f;

        const float maxRadAtCurrentSpeedOutside = m_maxAngleRad * speedRatio * clamp(m_angularVelMult * angVelZ, -1.f, 1.f);
        const float maxRadAtCurrentSpeedInside = maxRadAtCurrentSpeedOutside * m_insideWingMaxAngleMult;

        const float insideSmoothRate = m_angleSmoothTime * (2.f - speedRatio);
        const float outsideSmoothRate = insideSmoothRate * m_insideWingSpeedMult;

        if(leftWingIsInside)
        {
            SmoothCD(m_leftWingRotationRad, m_leftWingRotationSmoothRate, deltaTime, maxRadAtCurrentSpeedInside, insideSmoothRate);
            SmoothCD(m_rightWingRotationRad, m_rightWingRotationSmoothRate, deltaTime, maxRadAtCurrentSpeedOutside, outsideSmoothRate);
        }
        else
        {
            SmoothCD(m_leftWingRotationRad, m_leftWingRotationSmoothRate, deltaTime, maxRadAtCurrentSpeedOutside, outsideSmoothRate);
            SmoothCD(m_rightWingRotationRad, m_rightWingRotationSmoothRate, deltaTime, maxRadAtCurrentSpeedInside, insideSmoothRate);
        }

        const float leftWingNoise = m_leftWingNoise.Update(deltaTime);
        const float rightWingNoise = m_rightWingNoise.Update(deltaTime);

        const Quat leftRotation = Quat::CreateRotationX(m_leftWingRotationRad+leftWingNoise);
        const Quat rightRotation = Quat::CreateRotationX(-m_rightWingRotationRad+rightWingNoise);

        m_pLeftWing->SetLocalBaseTM(Matrix34(leftRotation));
        m_pRightWing->SetLocalBaseTM(Matrix34(rightRotation));
    }

    //Exhausts periodically cut out whilst damaged
    if(m_exhaustsCutOut || m_exhaustsTimer)
    {
        m_exhaustsTimer -= deltaTime;
        if(m_exhaustsTimer < 0.f)
        {
            if(m_exhaustsCutOut)
            {
                StartExhaust();
                if(--m_exhaustStuttersRemaining > 0)
                {
                    m_exhaustsTimer = m_stutterDurationOn;
                }
                else
                {
                    m_exhaustsTimer = Random(m_minTimeBetweenStutters, m_maxTimeBetweenStutters);

                    //Time between stutters decreases linearly as more damage is received
                    float progress = m_pVehicle->GetDamageRatio() - m_stutterStartDamageRatio;
                    m_exhaustsTimer *= 1.f - ((progress * m_invStutterDamageSpread) * m_timeBetweenStutterDecayMult);

                    m_exhaustStuttersRemaining = m_baseStutters + Random(m_maxExtraStutters); //Number of stutters next time
                }
            }
            else
            {
                StopExhaust();
                m_exhaustsTimer = m_stutterDurationOff;
            }
            m_exhaustsCutOut = !m_exhaustsCutOut;
        }
    }

#ifndef _RELEASE
    // Keep updating this, in case it is changed mid-game.
    m_sendTime = g_pGameCVars->v_MPVTOLNetworkSyncFreq;
#endif
}
//------------------------------------------------------------------------
void CMelee::Update(float frameTime, uint32 frameId)
{
	FUNCTION_PROFILER( GetISystem(), PROFILE_GAME );

	bool remote = false;
	bool doMelee = false;
	bool requireUpdate = false;

	Vec3 dirToTarget(ZERO);
	if(m_pMeleeAction && s_meleeSnapTargetId && g_pGameCVars->pl_melee.mp_melee_system_camera_lock_and_turn)
	{
		m_attackTime += frameTime;

		CActor* pOwner = m_pWeapon->GetOwnerActor();
		IEntity* pTarget = gEnv->pEntitySystem->GetEntity(s_meleeSnapTargetId);
		if(pOwner && pTarget)
		{
			Vec3 targetPos = pTarget->GetWorldPos();

			if(s_bMeleeSnapTargetCrouched)
			{
				targetPos.z -= g_pGameCVars->pl_melee.mp_melee_system_camera_lock_crouch_height_offset;
			}

			dirToTarget = targetPos - pOwner->GetEntity()->GetWorldPos();
			dirToTarget.Normalize();

			static const float smooth_time = 0.1f;
			SmoothCD(m_attackTurnAmount, m_attackTurnAmountSmoothRate, frameTime, 1.f, smooth_time);
			Quat newViewRotation;
			newViewRotation.SetSlerp(pOwner->GetViewRotation(), Quat::CreateRotationVDir(dirToTarget), m_attackTurnAmount);
			Ang3 newAngles(newViewRotation);
			newAngles.y = 0.f; //No head tilting
			newViewRotation = Quat(newAngles);
			pOwner->SetViewRotation( newViewRotation );
		}

		if(m_attackTime >= g_pGameCVars->pl_melee.mp_melee_system_camera_lock_time && pOwner && pOwner->IsClient())
		{
			pOwner->GetActorParams().viewLimits.ClearViewLimit(SViewLimitParams::eVLS_Item);
		}
	}

	if (m_attacking)
	{
		MeleeDebugLog ("CMelee<%p> Update while attacking: m_attacked=%d, delay=%f", this, m_attacked, m_delayTimer);

		requireUpdate = true;
		if (m_delayTimer>0.0f)
		{
			RequestAlignmentToNearestTarget();
			m_delayTimer-=frameTime;
			if (m_delayTimer<=0.0f)
			{
				m_delayTimer=0.0f;
			}
		}
		else if (m_netAttacking)
		{
			remote = true;
			doMelee = true;
			m_attacking = false;
			m_slideKick = false;
			m_netAttacking = false;

			m_pWeapon->SetBusy(false);
		}	
		else if (!m_attacked)
		{
			doMelee = true;
			m_attacked = true;
		}

		if ( !m_collisionHelper.IsBlocked() && doMelee)
		{
			if (CActor *pActor = m_pWeapon->GetOwnerActor())
			{
				if (IMovementController * pMC = pActor->GetMovementController())
				{
					SMovementState info;
					pMC->GetMovementState(info);

					if(!dirToTarget.IsZeroFast())
					{
						PerformMelee(info.weaponPosition, dirToTarget, remote); //We know where we will be facing at the point of impact - using our current fire direction is not accurate enough
					}
					else
					{
						PerformMelee(info.weaponPosition, info.fireDirection, remote);
					}
				}
			}
		}

		if( (m_useMeleeWeaponDelay <= 0.0f && m_useMeleeWeaponDelay > -1.0f) )
		{
			m_useMeleeWeaponDelay = -1.0f;

			// Switch to the MELEE WEAPON.
			SwitchToMeleeWeaponAndAttack();

			m_attacking = false;
		}
		m_useMeleeWeaponDelay -= frameTime;
	}

	if (requireUpdate)
		m_pWeapon->RequireUpdate(eIUS_FireMode);
}