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

	if(!m_isVTOLMovement)
	{
		CVehicleMovementHelicopter::ProcessAI(deltaTime);
		return;
	}

	m_velDamp = 0.15f;

	const float maxDirChange = 15.0f;

	// it's useless to progress further if the engine has yet to be turned on
	if(!m_isEnginePowered)
		return;

	m_movementAction.Clear();
	m_movementAction.isAI = true;
	ResetActions();

	// Our current state
	const Vec3 worldPos =  m_PhysPos.pos;
	const Matrix33 worldMat(m_PhysPos.q);
	Ang3 worldAngles = Ang3::GetAnglesXYZ(worldMat);

	const Vec3 currentVel = m_PhysDyn.v;
	const Vec3 currentVel2D(currentVel.x, currentVel.y, 0.0f);
	// +ve direction mean rotation anti-clocwise about the z axis - 0 means along y
	float currentDir = worldAngles.z;

	// to avoid singularity
	const Vec3 vWorldDir = worldMat * FORWARD_DIRECTION;
	const Vec3 vWorldDir2D =  Vec3(vWorldDir.x,  vWorldDir.y, 0.0f).GetNormalizedSafe();

	// Our inputs
	const float desiredSpeed = m_aiRequest.HasDesiredSpeed() ? m_aiRequest.GetDesiredSpeed() : 0.0f;
	const Vec3 desiredMoveDir = m_aiRequest.HasMoveTarget() ? (m_aiRequest.GetMoveTarget() - worldPos).GetNormalizedSafe() : vWorldDir;
	const Vec3 desiredMoveDir2D = Vec3(desiredMoveDir.x, desiredMoveDir.y, 0.0f).GetNormalizedSafe(vWorldDir2D);
	const Vec3 desiredVel = desiredMoveDir * desiredSpeed;
	const Vec3 desiredVel2D(desiredVel.x, desiredVel.y, 0.0f);
	const Vec3 desiredLookDir = m_aiRequest.HasLookTarget() ? (m_aiRequest.GetLookTarget() - worldPos).GetNormalizedSafe() : desiredMoveDir;
	const Vec3 desiredLookDir2D = Vec3(desiredLookDir.x, desiredLookDir.y, 0.0f).GetNormalizedSafe(vWorldDir2D);

	// Calculate the desired 2D velocity change
	Vec3 desiredVelChange2D = desiredVel2D - currentVel2D;
	float velChangeLength = desiredVelChange2D.GetLength2D();

	bool isLandingMode = false;

	if(m_pLandingGears && m_pLandingGears->AreLandingGearsOpen())
		isLandingMode = true;

	bool isHorizontal = (desiredSpeed >= 5.0f) && (desiredMoveDir.GetLength2D() > desiredMoveDir.z);
	float desiredPitch = 0.0f;
	float desiredRoll = 0.0f;

	float desiredDir = atan2f(-desiredLookDir2D.x, desiredLookDir2D.y);

	while(currentDir < desiredDir - gf_PI)
		currentDir += 2.0f * gf_PI;

	while(currentDir > desiredDir + gf_PI)
		currentDir -= 2.0f * gf_PI;

	float diffDir = (desiredDir - currentDir);
	m_actionYaw = diffDir * m_yawInputConst;
	m_actionYaw += m_yawInputDamping * (currentDir - m_lastDir) / deltaTime;
	m_lastDir = currentDir;

	if(isHorizontal && !isLandingMode)
	{
		float desiredFwdSpeed = desiredVelChange2D.GetLength();

		desiredFwdSpeed *= min(1.0f, diffDir / DEG2RAD(maxDirChange));

		if(!iszero(desiredFwdSpeed))
		{
			const Vec3 desiredWorldTiltAxis = Vec3(-desiredVelChange2D.y, desiredVelChange2D.x, 0.0f);
			const Vec3 desiredLocalTiltAxis = worldMat.GetTransposed() * desiredWorldTiltAxis;

			m_forwardAction = m_fwdPID.Update(currentVel.y, desiredLocalTiltAxis.GetLength(), -1.0f, 1.0f);

			float desiredTiltAngle = m_tiltPerVelDifference * desiredVelChange2D.GetLength();
			Limit(desiredTiltAngle, -m_maxTiltAngle, m_maxTiltAngle);

			if(desiredTiltAngle > 0.0001f)
			{
				const Vec3 desiredWorldTiltAxis2 = Vec3(-desiredVelChange2D.y, desiredVelChange2D.x, 0.0f).GetNormalizedSafe();
				const Vec3 desiredLocalTiltAxis2 = worldMat.GetTransposed() * desiredWorldTiltAxis2;

				Vec3 vVelLocal = worldMat.GetTransposed() * desiredVel;
				vVelLocal.NormalizeSafe();

				float dotup = vVelLocal.Dot(Vec3(0.0f,0.0f,1.0f));
				float currentSpeed = currentVel.GetLength();

				desiredPitch = dotup *currentSpeed / 100.0f;
				desiredRoll = desiredTiltAngle * desiredLocalTiltAxis2.y *currentSpeed/30.0f;
			}

		}
	}
	else
	{
		float desiredTiltAngle = m_tiltPerVelDifference * desiredVelChange2D.GetLength();
		Limit(desiredTiltAngle, -m_maxTiltAngle, m_maxTiltAngle);

		if(desiredTiltAngle > 0.0001f)
		{
			const Vec3 desiredWorldTiltAxis = Vec3(-desiredVelChange2D.y, desiredVelChange2D.x, 0.0f).GetNormalizedSafe();
			const Vec3 desiredLocalTiltAxis = worldMat.GetTransposed() * desiredWorldTiltAxis;

			desiredPitch = desiredTiltAngle * desiredLocalTiltAxis.x;
			desiredRoll = desiredTiltAngle * desiredLocalTiltAxis.y;
		}
	}

	float currentHeight = m_PhysPos.pos.z;

	if(m_aiRequest.HasMoveTarget())
	{
		m_hoveringPower = m_powerPID.Update(currentVel.z, desiredVel.z, -1.0f, 4.0f);

		//m_hoveringPower = (m_desiredHeight - currentHeight) * m_powerInputConst;
		//m_hoveringPower += m_powerInputDamping * (currentHeight - m_lastHeight) / deltaTime;

		if(isHorizontal)
		{
			if(desiredMoveDir.z > 0.6f || desiredMoveDir.z < -0.85f)
			{
				desiredPitch = max(-0.5f, min(0.5f, desiredMoveDir.z)) * DEG2RAD(35.0f);
				m_forwardAction += abs(desiredMoveDir.z);
			}

			m_liftAction = min(2.0f, max(m_liftAction, m_hoveringPower * 2.0f));
		}
		else
		{
			m_liftAction = 0.0f;
		}
	}
	else
	{
		// to keep hovering at the same place
		m_hoveringPower = m_powerPID.Update(currentVel.z, m_desiredHeight - currentHeight, -1.0f, 1.0f);
		m_liftAction = 0.0f;

		if(m_pVehicle->GetAltitude() > 10.0f)	//TODO: this line is not MTSafe
			m_liftAction = m_forwardAction;
	}

	m_actionPitch += m_pitchActionPerTilt * (desiredPitch - worldAngles.x);
	m_actionRoll += m_pitchActionPerTilt * (desiredRoll - worldAngles.y);

	Limit(m_actionPitch, -1.0f, 1.0f);
	Limit(m_actionRoll, -1.0f, 1.0f);
	Limit(m_actionYaw, -1.0f, 1.0f);

	if(m_horizontal > 0.0001f)
		m_desiredHeight = m_PhysPos.pos.z;

	Limit(m_forwardAction, -1.0f, 1.0f);
}
//------------------------------------------------------------------------
void CVehicleMovementVTOL::Update(const float deltaTime)
{
	FUNCTION_PROFILER(GetISystem(), PROFILE_GAME);

	CVehicleMovementHelicopter::Update(deltaTime);
	CryAutoCriticalSection lk(m_lock);

	if(m_pWingsAnimation)
	{
		m_pWingsAnimation->SetTime(m_wingsAnimTime);
	}

	IActorSystem *pActorSystem = g_pGame->GetIGameFramework()->GetIActorSystem();
	assert(pActorSystem);

	IActor *pActor = pActorSystem->GetActor(m_actorId);

	if(pActor && pActor->IsClient())
	{
		float turbulence = m_turbulence;

		if(m_pAltitudeLimitVar)
		{
			float altitudeLimit = m_pAltitudeLimitVar->GetFVal();
			float currentHeight = m_pEntity->GetWorldPos().z;

			if(!iszero(altitudeLimit))
			{
				float altitudeLowerOffset;

				if(m_pAltitudeLimitLowerOffsetVar)
				{
					float r = 1.0f - min(1.0f, max(0.0f, m_pAltitudeLimitLowerOffsetVar->GetFVal()));
					altitudeLowerOffset = r * altitudeLimit;

					if(currentHeight >= altitudeLowerOffset)
					{
						if(currentHeight > altitudeLowerOffset)
						{
							float zone = altitudeLimit - altitudeLowerOffset;
							turbulence += (currentHeight - altitudeLowerOffset) / (zone);
						}
					}
				}
			}
		}

		if(turbulence > 0.0f)
		{
			static_cast<CActor *>(pActor)->CameraShake(0.50f * turbulence, 0.0f, 0.05f, 0.04f, Vec3(0.0f, 0.0f, 0.0f), 10, "VTOL_Update_Turbulence");
		}

		float enginePowerRatio = m_enginePower / m_enginePowerMax;

		if(enginePowerRatio > 0.0f)
		{
			float rpmScaleDesired = 0.2f;
			rpmScaleDesired += abs(m_forwardAction) * 0.8f;
			rpmScaleDesired += abs(m_strafeAction) * 0.4f;
			rpmScaleDesired += abs(m_turnAction) * 0.25f;
			rpmScaleDesired = min(1.0f, rpmScaleDesired);
			Interpolate(m_rpmScale, rpmScaleDesired, 1.0f, deltaTime);
		}

		float turnParamGoal = min(1.0f, abs(m_turnAction)) * 0.6f;
		turnParamGoal *= (min(1.0f, max(0.0f, m_speedRatio)) + 1.0f) * 0.50f;
		turnParamGoal += turnParamGoal * m_boost * 0.25f;
		Interpolate(m_soundParamTurn, turnParamGoal, 0.5f, deltaTime);
		SetSoundParam(eSID_Run, "turn", m_soundParamTurn);

		float damage = GetSoundDamage();

		if(damage > 0.1f)
		{
			//if (ISound* pSound = GetOrPlaySound(eSID_Damage, 5.f, m_enginePos))
			//SetSoundParam(pSound, "damage", damage);
		}
	}
}
//------------------------------------------------------------------------
void CVehicleMovementVTOL::ProcessActions(const float deltaTime)
{
	FUNCTION_PROFILER(GetISystem(), PROFILE_GAME);

	UpdateDamages(deltaTime);
	UpdateEngine(deltaTime);

	m_velDamp = 0.25f;

	m_playerControls.ProcessActions(deltaTime);

	Limit(m_forwardAction, -1.0f, 1.0f);
	Limit(m_strafeAction, -1.0f, 1.0f);

	m_actionYaw = 0.0f;

	Vec3 worldPos = m_pEntity->GetWorldPos();

	IPhysicalEntity *pPhysics = GetPhysics();

	// get the current state

	// roll pitch + yaw

	Matrix34 worldTM = m_pRotorPart ? m_pRotorPart->GetWorldTM() : m_pEntity->GetWorldTM();
//	if (m_pRotorPart)
//		worldTM = m_pRotorPart->GetWorldTM();
//	else
//		worldTM = m_pEntity->GetWorldTM();

	Vec3 specialPos = worldTM.GetTranslation();
	Ang3 angles = Ang3::GetAnglesXYZ(Matrix33(worldTM));

	Matrix33 tm;
	tm.SetRotationXYZ((angles));

	// +ve pitch means nose up
	const float &currentPitch = angles.x;
	// +ve roll means to the left
	const float &currentRoll = angles.y;
	// +ve direction mean rotation anti-clockwise about the z axis - 0 means along y
	float currentDir = angles.z;

	const float maxPitchAngle = 60.0f;

	float pitchDeg = RAD2DEG(currentPitch);

	if(pitchDeg >= (maxPitchAngle * 0.75f))
	{
		float mult = pitchDeg / (maxPitchAngle);

		if(mult > 1.0f && m_desiredPitch < 0.0f)
		{
			m_desiredPitch *= 0.0f;
			m_actionPitch *= 0.0f;
			m_desiredPitch += 0.2f * mult;
		}
		else if(m_desiredPitch < 0.0f)
		{
			m_desiredPitch *= (1.0f - mult);
			m_desiredPitch += 0.05f;
		}
	}
	else if(pitchDeg <= (-maxPitchAngle * 0.75f))
	{
		float mult = abs(pitchDeg) / (maxPitchAngle);

		if(mult > 1.0f && m_desiredPitch > 0.0f)
		{
			m_desiredPitch *= 0.0f;
			m_actionPitch *= 0.0f;
			m_desiredPitch += 0.2f * mult;
		}
		else if(m_desiredPitch > 0.0f)
		{
			m_desiredPitch *= (1.0f - mult);
			m_desiredPitch -= 0.05f;
		}
	}

	if(currentRoll >= DEG2RAD(m_maxRollAngle * 0.7f) && m_desiredRoll > 0.001f)
	{
		float r = currentRoll / DEG2RAD(m_maxRollAngle);
		r = min(1.0f, r * 1.0f);
		r = 1.0f - r;
		m_desiredRoll *= r;
		m_desiredRoll = min(1.0f, m_desiredRoll);
	}
	else if(currentRoll <= DEG2RAD(-m_maxRollAngle * 0.7f) && m_desiredRoll < 0.001f)
	{
		float r = abs(currentRoll) / DEG2RAD(m_maxRollAngle);
		r = min(1.0f, r * 1.0f);
		r = 1.0f - r;
		m_desiredRoll *= r;
		m_desiredRoll = max(-1.0f, m_desiredRoll);
	}

	Vec3 currentFwdDir2D = m_currentFwdDir;
	currentFwdDir2D.z = 0.0f;
	currentFwdDir2D.NormalizeSafe();

	Vec3 currentLeftDir2D(-currentFwdDir2D.y, currentFwdDir2D.x, 0.0f);

	Vec3 currentVel = m_PhysDyn.v;
	Vec3 currentVel2D = currentVel;
	currentVel2D.z = 0.0f;

	float currentHeight = worldPos.z;
	float currentFwdSpeed = currentVel.Dot(currentFwdDir2D);

	ProcessActions_AdjustActions(deltaTime);

	float inputMult = m_basicSpeedFraction;

	// desired things
	float turnDecreaseScale = m_yawDecreaseWithSpeed / (m_yawDecreaseWithSpeed + fabs(currentFwdSpeed));

	Vec3 desired_vel2D =
		currentFwdDir2D * m_forwardAction * m_maxFwdSpeed * inputMult +
		currentLeftDir2D * m_strafeAction * m_maxLeftSpeed * inputMult;

	// calculate the angle changes

	Vec3 desiredVelChange2D = desired_vel2D - currentVel2D;

	float desiredTiltAngle = m_tiltPerVelDifference * desiredVelChange2D.GetLength();
	Limit(desiredTiltAngle, -m_maxTiltAngle, m_maxTiltAngle);

	float goal = abs(m_desiredPitch) + abs(m_desiredRoll);
	goal *= 1.5f;
	Interpolate(m_playerAcceleration, goal, 0.25f, deltaTime);
	Limit(m_playerAcceleration, 0.0f, 5.0f);

	//static float g_angleLift = 4.0f;

	if(abs(m_liftAction) > 0.001f && abs(m_forwardAction) < 0.001)
	{
//		float pitch = RAD2DEG(currentPitch);

		if(m_liftPitchAngle < 0.0f && m_liftAction > 0.0f)
			m_liftPitchAngle = 0.0f;
		else if(m_liftPitchAngle > 0.0f && m_liftAction < 0.0f)
			m_liftPitchAngle = 0.0f;

		Interpolate(m_liftPitchAngle, 1.25f * m_liftAction, 0.75f, deltaTime);

		if(m_liftPitchAngle < 1.0f && m_liftPitchAngle > -1.0f)
			m_desiredPitch += 0.05f * m_liftAction;
	}
	else if(m_liftAction < 0.001f && abs(m_liftPitchAngle) > 0.001)
	{
		Interpolate(m_liftPitchAngle, 0.0f, 1.0f, deltaTime);
		m_desiredPitch += 0.05f * -m_liftPitchAngle;
	}

	/* todo
	else if (m_liftAction < -0.001f)
	{
		m_desiredPitch += min(0.0f, (DEG2RAD(-5.0f) - currentPitch)) * 0.5f * m_liftAction;
	}*/

	if(!iszero(m_desiredPitch))
	{
		m_actionPitch -= m_desiredPitch * m_pitchInputConst;
		Limit(m_actionPitch, -m_maxYawRate, m_maxYawRate);
	}

	float rollAccel = 1.0f;

	if(abs(currentRoll + m_desiredRoll) < abs(currentRoll))
		rollAccel *= 1.25f;

	m_actionRoll += m_pitchActionPerTilt * m_desiredRoll * rollAccel * (m_playerAcceleration + 1.0f);
	Limit(m_actionRoll, -10.0f, 10.0f);
	Limit(m_actionPitch, -10.0f, 10.0f);

	// roll as we turn
	if(!m_strafeAction)
	{
		m_actionYaw += m_yawPerRoll * currentRoll;
	}

	if(abs(m_strafeAction) > 0.001f)
	{
		float side = 0.0f;
		side = min(1.0f, max(-1.0f, m_strafeAction));

		float roll = DEG2RAD(m_extraRollForTurn * 0.25f * side) - (currentRoll);
		m_actionRoll += max(0.0f, abs(roll)) * side * 1.0f;
	}

	float relaxRollTolerance = 0.0f;

	if(abs(m_turnAction) > 0.01f || abs(m_PhysDyn.w.z) > DEG2RAD(3.0f))
	{
		m_actionYaw += -m_turnAction * m_yawInputConst * GetDamageMult();

		float side = 0.0f;

		if(abs(m_turnAction) > 0.01f)
			side = min(1.0f, max(-1.0f, m_turnAction));

		float roll = DEG2RAD(m_extraRollForTurn * side) - (currentRoll);
		m_actionRoll += max(0.0f, abs(roll)) * side * m_rollForTurnForce;

		roll *= max(1.0f, abs(m_PhysDyn.w.z));

		m_actionRoll += roll;

		Limit(m_actionYaw, -m_maxYawRate, m_maxYawRate);
	}

	m_desiredDir = currentDir;
	m_lastDir = currentDir;

	float boost = Boosting() ? m_boostMult : 1.0f;
	float liftActionMax = 1.0f;

	if(m_pAltitudeLimitVar)
	{
		float altitudeLimit = m_pAltitudeLimitVar->GetFVal();

		if(!iszero(altitudeLimit))
		{
			float altitudeLowerOffset;

			if(m_pAltitudeLimitLowerOffsetVar)
			{
				float r = 1.0f - min(1.0f, max(0.0f, m_pAltitudeLimitLowerOffsetVar->GetFVal()));
				altitudeLowerOffset = r * altitudeLimit;
			}
			else
				altitudeLowerOffset = altitudeLimit;

			float mult = 1.0f;

			if(currentHeight >= altitudeLimit)
			{
				if(m_liftAction > 0.f)
				{
					mult = 0.0f;
				}
			}
			else if(currentHeight >= altitudeLowerOffset)
			{
				float zone = altitudeLimit - altitudeLowerOffset;
				mult = (altitudeLimit - currentHeight) / (zone);
			}

			m_liftAction *= mult;

			if(currentPitch > DEG2RAD(0.0f))
			{
				if(m_forwardAction > 0.0f)
					m_forwardAction *= mult;

				if(m_actionPitch > 0.0f)
				{
					m_actionPitch *= mult;
					m_actionPitch += -currentPitch;
				}
			}

			m_desiredHeight = min(altitudeLowerOffset, currentHeight);
		}
	}
	else
	{
		m_desiredHeight = currentHeight;
	}

	if(abs(m_liftAction) > 0.001f)
	{
		m_liftAction = min(liftActionMax, max(-0.2f, m_liftAction));

		m_hoveringPower = (m_powerInputConst * m_liftAction) * boost;
		m_noHoveringTimer = 0.0f;
	}
	else if(!m_isTouchingGround)
	{
		if(m_noHoveringTimer <= 0.0f)
		{
			float gravity;

			pe_simulation_params paramsSim;

			if(pPhysics->GetParams(&paramsSim))
				gravity = abs(paramsSim.gravity.z);
			else
				gravity = 9.2f;

			float upDirZ = m_workingUpDir.z;

			if(abs(m_forwardAction) > 0.01 && upDirZ > 0.0f)
				upDirZ = 1.0f;
			else if(upDirZ > 0.8f)
				upDirZ = 1.0f;

			float upPower = upDirZ;
			upPower -= min(1.0f, abs(m_forwardAction) * abs(angles.x));

			float turbulenceMult = 1.0f - min(m_turbulenceMultMax, m_turbulence);
			Vec3 &impulse = m_control.impulse;
			impulse += Vec3(0.0f, 0.0f, upPower) * gravity * turbulenceMult * GetDamageMult();
			impulse.z -= m_PhysDyn.v.z * turbulenceMult;
		}
		else
		{
			m_noHoveringTimer -= deltaTime;
		}
	}

	if(m_pStabilizeVTOL)
	{
		float stabilizeTime = m_pStabilizeVTOL->GetFVal();

		if(stabilizeTime > 0.0f)
		{
			if(m_relaxTimer < 6.0f)
				m_relaxTimer += deltaTime;
			else
			{
				float r = currentRoll - relaxRollTolerance;
				r = min(1.0f, max(-1.0f, r));

				m_actionRoll += -r * m_relaxForce * (m_relaxTimer / 6.0f);
			}

		}
	}

	if(m_netActionSync.PublishActions(CNetworkMovementHelicopter(this)))
		m_pVehicle->GetGameObject()->ChangedNetworkState(eEA_GameClientDynamic);
}
	virtual void ProcessEvent( EFlowEvent event, SActivationInfo *pActInfo )
	{
		switch (event)
		{
		case eFE_Initialize:
			break;
		case eFE_Activate:
			if (IsPortActive(pActInfo, EIP_Trigger))
			{
				const Vec3& dir = GetPortVec3(pActInfo, EIP_LimitDir);
				const bool localSpace = GetPortBool(pActInfo, EIP_LocalSpace);
				const float rangeH = GetPortFloat(pActInfo, EIP_LimitYaw);
				const float rangeV = GetPortFloat(pActInfo, EIP_LimitPitch);
				CActor *pPlayerActor = static_cast<CActor *>(gEnv->pGame->GetIGameFramework()->GetClientActor());
				if (pPlayerActor)
				{
					CPlayer::SStagingParams stagingParams;
					CPlayer* pPlayer = static_cast<CPlayer*> (pPlayerActor);
					if (dir.len2()>0.01f)
					{
						if (localSpace)
						{
							const Quat& viewQuat = pPlayer->GetViewQuatFinal(); // WC
							Vec3 dirWC = viewQuat * dir;
							stagingParams.vLimitDir = dirWC.GetNormalizedSafe(ZERO);
						}
						else
							stagingParams.vLimitDir = dir.GetNormalizedSafe(ZERO);
					}

					stagingParams.vLimitRangeH = DEG2RAD(rangeH);
					stagingParams.vLimitRangeV = DEG2RAD(rangeV);
					stagingParams.bLocked = GetPortBool(pActInfo, EIP_Lock);
					int stance = GetPortInt(pActInfo, EIP_Stance);
					if (stance < STANCE_NULL || stance >= STANCE_LAST)
					{
						stance = STANCE_NULL;
						GameWarning("[flow] PlayerStaging: stance=%d invalid", stance);
					}
					stagingParams.stance = (EStance) stance;

					bool bActive = (stagingParams.bLocked ||
						(!stagingParams.vLimitDir.IsZero() && 
						!iszero(stagingParams.vLimitRangeH) && 
						!iszero(stagingParams.vLimitRangeV)) );
					pPlayer->StagePlayer(bActive, &stagingParams);

					/*
					SActorParams* pActorParams = pPlayerActor->GetActorParams();
					if (pActorParams)
					{
						CPlayer* pPlayer = static_cast<CPlayer*> (pPlayerActor);
						if (dir.len2()>0.01f)
						{
							if (localSpace)
							{
								const Quat& viewQuat = pPlayer->GetViewQuatFinal(); // WC
								Vec3 dirWC = viewQuat * dir;
								pActorParams->vLimitDir = dirWC.GetNormalizedSafe(ZERO);
							}
							else
								pActorParams->vLimitDir = dir.GetNormalizedSafe(ZERO);
						}
						else 
							pActorParams->vLimitDir.zero();

						pActorParams->vLimitRangeH = DEG2RAD(rangeH);
						pActorParams->vLimitRangeV = DEG2RAD(rangeV);
						const bool bLock = GetPortBool(pActInfo, EIP_Lock);

						// AlexL 23/01/2007: disable this until we have a working solution to lock player movement (action filter)
						// SPlayerStats* pActorStats = static_cast<SPlayerStats*> (pPlayer->GetActorStats());
						// if (pActorStats)
						//	pActorStats->spectatorMode = bLock ? CActor::eASM_Cutscene : 0;
						IActionMapManager* pAmMgr = g_pGame->GetIGameFramework()->GetIActionMapManager();
						if (pAmMgr)
							pAmMgr->EnableFilter("no_move", bLock);

						if (bLock)
						{
							// CPlayerMovementController* pMC = static_cast<CPlayerMovementController*> (pPlayer->GetMovementController());
							// pMC->Reset();
							if(pPlayer->GetPlayerInput())
								pPlayer->GetPlayerInput()->Reset();
						}
					}
					*/
				}
				ActivateOutput(pActInfo, EOP_Done, false);
			}
			break;
		}
	}
