//------------------------------------------------------------------------
bool CVehicleMovementVTOL::Init(IVehicle *pVehicle, const CVehicleParams &table)
{
	if (!CVehicleMovementHelicopter::Init(pVehicle, table))
	{
		return false;
	}

	MOVEMENT_VALUE("horizFwdForce", m_horizFwdForce);
	MOVEMENT_VALUE("horizLeftForce", m_horizLeftForce);
	MOVEMENT_VALUE("boostForce", m_boostForce);
	MOVEMENT_VALUE("strafeForce", m_strafeForce);
	MOVEMENT_VALUE("angleLift", m_angleLift);
	m_playerDampingBase = 0.15f;
	m_playerDampingRotation = 0.3f;
	m_playerDimLowInput = 0.01f;
	m_playerRotationMult.x = 55.0f;
	m_playerRotationMult.y = 40.0f;
	m_playerRotationMult.z = 0.0f;
	m_maxFwdSpeedHorizMode = m_maxFwdSpeed;
	m_maxUpSpeedHorizMode = m_maxUpSpeed;
	m_pWingsAnimation = NULL;
	m_wingHorizontalStateId = InvalidVehicleAnimStateId;
	m_wingVerticalStateId = InvalidVehicleAnimStateId;

	if (!table.getAttr("timeUntilWingsRotate", m_timeUntilWingsRotate))
	{
		m_timeUntilWingsRotate = 0.65f;
	}

	m_engineUpDir.Set(0.0f, 0.0f, 1.0f);

	if (!table.getAttr("wingsSpeed", m_wingsSpeed))
	{
		m_wingsSpeed = 1.0f;
	}

	m_playerDampingBase *= 3.0f;
	m_fwdPID.Reset();
	m_fwdPID.m_kP = 0.66f;
	m_fwdPID.m_kD = 0.2f;
	m_fwdPID.m_kI = 0.0f;
	m_relaxForce = 0.50f;
	m_relaxPitchTime = 0.0f;
	m_relaxRollTime = 0.0f;
	m_playerControls.RegisterValue(&m_forwardAction, false, 0.0f, "forward");
	m_playerControls.RegisterAction(eVAI_MoveForward, CHelicopterPlayerControls::eVM_Positive, &m_forwardAction);
	m_playerControls.RegisterAction(eVAI_MoveBack, CHelicopterPlayerControls::eVM_Negative, &m_forwardAction);
	m_playerControls.RegisterValue(&m_strafeAction, false, 0.0f, "strafe");
	m_playerControls.RegisterAction(eVAI_StrafeLeft, CHelicopterPlayerControls::eVM_Negative, &m_strafeAction);
	m_playerControls.RegisterAction(eVAI_StrafeRight, CHelicopterPlayerControls::eVM_Positive, &m_strafeAction);
	m_playerControls.SetActionMult(eVAI_RotateYaw, m_maxYawRate * 0.4f);
	m_playerControls.SetActionMult(eVAI_RotatePitch, m_maxYawRate * 0.4f);
	m_pStabilizeVTOL = gEnv->pConsole->GetCVar("v_stabilizeVTOL");
	m_maxSpeed = 75.0f;
	return true;
}
//------------------------------------------------------------------------
bool CVehicleMovementTank::Init(IVehicle* pVehicle, const CVehicleParams& table)
{
	if (!CVehicleMovementStdWheeled::Init(pVehicle, table))
		return false;

	MOVEMENT_VALUE("pedalSpeed", m_pedalSpeed);
	MOVEMENT_VALUE_OPT("pedalThreshold", m_pedalThreshold, table);
	MOVEMENT_VALUE("steerSpeed", m_steerSpeed);
	MOVEMENT_VALUE_OPT("steerSpeedRelax", m_steerSpeedRelax, table);
	MOVEMENT_VALUE_OPT("steerLimit", m_steerLimit, table);  
	MOVEMENT_VALUE("latFricMin", m_latFricMin);
	MOVEMENT_VALUE("latFricMinSteer", m_latFricMinSteer);
	MOVEMENT_VALUE("latFricMax", m_latFricMax);  
	MOVEMENT_VALUE("latSlipMin", m_latSlipMin);
	MOVEMENT_VALUE("latSlipMax", m_latSlipMax);

	MOVEMENT_VALUE_OPT("steeringImpulseMin", m_steeringImpulseMin, table);
	MOVEMENT_VALUE_OPT("steeringImpulseMax", m_steeringImpulseMax, table);
	MOVEMENT_VALUE_OPT("steeringImpulseRelaxMin", m_steeringImpulseRelaxMin, table);
	MOVEMENT_VALUE_OPT("steeringImpulseRelaxMax", m_steeringImpulseRelaxMax, table);

	m_maxSoundSlipSpeed = 10.f;  


	return true;
}
//------------------------------------------------------------------------
bool CVehicleMovementHelicopter::Init(IVehicle* pVehicle, const CVehicleParams& table)
{
	if (!CVehicleMovementBase::Init(pVehicle, table))
		return false;

	// Initialise the arcade physics, handling helper
	if (CVehicleParams handlingParams = table.findChild("HandlingArcade"))
		if (!m_arcade.Init(pVehicle, handlingParams))
			return false;

	MOVEMENT_VALUE("engineWarmupDelay", m_engineWarmupDelay);
	MOVEMENT_VALUE("enginePowerMax", m_enginePowerMax);
	MOVEMENT_VALUE("yawPerRoll", m_yawPerRoll);
	MOVEMENT_VALUE("maxSpeed", m_maxSpeed);
	MOVEMENT_VALUE("maxPitchAngle", m_maxPitchAngle);
	MOVEMENT_VALUE("maxRollAngle", m_maxRollAngle);
	MOVEMENT_VALUE("rollDamping", m_rollDamping);

	if(table.haveAttr("extendMoveTarget"))
	{
		table.getAttr("extendMoveTarget", m_bExtendMoveTarget);
	}
	table.getAttr("applyNoiseAsVelocity", m_bApplyNoiseAsVelocity);

	if(CVehicleParams noiseParams = table.findChild("MovementNoise"))
	{
		InitMovementNoise(noiseParams, m_defaultNoise);
	}

	// high-level controller
	Ang3 angles				= m_pEntity->GetWorldAngles();
	m_enginePower			= 0.0f;

	if (table.haveAttr("rotorPartName"))
		m_pRotorPart = m_pVehicle->GetPart(table.getAttr("rotorPartName"));

	m_isEngineGoingOff = true;
	m_isEnginePowered = false;

	ResetActions();

	m_pVehicle->GetGameObject()->EnableUpdateSlot(m_pVehicle, IVehicle::eVUS_EnginePowered);

	return true;
}
//------------------------------------------------------------------------
bool CVehicleMovementHelicopter::Init(IVehicle *pVehicle, const CVehicleParams &table)
{
	if(!CVehicleMovementBase::Init(pVehicle, table))
		assert(0);

	MOVEMENT_VALUE("engineWarmupDelay", m_engineWarmupDelay);

	// heli abilities
	MOVEMENT_VALUE("altitudeMax", m_altitudeMax);
	MOVEMENT_VALUE("rotorDiskTiltScale", m_rotorDiskTiltScale);
	MOVEMENT_VALUE("pitchResponsiveness", m_pitchResponsiveness);
	MOVEMENT_VALUE("rollResponsiveness", m_rollResponsiveness);
	MOVEMENT_VALUE("yawResponsiveness", m_yawResponsiveness);
	MOVEMENT_VALUE("enginePowerMax", m_enginePowerMax);
	MOVEMENT_VALUE("rotationDamping", m_rotationDamping);
	MOVEMENT_VALUE("yawPerRoll", m_yawPerRoll);

	// high-level controller abilities
	MOVEMENT_VALUE("maxYawRate", m_maxYawRate);
	MOVEMENT_VALUE("maxFwdSpeed", m_maxFwdSpeed);
	MOVEMENT_VALUE("maxLeftSpeed", m_maxLeftSpeed);
	MOVEMENT_VALUE("maxUpSpeed", m_maxUpSpeed);
	MOVEMENT_VALUE("basicSpeedFraction", m_basicSpeedFraction);
	MOVEMENT_VALUE("yawDecreaseWithSpeed", m_yawDecreaseWithSpeed);
	MOVEMENT_VALUE("tiltPerVelDifference", m_tiltPerVelDifference);
	MOVEMENT_VALUE("maxTiltAngle", m_maxTiltAngle);
	MOVEMENT_VALUE("extraRollForTurn", m_extraRollForTurn);
	MOVEMENT_VALUE("rollForTurnForce", m_rollForTurnForce);
	MOVEMENT_VALUE("yawPerRoll", m_yawPerRoll);
	MOVEMENT_VALUE("pitchActionPerTilt", m_pitchActionPerTilt);
	MOVEMENT_VALUE("pitchInputConst", m_pitchInputConst);
	MOVEMENT_VALUE("powerInputConst", m_powerInputConst);
	MOVEMENT_VALUE("powerInputDamping", m_powerInputDamping);
	MOVEMENT_VALUE("relaxForce", m_relaxForce);
	MOVEMENT_VALUE("yawInputConst", m_yawInputConst);
	MOVEMENT_VALUE("yawInputDamping", m_yawInputDamping);
	MOVEMENT_VALUE("maxRollAngle", m_maxRollAngle);
	MOVEMENT_VALUE("velDamping", m_velDamp);

	// Initialise the power PID.
	m_powerPID.Reset();
	m_powerPID.m_kP = 0.2f;
	m_powerPID.m_kD = 0.01f;
	m_powerPID.m_kI = 0.0001f;

	m_maxSpeed = 40.f; // empirically determined

	m_liftPID.Reset();
	m_yawPID.Reset();

	m_liftPID.m_kP = 0.66f;
	m_liftPID.m_kD = 0.2f;
	m_liftPID.m_kI = 0.0f;

	m_yawPID.m_kP = -0.03f;
	m_yawPID.m_kI = 0.0f;
	m_yawPID.m_kD = 0.0f;

	// high-level controller
	Ang3 angles = m_pEntity->GetWorldAngles();
	m_desiredDir = angles.z;

	m_desiredHeight = m_pEntity->GetWorldPos().z;
	m_lastDir = m_desiredDir;
	m_enginePower = 0.0f;

	m_isTouchingGround = false;
	m_timeOnTheGround = 50.0f;

	if(table.haveAttr("rotorPartName"))
		m_pRotorPart = m_pVehicle->GetPart(table.getAttr("rotorPartName"));
	else
		m_pRotorPart = NULL;

	m_desiredPitch = 0.0f;

	ResetActions();

	m_playerDampingBase = 0.1f;
	m_playerDampingRotation = 0.15f;
	m_playerDimLowInput = 0.25f;

	m_playerRotationMult.x = 60.0f;
	m_playerRotationMult.y = 60.0f;
	m_playerRotationMult.z = 10.0f;

	m_strafeForce = 1.0f;

	m_engineUpDir.Set(0.0f, 0.0f, 1.0f);

	m_boostMult = 2.00f;

	ICVar *pSensitivVar = gEnv->pConsole->GetCVar("cl_sensitivity");

	m_playerControls.RegisterValue(&m_liftAction, false, 0.0f, "lift");
	m_playerControls.RegisterAction(eVAI_MoveUp, CHelicopterPlayerControls::eVM_Positive, &m_liftAction);
	m_playerControls.RegisterAction(eVAI_MoveDown, CHelicopterPlayerControls::eVM_Negative, &m_liftAction);

	m_playerControls.RegisterValue(&m_turnAction, false, 0.0f, "roll");
	m_playerControls.RegisterAction(eVAI_TurnLeft, CHelicopterPlayerControls::eVM_Negative, &m_turnAction);
	m_playerControls.RegisterAction(eVAI_TurnRight, CHelicopterPlayerControls::eVM_Positive, &m_turnAction);
	m_playerControls.RegisterAction(eVAI_RotateYaw, CHelicopterPlayerControls::eVM_Positive, &m_turnAction, pSensitivVar);
	m_playerControls.SetActionMult(eVAI_RotateYaw, m_maxYawRate * 0.65f);

	m_playerControls.RegisterValue(&m_desiredRoll, false, gf_PI * 4.0f, "turn");
	m_playerControls.RegisterAction(eVAI_RollLeft, CHelicopterPlayerControls::eVM_Negative, &m_desiredRoll);
	m_playerControls.RegisterAction(eVAI_RollRight, CHelicopterPlayerControls::eVM_Positive, &m_desiredRoll);
	m_playerControls.RegisterAction(eVAI_RotateRoll, CHelicopterPlayerControls::eVM_Positive, &m_desiredRoll, pSensitivVar);

	m_playerControls.RegisterValue(&m_desiredPitch, false, 0.0f, "pitch");
	m_playerControls.RegisterAction(eVAI_RotatePitch, CHelicopterPlayerControls::eVM_Negative, &m_desiredPitch, pSensitivVar);
	m_playerControls.SetActionMult(eVAI_RotatePitch, m_maxYawRate * 0.65f);

	m_pInvertPitchVar = gEnv->pConsole->GetCVar("v_invertPitchControl");
	m_pAltitudeLimitVar = gEnv->pConsole->GetCVar("v_altitudeLimit");
	m_pAltitudeLimitLowerOffsetVar = gEnv->pConsole->GetCVar("v_altitudeLimitLowerOffset");
	m_pStabilizeVTOL = gEnv->pConsole->GetCVar("v_stabilizeVTOL");

	m_turbulenceMultMax = 0.25f;

	return true;
}
//------------------------------------------------------------------------
bool CVehicleMovementStdBoat::Init(IVehicle* pVehicle, const CVehicleParams& table)
{
  if (!CVehicleMovementBase::Init(pVehicle, table))
    return false;
  
  MOVEMENT_VALUE("velMax", m_velMax);      
  MOVEMENT_VALUE("velMaxReverse", m_velMaxReverse);
  MOVEMENT_VALUE("acceleration", m_accel);      
  MOVEMENT_VALUE("accelerationVelMax", m_accelVelMax);      
  MOVEMENT_VALUE("accelerationMultiplier", m_accelCoeff);         
  MOVEMENT_VALUE("pushTilt", m_pushTilt);     
  MOVEMENT_VALUE("turnRateMax", m_turnRateMax);
  MOVEMENT_VALUE("turnAccel", m_turnAccel);      
  MOVEMENT_VALUE("cornerForce", m_cornerForceCoeff);      
  MOVEMENT_VALUE("cornerTilt", m_cornerTilt);    
  MOVEMENT_VALUE("turnDamping", m_turnDamping); 
  MOVEMENT_VALUE("turnAccelMultiplier", m_turnAccelCoeff);
  MOVEMENT_VALUE_OPT("rollAccel", m_rollAccel, table);
  MOVEMENT_VALUE_OPT("pedalLimitReverse", m_pedalLimitReverse, table);
  MOVEMENT_VALUE_OPT("turnVelocityMult", m_turnVelocityMult, table);
  MOVEMENT_VALUE_OPT("velLift", m_velLift, table);
  MOVEMENT_VALUE_OPT("lateralDamping", m_lateralDamping, table);
  
  table.getAttr("waveIdleStrength", m_waveIdleStrength);
  table.getAttr("waveSpeedMult", m_waveSpeedMult);
  
  if (table.haveAttr("cornerHelper"))
	{
		if (IVehicleHelper* pHelper = m_pVehicle->GetHelper(table.getAttr("cornerHelper")))
			m_cornerOffset = pHelper->GetVehicleSpaceTranslation();
	}

  if (table.haveAttr("pushHelper"))
	{
		if (IVehicleHelper* pHelper = m_pVehicle->GetHelper(table.getAttr("pushHelper")))
			m_pushOffset = pHelper->GetVehicleSpaceTranslation();
	}

  // compute inertia [assumes box]
  AABB bbox;	
  
  IVehiclePart* pMassPart = pVehicle->GetPart("mass");
  if (!pMassPart)
    pMassPart = pVehicle->GetPart("massBox");
	
  if (pMassPart)
	{
		bbox = pMassPart->GetLocalBounds();
	}
	else
	{
		GameWarning("[CVehicleMovementStdBoat]: initialization: No \"mass\" geometry found!");
		m_pEntity->GetLocalBounds(bbox);
	}

  m_maxSpeed = m_velMax;
	float mass = pVehicle->GetMass();
  
  float width = bbox.max.x - bbox.min.x;
  float length = bbox.max.y - bbox.min.y;
  float height = bbox.max.z - bbox.min.z;
  m_Inertia.x = mass * (sqr(length)+ sqr(height)) / 12;
  m_Inertia.y = mass * (sqr(width) + sqr(height)) / 12;
  m_Inertia.z = mass * (sqr(width) + sqr(length)) / 12;
  
  m_massOffset = bbox.GetCenter();

  //CryLog("[StdBoat movement]: got mass offset (%f, %f, %f)", m_massOffset.x, m_massOffset.y, m_massOffset.z);

	m_pSplashPos = m_pVehicle->GetHelper("splashPos");

	if (m_pSplashPos)
		m_lastWakePos = m_pSplashPos->GetWorldSpaceTranslation();
	else
		m_lastWakePos = m_pVehicle->GetEntity()->GetWorldTM().GetTranslation();

	const char* waveEffect = "";
	MOVEMENT_VALUE_OPT("waveEffect", &waveEffect, table);
	m_pWaveEffect = gEnv->pParticleManager->FindEffect(waveEffect, "MovementStdBoat");

  m_waveTimer = cry_random(0.0f, gf_PI);
  m_diving = false;
  m_wakeSlot = -1;   
  m_waveSoundPitch = 0.f;
  m_rpmPitchDir = 0;
  m_waveSoundAmount = 0.1f;

  // AI related
  m_prevAngle = 0.0f;
  
	m_factorMaxSpeed = 1.f;
	m_factorAccel = 1.f;

  return true;
}
bool CVehicleMovementMPVTOL::Init(IVehicle* pVehicle, const CVehicleParams& table)
{
    bool success = BaseClass::Init(pVehicle, table);

    //ToDo: Any VTOL animations/effects setup
    MOVEMENT_VALUE("rollSpeedMultiplier", m_rollSpeedMultiplier);

    // Control what needs to be network synced
    int vtolmanagerControlled = 0;
    table.getAttr("vtolmanagerControlled", vtolmanagerControlled);
    if (vtolmanagerControlled && g_pGame->GetGameRules()->GetVTOLVehicleManager())
    {
        // No need to do low level physics synchronisation
        m_pVehicle->GetGameObject()->DontSyncPhysics();
        // Disable some of the additional network serialisation
        // Disable all pos, rot serialization. All Network syncing is done via catchup along the path, handled by the manager.
        // The only data sent is the pathId, and the distance along the path (pathLoc)
        //m_netActionSync.m_actionRep.SetFlags(CNetworkMovementHelicopterCrysis2::k_syncPos|CNetworkMovementHelicopterCrysis2::k_controlPos);
        m_sendTime = g_pGameCVars->v_MPVTOLNetworkSyncFreq;
        m_updateAspects |= k_vtolPathUpdate;
    }

    if(CVehicleParams stutterParams = table.findChild("EngineStuttering"))
    {
        stutterParams.getAttr("stutterStartDamageRatio", m_stutterStartDamageRatio);
        if(m_stutterStartDamageRatio == 1.f)
        {
            GameWarning("CVehicleMovementMPVTOL::Init: stutterStartDamageRatio XML param == 1.0f. Will cause divide by 0 error in release.");
            m_stutterStartDamageRatio = 0.f;
        }
        m_invStutterDamageSpread = __fres(1.f - m_stutterStartDamageRatio);
        stutterParams.getAttr("minStutters", m_baseStutters);
        stutterParams.getAttr("maxStutters", m_maxExtraStutters);
        m_maxExtraStutters -= m_baseStutters;
        stutterParams.getAttr("minTimeBetweenStutters", m_minTimeBetweenStutters);
        stutterParams.getAttr("maxTimeBetweenStutters", m_maxTimeBetweenStutters);
        stutterParams.getAttr("timeBetweenStutterDecayMult", m_timeBetweenStutterDecayMult);
        stutterParams.getAttr("stutterDurationOn", m_stutterDurationOn);
        stutterParams.getAttr("stutterDurationOff", m_stutterDurationOff);
    }

    if(CVehicleParams wingRotationParams = table.findChild("WingRotation"))
    {
        float maxAngleDeg;
        if(wingRotationParams.getAttr("maxAngleDeg", maxAngleDeg))
        {
            m_maxAngleRad = DEG2RAD(maxAngleDeg);
        }
        wingRotationParams.getAttr("canReachMaxAngleAtSpeed", m_maxAngleSpeed);
        CRY_ASSERT_MESSAGE(m_maxAngleSpeed, "CVehicleMovementMPVTOL::Init - canReachMaxAngleAtSpeed is 0. This will result in divide by 0 error during update.");
        wingRotationParams.getAttr("angleAngularVelMult", m_angularVelMult);
        wingRotationParams.getAttr("smoothTime", m_angleSmoothTime);
        wingRotationParams.getAttr("insideWingSpeedMult", m_insideWingSpeedMult);
        wingRotationParams.getAttr("insideWingMaxAngleMult", m_insideWingMaxAngleMult);

        float noiseAmp = 0.f;
        float noiseFreq = 0.f;
        wingRotationParams.getAttr("noiseAmplitude", noiseAmp);
        wingRotationParams.getAttr("noiseFrequency", noiseFreq);

        m_leftWingNoise.Setup(noiseAmp, noiseFreq, 0x473845);
        m_rightWingNoise.Setup(noiseAmp, noiseFreq, 0x287463);
    }

    if(CVehicleParams noiseOverrideParams = table.findChild("NoiseOverrides"))
    {
        int count = noiseOverrideParams.getChildCount();
        for(int i = 0; i < count; ++i)
        {
            if(i == MAX_NOISE_OVERRIDES)
            {
                GameWarning("CVehicleMovementMPVTOL::Init - %i noise overrides specified in XML but only %i currently supported. Needs code change to support more.", count, MAX_NOISE_OVERRIDES);
                break;
            }

            InitMovementNoise(noiseOverrideParams.getChild(i), m_noiseOverrides[i]);
        }
    }

    pVehicle->RegisterVehicleEventListener(this, "CVehicleMovementMPVTOL");

    return success;
}