void AutoNavigator::recalculateParameters()
{
	// GameObject values
	f32 maa = environment()->getGoValue<f32>
	(
		ownerHandle(),
		ID::PV_MaxAngularAcceleration,
		pluginId()
	);

	mMaxAngularAcceleration = maa * radian_per_second_squared;

	f32 ms = environment()->getGoValue<f32>
	(
		ownerHandle(),
		ID::PV_MaxSpeed,
		pluginId()
	);
	
	mMaxSpeed = ms * si::meters_per_second;

	// Module values
	ModuleMapT::iterator it = mModules.begin();
	for (; it != mModules.end(); ++it)
	{
		mRadius = value<f32>(ID::PV_TriggerRadius, it->first) * si::meter;
	}
}
void WeaponRack::updateGuiAmmo() const
{
	emit<GameObjectEvent>
	(
		ID::GOE_ROCKET_AMMO,
		mRocketAmmo,
		0,
		ownerHandle()
	);
}
AutoNavigator::AutoNavigator(GameObject& owner, PluginId pid) :
Property::Concept(owner, "AutoNavigator", pid)
{
	initvar(ID::PV_TriggerRadius);

	require("ThrustControl");
	require("Physical");

	requestEvent(ID::GOE_VALUE_UPDATED);
	requestEvent(ID::GOE_AUTONAVIGATE);

	assert(ownerHandle() == rootModule() &&
		"AutoNavigator: This code may contain some out-dated assumptions.");
}
void AutoNavigator::accelerate(quantity<si::velocity, f32> targetSpeed) const
{
	quantity<si::dimensionless, f32> factor =
	(
		targetSpeed / mMaxSpeed
	);

	emit<GameObjectEvent>
	(
		ID::GOE_CONTROL_THRUST,
		factor,
		ownerHandle()
	);
}
Destroyable::Destroyable(GameObject& owner, PluginId pid) :
Property::Concept(owner, "Destroyable", pid),
mDamageMultiplier(100.0f)
{
	requiredPvInitialized(ID::PV_Destroyed);
	requiredPvInitialized(ID::PV_Respawns);
	requiredPvInitialized(ID::PV_Armor);
	requiredPvInitialized(ID::PV_Damage);
	requiredPvInitialized(ID::PV_RespawnCountdown);
	requiredPvInitialized(ID::PV_Effect);

	subLane()->connect(ID::PE_CONTACT, this, &Destroyable::onContact, ownerHandle());
	//subLane()->connectV(ID::GOE_REINITIALIZE, this, &Destroyable::onReinitialize, ownerHandle());
	
	require("Physical");
}
void AutoNavigator::rotate(const qv4& rotation) const
{
	const v3& currentRotationVel = getGoValue<v3>(ID::PV_RelativeRotationVelocity, pluginId());

	// braking distance in radian
	v3 b = (currentRotationVel * currentRotationVel) / (2.0f * mMaxAngularAcceleration.value());

	// reduce the vibration caused by the time delay of 2 frames by using the braking distance * 3 
	b *= 2.0f;

	quantity<si::plane_angle,f32> pitch = rotation.getPitch(false) * si::radian;
	quantity<si::plane_angle,f32> yaw = rotation.getYaw(false) * si::radian;

	// get the sign
	f32 factor = sign(pitch.value());

	if ((factor * pitch) > (b.x * si::radian))
	{
		if ((factor * pitch) > mOptimalAngle)
			emit<GameObjectEvent>(ID::GOE_CONTROL_PITCH, 1.0f * factor, ownerHandle());
		else
			emit<GameObjectEvent>(ID::GOE_CONTROL_PITCH, 0.05f * factor, ownerHandle());
	}
	else
	{
		emit<GameObjectEvent>(ID::GOE_CONTROL_PITCH, 0.0f, ownerHandle());
	}

	// get the sign
	factor = sign(yaw.value());

	if ((factor * yaw) > (b.y * si::radian))
	{
		if ((factor * yaw) > mOptimalAngle)
			emit<GameObjectEvent>(ID::GOE_CONTROL_YAW, 1.0f * factor, ownerHandle());
		else
			emit<GameObjectEvent>(ID::GOE_CONTROL_YAW, 0.05f * factor, ownerHandle());
	}
	else
		emit<GameObjectEvent>(ID::GOE_CONTROL_YAW, 0.0f, ownerHandle());
}
void AutoNavigator::internalSynchronize()
{
	emit<GameObjectEvent>(ID::GOE_CONTROL_PITCH, mRotationFactorPitch, ownerHandle());
	emit<GameObjectEvent>(ID::GOE_CONTROL_YAW, mRotationFactorYaw, ownerHandle());
	emit<GameObjectEvent>(ID::GOE_CONTROL_THRUST,mAccelerationFactor, ownerHandle());
}