Example #5
0
static void
test_egd_success(void *arg)
{
  int pipefds[2] = {-1,-1};
  struct sockaddr_un sun;
  char dir[128] = "/tmp/otterylite_test_XXXXXX";
  char fname[128] = {0};
  int listener = -1;
  pid_t pid;
  int r, exitstatus=0;
  u8 buf[64];
  unsigned flags;

  (void)arg;


  tt_assert(mkdtemp(dir) != NULL);
  tt_int_op(-1, ==, ottery_egd_socklen);
  tt_int_op(-1, ==, OTTERY_PUBLIC_FN(set_egd_address)((struct sockaddr*)&sun, 16384));

  tt_assert(strlen(dir) < 128 - 32);
  snprintf(fname, sizeof(fname), "%s/fifo", dir);
  tt_int_op(strlen(fname), <, sizeof(sun.sun_path));

  tt_int_op(-2, ==, ottery_getentropy_egd(buf, &flags)); /* not turned on. */

  memset(&sun, 0, sizeof(sun));
  sun.sun_family = -1; /* Bad family */
  tt_int_op(0, ==, OTTERY_PUBLIC_FN(set_egd_address)((struct sockaddr*)&sun, sizeof(sun)));
  tt_int_op(-1, ==, ottery_getentropy_egd(buf, &flags)); /* bad family */

  sun.sun_family = AF_UNIX;
  memcpy(sun.sun_path, fname, strlen(fname)+1);
  listener = socket(AF_UNIX, SOCK_STREAM, 0);
  tt_int_op(listener, >=, 0);

  tt_int_op(0, ==, pipe(pipefds));

  tt_int_op(0, ==, OTTERY_PUBLIC_FN(set_egd_address)((struct sockaddr*)&sun, sizeof(sun)));

  tt_int_op(sizeof(sun), ==, ottery_egd_socklen);

  tt_int_op(-1, ==, ottery_getentropy_egd(buf, &flags)); /* nobody listening yet */

  tt_int_op(bind(listener, (struct sockaddr*)&sun, sizeof(sun)), ==, 0);
  tt_int_op(listen(listener, 16), ==, 0);

  if ((pid = fork())) {
    /* parent */
    close(listener);
    close(pipefds[1]);
  } else {
    /* child */
    close(pipefds[0]);
    run_egd_server(listener, pipefds[1]);
    exit(1);
  }

  memset(buf, 0, sizeof(buf));
  r = ottery_getentropy_egd(buf, &flags);
  tt_int_op(r, ==, ENTROPY_CHUNK);
  tt_assert(iszero(buf + ENTROPY_CHUNK, sizeof(buf) - ENTROPY_CHUNK));
  tt_assert(! iszero(buf, ENTROPY_CHUNK));
  tt_mem_op(buf, ==, notsorandom, ENTROPY_CHUNK);

  r = (int)read(pipefds[0], buf, 1);
  tt_int_op(r, ==, 1);
  waitpid(pid, &exitstatus, 0);
  tt_int_op(exitstatus, ==, 0);
  tt_int_op(buf[0], ==, 'Y');

  tt_int_op(0, ==, OTTERY_PUBLIC_FN(set_egd_address)(NULL, 0));
  tt_int_op(-1, ==, ottery_egd_socklen);

 end:
  if (pipefds[0] >= 0)
    close(pipefds[0]);
  if (pipefds[1] >= 1)
    close(pipefds[1]);
  if (*fname)
    unlink(fname);
  rmdir(dir);
}
Example #6
0
void
top_level_eval(void)
{
	save();

	trigmode = 0;

	p1 = symbol(AUTOEXPAND);

	if (iszero(get_binding(p1)))
		expanding = 0;
	else
		expanding = 1;

	p1 = pop();
	push(p1);
	eval();
	p2 = pop();

	// "draw", "for" and "setq" return "nil", there is no result to print

	if (p2 == symbol(NIL)) {
		push(p2);
		restore();
		return;
	}

	// update "last"

	set_binding(symbol(LAST), p2);

	if (!iszero(get_binding(symbol(BAKE)))) {
		push(p2);
		bake();
		p2 = pop();
	}

	// If we evaluated the symbol "i" or "j" and the result was sqrt(-1)

	// then don't do anything.

	// Otherwise if "j" is an imaginary unit then subst.

	// Otherwise if "i" is an imaginary unit then subst.

	if ((p1 == symbol(SYMBOL_I) || p1 == symbol(SYMBOL_J))
	&& isimaginaryunit(p2))
		;
	else if (isimaginaryunit(get_binding(symbol(SYMBOL_J)))) {
		push(p2);
		push(imaginaryunit);
		push_symbol(SYMBOL_J);
		subst();
		p2 = pop();
	} else if (isimaginaryunit(get_binding(symbol(SYMBOL_I)))) {
		push(p2);
		push(imaginaryunit);
		push_symbol(SYMBOL_I);
		subst();
		p2 = pop();
	}

#ifndef LINUX

	// if we evaluated the symbol "a" and got "b" then print "a=b"

	// do not print "a=a"

	if (issymbol(p1) && !iskeyword(p1) && p1 != p2 && test_flag == 0) {
		push_symbol(SETQ);
		push(p1);
		push(p2);
		list(3);
		p2 = pop();
	}
#endif
	push(p2);

	restore();
}
Example #7
0
int main(int argc, char *argv[])
{
	p_mem_t shared_mem, results_mem;
	uint32_t eram_base;
	char results[1024] = { '\0' };
	int device_cols, device_rows, nside;
	p_dev_t dev;
	p_prog_t prog;
	p_team_t team;
	p_coords_t size;
	p_coords_t start = { .row = 0, .col = 0 };

	unsigned int msize;
	float        seed;
	unsigned int addr; //, clocks;
	size_t       sz;
	int          verbose=0;
	double       tdiff[3];
	int          result, retval = 0;

	msize     = 0x00400000;

	get_args(argc, argv);

	fo = stderr;
	fi = stdin;
	printf( "------------------------------------------------------------\n");
	printf( "Calculating:   C[%d][%d] = A[%d][%d] * B[%d][%d]\n", _Smtx, _Smtx, _Smtx, _Smtx, _Smtx, _Smtx);
	seed = 0.0;
	if(verbose){
	  printf( "Seed = %f\n", seed);
	}

	dev = p_init(P_DEV_EPIPHANY, 0);
	if (p_error(dev)) {
		fprintf(stderr, "Error initializing PAL\n");
		return p_error(dev);
	}

	device_cols = p_query(dev, P_PROP_COLS);
	device_rows = p_query(dev, P_PROP_ROWS);

	// Use min size
	nside = device_cols > device_rows ? device_cols : device_rows;

	if (nside < 4) {
		fprintf(stderr, "Error: Too small device, need at least 4x4\n");
		return 1;
	}

	// Either 1024, 256, 64, or 16 cores (side must be power of two),
	nside = nside >= 32 ? 32 : nside >= 16 ? 16 : nside >= 8 ? 8 : 4;

	size.row = nside;
	size.col = nside;
	team = p_open4(dev, P_TOPOLOGY_2D, &start, &size);
	printf("Using team of size %d\n", p_team_size(team));
	if (p_error(team)) {
		fprintf(stderr, "Error opening team\n");
		return p_error(team);
	}

	prog = p_load(dev, ar.elfFile, 0);

	eram_base = (unsigned) p_query(dev, P_PROP_MEMBASE);
	shared_mem = p_map(dev, eram_base, msize);

	// Clear mailbox contents
	memset(&Mailbox, 0, sizeof(Mailbox));
	p_write(&shared_mem, &Mailbox, 0, sizeof(Mailbox), 0);

	// Generate operand matrices based on a provided seed
	matrix_init((int)seed);

#ifdef __WIPE_OUT_RESULT_MATRIX__
	// Wipe-out any previous remains in result matrix (for verification)
	addr = offsetof(shared_buf_t, C[0]);
	sz = sizeof(Mailbox.C);
	if(verbose){
	  printf( "Writing C[%uB] to address %08x...\n", (unsigned) sz, addr);
	}
	p_write(&shared_mem, (void *) Mailbox.C, addr, sz, 0);
#endif

	/* Wallclock time */
	clock_gettime(CLOCK_MONOTONIC, &timer[0]);
	/* Clock CPUTIME too. We don't want to indicate failure just
	 * because the system was under high load. */
	clock_gettime(CLOCK_THREAD_CPUTIME_ID, &timer[4]);

	// Copy operand matrices to Epiphany system
	addr = offsetof(shared_buf_t, A[0]);
	sz = sizeof(Mailbox.A);
	if(verbose){
	  printf( "Writing A[%uB] to address %08x...\n", (unsigned) sz, addr);
	}
	p_write(&shared_mem, (void *) Mailbox.A, addr, sz, 0);

	addr = offsetof(shared_buf_t, B[0]);
	sz = sizeof(Mailbox.B);
	if(verbose){
	  printf( "Writing B[%uB] to address %08x...\n", (unsigned) sz, addr);
	}
	p_write(&shared_mem, (void *) Mailbox.B, addr, sz, 0);
	// Call the Epiphany matmul() function

	if(verbose){
	  printf( "GO Epiphany! ...   ");
	}
	if(verbose){
	  printf("Loading program on Epiphany chip...\n");
	}

	p_arg_t args[] = { &nside, sizeof(nside), true };
	if (p_run(prog, "matmul", team, 0, p_team_size(team), 1, args, 0)) {
		fprintf(stderr, "Error loading Epiphany program.\n");
		exit(1);
	}

	// Read result matrix and timing
	addr = offsetof(shared_buf_t, C[0]);
	sz = sizeof(Mailbox.C);
	if(verbose){
	  printf( "Reading result from address %08x...\n", addr);
	}
	p_read(&shared_mem, (void *) Mailbox.C, addr, sz, 0);

	clock_gettime(CLOCK_MONOTONIC, &timer[1]);
	clock_gettime(CLOCK_THREAD_CPUTIME_ID, &timer[5]);


	// Calculate a reference result
	clock_gettime(CLOCK_THREAD_CPUTIME_ID, &timer[2]);
#ifndef __DO_STRASSEN__
	matmul(Mailbox.A, Mailbox.B, Cref, _Smtx);
#else
	matmul_strassen(Mailbox.A, Mailbox.B, Cref, _Smtx);
#endif
	clock_gettime(CLOCK_THREAD_CPUTIME_ID, &timer[3]);
	addr = offsetof(shared_buf_t, core.clocks);
	sz = sizeof(Mailbox.core.clocks);
	if(verbose){
	  printf( "Reading time from address %08x...\n", addr);
	}
	p_read(&shared_mem, &Mailbox.core.clocks, addr, sizeof(Mailbox.core.clocks), 0);
//	clocks = Mailbox.core.clocks;





	// Calculate the difference between the Epiphany result and the reference result
	matsub(Mailbox.C, Cref, Cdiff, _Smtx);

	tdiff[0] = (timer[1].tv_sec - timer[0].tv_sec) * 1000 + ((double) (timer[1].tv_nsec - timer[0].tv_nsec) / 1000000.0);
//	tdiff[0] = ((double) clocks) / eMHz * 1000;
	tdiff[1] = (timer[3].tv_sec - timer[2].tv_sec) * 1000 + ((double) (timer[3].tv_nsec - timer[2].tv_nsec) / 1000000.0);
	tdiff[2] = (timer[5].tv_sec - timer[4].tv_sec) * 1000 + ((double) (timer[5].tv_nsec - timer[4].tv_nsec) / 1000000.0);


	// If the difference is 0, then the matrices are identical and the
	// calculation was correct
	if (iszero(Cdiff, _Smtx))
	  {

	    printf( "Epiphany(time) %9.1f msec  (@ %03d MHz)\n", tdiff[0], eMHz);
	    printf( "Host(time)     %9.1f msec  (@ %03d MHz)\n", tdiff[1], aMHz);
	    printf( "------------------------------------------------------------\n");
	    printf( "TEST \"matmul-16\" PASSED\n");
	    retval = 0;
	} else {
	  printf( "\n\nERROR: C_epiphany is different from C_host !!!\n");
	  printf( "TEST \"matmul-16\" FAILED\n");
	  retval = 1;
	}

#if 0
#ifdef __DUMP_MATRICES__
	printf( "\n\n\n");
	printf( "A[][] = \n");
	matprt(Mailbox.A, _Smtx);
	printf( "B[][] = \n");
	matprt(Mailbox.B, _Smtx);
	printf( "C[][] = \n");
	matprt(Mailbox.C, _Smtx);
	printf( "Cref[][] = \n");
	matprt(Cref, _Smtx);

	int i, j;
	for (i=0; i<_Nside; i++)
		for (j=0; j<_Nside; j++)
		{
			e_read(pEpiphany, i, j, 0x2000+0*sizeof(float), &Aepi[(i*_Score+0)*_Smtx + j*_Score], 2*sizeof(float));
			e_read(pEpiphany, i, j, 0x2000+2*sizeof(float), &Aepi[(i*_Score+1)*_Smtx + j*_Score], 2*sizeof(float));
			e_read(pEpiphany, i, j, 0x4000+0*sizeof(float), &Bepi[(i*_Score+0)*_Smtx + j*_Score], 2*sizeof(float));
			e_read(pEpiphany, i, j, 0x4000+2*sizeof(float), &Bepi[(i*_Score+1)*_Smtx + j*_Score], 2*sizeof(float));
		}
	printf( "Aepi[][] = \n");
	matprt(Aepi, _Smtx);
	printf( "Bepi[][] = \n");
	matprt(Bepi, _Smtx);
#endif
#endif



	// p_unmap ...
	p_close(team);
	p_finalize(dev);

	return retval;
}


// Initialize operand matrices
void matrix_init(int seed)
{
	int i, j, p;

	p = 0;
	for (i=0; i<_Smtx; i++)
		for (j=0; j<_Smtx; j++)
			Mailbox.A[p++] = (i + j + seed) % _MAX_MEMBER_;

	p = 0;
	for (i=0; i<_Smtx; i++)
		for (j=0; j<_Smtx; j++)
			Mailbox.B[p++] = ((i + j) * 2 + seed) % _MAX_MEMBER_;

	p = 0;
	for (i=0; i<_Smtx; i++)
		for (j=0; j<_Smtx; j++)
			Mailbox.C[p++] = 0x8dead;

	return;
}