Vector3 UnitAiMoonGuard::chargeAtTarget(const WorldInterface& world, const PhysicsObjectId& target, const Vector3& orig_velocity)
{
    if (!world.isAlive(target))
    {
        return orig_velocity;
    }

    Vector3 unit_pos = getShip().getPosition();
    Vector3 target_pos = world.getPosition(target);
    Vector3 target_forward = world.getForward(target);


    //Vector3 desired_velocity = steeringBehaviour->seek(world, target);
    Vector3 desired_velocity = steeringBehaviour->aim(world, target, Bullet::SPEED);
    //Vector3 desired_velocity = steeringBehaviour->escort(world, target, -target_forward * 50);
    Vector3 v = avoidPlanetoids(world, desired_velocity);

    //printf("\tRamming\n");
    return v;
}
Vector3 SteeringBehaviour :: calculateEscortPosition (const WorldInterface& world,
                                                      const PhysicsObjectId& id_target,
                                                      const Vector3& offset) const
{
	assert(m_steering_behaviour == ESCORT);
	assert(id_target != PhysicsObjectId::ID_NOTHING);

	if(!world.isAlive(id_target))
		return Vector3::ZERO;

	Vector3 target_position = world.getPosition(id_target);
	Vector3 target_forward  = world.getForward (id_target);
	Vector3 target_up       = world.getUp      (id_target);
	Vector3 target_right    = world.getRight   (id_target);

	return target_position +
	       target_forward * offset.x +
	       target_up      * offset.y +
	       target_right   * offset.z;
}
// avoid only when going to collide
Vector3 SteeringBehaviour :: avoid (const WorldInterface& world,
                                    const Vector3& original_velocity,
                                    const Vector3& sphere_center,
                                    double sphere_radius,
                                    double clearance,
                                    double avoid_distance) const
{
	assert(sphere_radius >= 0.0);
	assert(clearance > 0.0);
	assert(clearance <= avoid_distance);

	if(!world.isAlive(m_id_agent) ||
	   original_velocity.isZero())
	{
		assert(invariant());
		return Vector3::ZERO;
	}

	Vector3 agent_position    = world.getPosition(m_id_agent);
	double  agent_radius      = world.getRadius(m_id_agent);
	double  desired_speed     = world.getShipSpeedMax(m_id_agent);
	Vector3 relative_position = sphere_center - agent_position;
	double  radius_sum        = sphere_radius + agent_radius;

	if(relative_position.isNormGreaterThan(radius_sum + avoid_distance))
	{
		if(DEBUGGING_AVOID)
			cout << "Avoid: Outside avoid distance" << endl;
		assert(invariant());
		return original_velocity.getTruncated(desired_speed);  // too far away to worry about
	}

	Vector3 agent_forward = world.getForward(m_id_agent);

	if(relative_position.dotProduct(agent_forward) < 0.0)
	{
		// past center of object; no cylinder
		if(DEBUGGING_AVOID)
			cout << "Avoid: Departing from object" << endl;

		if(relative_position.isNormLessThan(radius_sum + clearance))
		{
			// we are too close, so flee and slow down

			double distance_fraction = (relative_position.getNorm() - radius_sum) / clearance;
			if(DEBUGGING_AVOID)
				cout << "\tInside panic distance: fraction = " << distance_fraction << endl;
			if(distance_fraction < 0.0)
				distance_fraction = 0.0;

			Vector3 interpolated =  original_velocity.getNormalized() *        distance_fraction +
			                       -relative_position.getNormalized() * (1.0 - distance_fraction);

			if(distance_fraction > AVOID_SPEED_FACTOR_MIN)
				desired_speed *= distance_fraction;
			else
				desired_speed *= AVOID_SPEED_FACTOR_MIN;

			if(original_velocity.isNormLessThan(desired_speed))
				desired_speed = original_velocity.getNorm();

			assert(invariant());
			return interpolated.getCopyWithNorm(desired_speed);
		}
		else
		{
			if(DEBUGGING_AVOID)
				cout << "\tPast object" << endl;
			assert(invariant());
			return original_velocity.getTruncated(desired_speed);  // far enough past object
		}
	}
	else
	{
		// have not reached center of object; check against cylinder
		if(DEBUGGING_AVOID)
			cout << "Avoid: Approaching object" << endl;

		double distance_from_cylinder_center = relative_position.getAntiProjection(agent_forward).getNorm();
		double clearance_fraction            = (distance_from_cylinder_center - radius_sum) / clearance;
		if(DEBUGGING_AVOID)
		{
			cout << "\tTo sphere:         " << relative_position << endl;
			cout << "\tDistance_from_cylinder_center: " << distance_from_cylinder_center << endl;
			cout << "\tRadius_sum:        " << radius_sum << endl;
			cout << "\tClearance:         " << clearance << endl;
			cout << "\tFraction:          " << clearance_fraction << endl;
		}

		if(clearance_fraction < 0.0)
		{
			clearance_fraction = 0.0;
			if(DEBUGGING_AVOID)
				cout << "\tLined up at sphere" << endl;
		}

		if(clearance_fraction > 1.0)
		{
			if(DEBUGGING_AVOID)
				cout << "\tOutside cylinder" << endl;
			assert(invariant());
			return original_velocity;  // outside of danger cylinder
		}
		if(DEBUGGING_AVOID)
			cout << "\tModified fraction: " << clearance_fraction << endl;

		assert(!original_velocity.isZero());
		assert(!agent_forward.isZero());
		Vector3 sideways_vector = -relative_position.getAntiProjection(agent_forward);
		while(sideways_vector.isNormLessThan(AVOID_SIDEWAYS_NORM_MIN))
		{
			// we have almost no sideways, so use a random value
			sideways_vector = Vector3::getRandomUnitVector().getAntiProjection(agent_forward);
			// keep trying until we get a good one
		}
		assert(!original_velocity.isZero());
		assert(!sideways_vector.isZero());
		assert(sideways_vector.isOrthogonal(agent_forward));
		if(DEBUGGING_AVOID)
			cout << "\tSideways: " << sideways_vector << endl;

		Vector3 interpolated = original_velocity.getNormalized() *        clearance_fraction +
		                       sideways_vector  .getNormalized() * (1.0 - clearance_fraction);

		if(original_velocity.isNormLessThan(desired_speed))
			desired_speed = original_velocity.getNorm();

		if(DEBUGGING_AVOID)
			cout << "\tDodging out of cylinder: " << interpolated.getCopyWithNorm(desired_speed) << endl;
		assert(invariant());
		return interpolated.getCopyWithNorm(desired_speed);
	}
}