swr2.0/
swr2.0/area/
swr2.0/boards/
swr2.0/clans/
swr2.0/doc/
swr2.0/planets/
swr2.0/spacecraft/
/*
 * Copyright (c) 2006 Kai Braaten
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

/*
 * This file contains various utility functions to handle a ship's
 * behaviour in three dimensional space.
 *
 * The code assumes that you have replaced the old position and
 * heading variables in SPACE_DATA like this:
 *
 * struct ship_data
 * {
 *   Vector3 pos;  // current position
 *   Vector3 head; // heading/trajectory
 * };
 *
 * Don't forget to initialze the structures before use:
 * vector_init( &ship->pos );
 * vector_init( &ship->head );
 *
 * To get the most out of the Vector3 library it is recommended to use
 * it for everything related to positions and movement, including planets,
 * asteroids, missiles, and whatever else might apply to your codebase.
 * It will likely require a little work, as planets' positions were
 * originally handled as integers.
 *
 * A reminder about floating point comparisons:
 * Testing two floats or doubles for equality is not reliable in C.
 * This means that the following code may not give you the result you want:
 *
 * // Bad code follows:
 * if( vector_distance( &ship->pos, &target->pos ) == 100.0 )
 * {
 *   ... your code here
 * }
 *
 * Instead you must use a little slack like this:
 * if( myDouble < 101.0 && myDouble > 99.0 )
 */

#include <stdio.h>
#include "vector3.h"
#include "mud.h"
#include "vector3_aux.h"

/*
 * To check if a ship is facing a specific position, which can be another
 * ship, a planet, an asteroid, etc.
 *
 * if( ship_is_facing( ship, &target->pos ) )
 * {
 *   ... your code here
 * }
 */
static bool ship_is_facing( const SHIP_DATA * const ship,
    const Vector3 * const target )
{
  Vector3 h, d;
  bool facing = FALSE;
  double cosofa = 0.0;

  vector_copy( &h, &ship->head );

  d.x = target->x - ship->pos.x;
  d.y = target->y - ship->pos.y;
  d.z = target->z - ship->pos.z;

  cosofa =
    vector_dot( &h, &d ) / ( vector_length( &h ) + vector_length( &d ) );

  if( cosofa > 0.75 )
    facing = TRUE;

  return facing;
}

bool ship_is_facing_ship( const SHIP_DATA * const ship,
    const SHIP_DATA * const target )
{
  return ship_is_facing( ship, &target->pos );
}

bool ship_is_facing_planet( const SHIP_DATA * const ship,
    const PLANET_DATA * const target )
{
  return ship_is_facing( ship, &target->pos );
}

/*
 * Flip the trajectory to head the opposite way (180 degrees).
 */
void ship_turn_180( SHIP_DATA * const ship )
{
  ship->head.x *= -1;
  ship->head.y *= -1;
  ship->head.z *= -1;
}

/*
 * Set a new course towards another space object's position.
 *
 * Towards another ship.
 * ship_set_course( ship, &target->pos );
 *
 * Towards a planet.
 * ship_set_course( ship, &planet->pos );
 *
 * Etc, etc...
 */
void ship_set_course( SHIP_DATA * const ship,
    const Vector3 * const destination )
{
  ship->head.x = destination->x - ship->pos.x;
  ship->head.y = destination->y - ship->pos.y;
  ship->head.z = destination->z - ship->pos.z;
  vector_normalize( &ship->head );
}

void ship_set_course_to_ship( SHIP_DATA * const ship,
    const SHIP_DATA * const target )
{
  ship_set_course( ship, &target->pos );
}

void ship_set_course_to_planet( SHIP_DATA * const ship,
    const PLANET_DATA * const target )
{
  ship_set_course( ship, &target->pos );
}

void missile_set_course_to_ship( MISSILE_DATA * const missile,
    const SHIP_DATA * const target )
{
  missile->head.x = target->pos.x - missile->pos.x;
  missile->head.y = target->pos.y - missile->pos.y;
  missile->head.z = target->pos.z - missile->pos.z;
  vector_normalize( &missile->head );
}

/*
 * High-level function to align a ship's trajectory with another's.
 * Useful for grouped ships, docked ships, etc.
 */
void ship_align_heading( SHIP_DATA * const ship,
    const SHIP_DATA * const target )
{
  vector_copy( &ship->head, &target->head );
}

/*
 * Calculate new position based on heading and speed.
 */

static void move_space_object( Vector3 * const pos,
    const Vector3 * const head, const int speed )
{
  if( speed > 0 )
  {
    const double change = vector_length( head );

    if( change > 0 )
    {
      Vector3 tmpv;
      tmpv.x = head->x / change;
      tmpv.y = head->y / change;
      tmpv.z = head->z / change;
      pos->x += ( tmpv.x * speed ) / 5;
      pos->y += ( tmpv.y * speed ) / 5;
      pos->z += ( tmpv.z * speed ) / 5;
    }
  }
}

void ship_move( SHIP_DATA * const ship )
{
  move_space_object( &ship->pos, &ship->head, ship->currspeed );
}

void missile_move( MISSILE_DATA * const missile )
{
  move_space_object( &missile->pos, &missile->head, missile->speed );
}

double ship_distance_to_ship( const SHIP_DATA * const ship,
    const SHIP_DATA * const target )
{
  return vector_distance( &ship->pos, &target->pos );
}

double ship_distance_to_planet( const SHIP_DATA * const ship,
    const PLANET_DATA * const planet )
{
  return vector_distance( &ship->pos, &planet->pos );
}

double missile_distance_to_ship( const MISSILE_DATA * const missile,
    const SHIP_DATA * const target )
{
  return vector_distance( &missile->pos, &target->pos );
}

void vector_randomize( Vector3 * const vec, int from, int to )
{
  vec->x += number_range( from, to );
  vec->y += number_range( from, to );
  vec->z += number_range( from, to );
}