/
lib/banish/
lib/d/coronos/
lib/d/coronos/w/alena/
lib/d/coronos/w/angel/
lib/d/coronos/w/angel/caves/
lib/d/coronos/w/angel/caves/monst/
lib/d/coronos/w/angel/city/chambers/
lib/d/coronos/w/angel/city/monst/
lib/d/coronos/w/angel/city/obj/
lib/d/coronos/w/angel/city/streets/
lib/d/coronos/w/angel/farms/plains/
lib/d/coronos/w/angel/monst/
lib/d/tempus/
lib/d/tempus/w/angel/
lib/d/tempus/w/kingbill/
lib/d/tempus/w/mirak/
lib/d/tempus/w/mirak/monst/
lib/d/tempus/w/mirak/obj/
lib/d/tempus/w/relgar/planes/baat/
lib/d/tempus/w/sarak/
lib/d/tempus/w/serepion/mon/
lib/d/tempus/w/valrejn/
lib/doc/
lib/doc/domains/
lib/doc/efun/
lib/include/fn_specs/
lib/info/
lib/inherit/base/
lib/log/
lib/log/mailbox/
lib/log/main/
lib/news/
lib/obj/party/
lib/objects/componen/
lib/open/
lib/open/party/
lib/open/paste/
lib/open/spells/
lib/open/valrejn/
lib/players/
lib/players/alena/
lib/players/alena/obj/
lib/players/alena/open/
lib/players/alena/private/
lib/players/angel/
lib/players/angel/obj/
lib/players/ash/
lib/players/biggs/
lib/players/biggs/food/
lib/players/biggs/gobkeep/
lib/players/biggs/mnstr/
lib/players/biggs/town/caves/
lib/players/biggs/town/tower/
lib/players/biggs/wpns/
lib/players/calris/
lib/players/deathurg/
lib/players/deathurg/open/
lib/players/deathurg/private/thief/
lib/players/dogberry/
lib/players/dogberry/library/
lib/players/dogberry/open/
lib/players/epsilon/
lib/players/epsilon/private/
lib/players/farewell/
lib/players/hippo/
lib/players/hippo/open/
lib/players/hippo/tools/
lib/players/jimpa/
lib/players/josh/
lib/players/josh/room/
lib/players/josh/room/mage/dungeon/
lib/players/josh/room/mage/dungeon/obj/
lib/players/josh/wep/
lib/players/kingbill/
lib/players/metatron/
lib/players/miette/
lib/players/mirak/
lib/players/mirak/open/
lib/players/parsilan/
lib/players/relgar/
lib/players/relgar/private/
lib/players/sarak/
lib/players/sarak/bugs/
lib/players/sarak/feelings/
lib/players/sarak/magical/
lib/players/sarak/minotaur/island/
lib/players/sarak/open/
lib/players/sarak/private/
lib/players/serepion/
lib/players/serepion/open/
lib/players/serepion/private/
lib/players/spike/
lib/players/spike/open/
lib/players/spike/private/
lib/players/spike/seaworld/
lib/players/valrejn/
lib/players/valrejn/open/
lib/players/valrejn/private/
lib/players/virus/
lib/players/wrath/
lib/players/wrath/arm/
lib/players/wrath/mon/
lib/players/wrath/room/
lib/players/wrath/room/entry/
lib/players/wrath/room/zolgath/
lib/players/wrath/weap/
lib/players/zil/
lib/room/
lib/room/city/arena/
lib/room/city/creator/
lib/room/city/garden/monst/
lib/room/city/library/
lib/room/city/library/open/books/
lib/room/city/shop/
lib/room/death/
lib/room/death/open/
lib/room/island/
lib/room/keeps/
lib/room/registry/
lib/room/ships/crew/
lib/room/ships/open/
lib/room/ships/open/types/bounty/
lib/room/ships/open/types/nebula/
lib/room/ships/open/types/phoenix/
lib/secure/udp_cmd_/
lib/skills/
lib/skills/fighter/
lib/skills/psionici/
lib/skills/thief/
lib/usr/
lib/usr/creators/
lib/usr/no_banis/
lib/usr/players/
/******************************************************************************
 * Sailing Ship v4.01, (c) Angel February 1994.
 * Original code Jan 1994, Angel
 *
 * Ships designed for two purposes:
 *        1) For future type domain use
 *        2) For sailing ships
 *
 * Ships have the following functions:
 *        1) Travel from place to place either, (a) automated, or (b) manual
 *        Players are able to make the ships travel from place to place so
 *        long as they are able to programm the conn. Automated travel is
 *        done without player intervention. A ship travels from port to port
 *        all by itself.
 *
 *        2) PK'ing through attacking other ships is possible through the
 *        tactical display (in what ever form it may be in).
 *   
 *        3) Messages are diplayed in all rooms, and attacking messages are
 *        displayed in all rooms of the enemy ship.
 *
 *        4) Scans are able to be performed to determine where places/ships are
 *
 *
 */ 


#include <mudlib.h>
#include "/room/ships/ships.cfg"


int x1, y1, z1, x2, y2, z2;        /* handy coordinates                    */
int distance;                      /* how far the trip is                  */
int speed;                         /* max speed the ship goes              */
int waiting;                       /* time the ship is waiting somewhere   */
int timer;                         /* how far we've currently travelled    */
int counter;                       /* counter for automated travel         */
int *destination_coordinates;      /* where we currently are               */
int *old_destination_coordinates;  /* where we came from                   */
int hp;                            /* dmg the ship can take                */

status automated;                  /* is the ship automated?               */


string ship_name;                  /* this ships designation               */
string destination_file;           /* file we're travelling to right now!  */
string destination;                /* name of the place we're going to     */
string destination_long;           /* long of the place we're going        */
mixed *destinations;              /* ALL the places we're going to        */
string msgout;                     /* ships' leaving message               */
string msgin;                      /* ships' arriving message              */

     
inherit ROOM;
void reset(status arg) {
  if(arg) return;

#ifndef STAR_SHIP
  set_short("the sutherland");
  set_long(
     "A tall mast with spinnaker flying from it towers above you on this \n"+
     "grand sailing ship. Three other sails are full with the sea winds  \n"+
     "pushing the ship ever closer to its port of call; your destination.\n");
  set_items(({
     "spinnaker",
          "A huge sail full of wind. Upon the spinnaker is a design \n"+
          "of a naked woman with the lower body of a great wave",
     "mast",
          "The spinnaker flies from the mast",
     "ship",
          "You're standing on it",
     "sail#sails",
          "The wind fills them, pushing the ship along in the water",
     "wind#winds", 
          "You can't see the wind!",  /* someone is bound to do it! */
     "sea#water#wave#waves",
          "They crash against the ship, making it toss up and "+
          "down in the water",
     "wheel",
          "The ships wheel is painted a rusty brown, matching the wood \n"+
          "on the rest of the ship. Beside it is a compass, as well as "+
          "a brass telescope",
  }));
  set_weather(2, 4, 6);

  set_night_desc(
     "A lantern hangs by the wheel, lighting the upper decks.\n");
  set_night_items(({
     "lantern", "A simple oil lantern made from brass",
  }));

#else
  set_short("the miranda");
  set_long(
     "You stand on the bridge of the Miranda, the first of its class, \n"+
     "named after the character of the same name in Shakespeare's play\n"+
     "the tempest. The Miranda was commissioned in the late 23rd century.\n");
  set_weather(2, 1, 0);

#endif /* SCI_FI */

}




/*************************************************************************/
/* Set Funs */
string set_ship_name(string str)      { return ship_name = str;    }
string set_msgin(string str)          { return msgin = str;        }
string set_msgout(string str)         { return msgout = str;       }

string *set_destinations(string *arr) { return destinations = arr; }

int    set_ship_speed(int i)          { return speed = i;          }



/*************************************************************************/
/* Cfg prototypes for ships */
void msg(string msg, string ship);

mixed *get_ships_data();
int *query_coordinates();
int *relative_bearing(int *coordinates1, int *coordinates2);

int   calc_direction(int *coordinates1, int *coordinates2);
int   calc_distance(int *coordinates1, int *coordinates2);
int   calc_elevation(int *coordinates1, int *coordinates2);
int   square_root(float i);

status ship_sail(string str);

status check_destination(string place);

/*************************************************************************/
/* Actions */

void init() {
  if(waiting)
    add_action("ship_disembark", "disembark");

  if(!automated) {
    add_action("ship_sail", "sail");
    add_action("ship_programme_coordinates", "input");
    add_action("ship_speed", "speed");
  }

  if(!destinations) destinations = PORTS_OF_CALL;
  if(!ship_name)    ship_name    = "Miranda";
  if(!hp)  hp  = HP;
  if(!speed) speed = IMPULSE_POWER;
  if(!old_destination_coordinates) old_destination_coordinates = ({ 0,0,0, }); 

  add_action("ship_scan", "scan");

  ::init();
}

status ship_speed(string str) {
  int i, j;

  if(sscanf(str, "warp %d", i) == 1) {
    if(i >= MAX_WARP) {
      write("The computer chirps: Exceeding maximum warp capability.\n"+
            "                     Enter warp speed again.\n");
      return 1;
    }  
    write("You enter warp "+i+" into the conn.\n");
    say(NAME+" engages the warp engines.\n");
    set_ship_speed(i*WARP_SPEED);
    set_heart_beat(1);
    return 1;
  }
  else if(sscanf(str, "impulse %d/%d", i, j) == 2) {
    write("You slow the engines down to "+i+"/"+j+" impulse power.\n");
    say(NAME+" engages the impulse engines.\n");
    set_ship_speed((IMPULSE_POWER * i)/j);
    set_heart_beat(1);
    return 1;
  }
  else {
    write("The computer chirps: Incorrect input.\n"+
          "Usage: speed warp <number> | impulse <fraction>\n");
    return 1;
  }
  return 0;
}

status ship_disembark() {
  write("You disembark from the "+SHIP_NAME+".\n");
  this_player()->move_player("off the "+SHIP_NAME+"#"+destination_file);
  return 1;
}

status ship_programme_coordinates(string str) {
  int x, y, z;
  int i;

  if(!str) {
    write("The computer chirps: Invalid input.\n");
    return 1;
  }
  if(sscanf(str, "%dx %dy %dz", x, y, z) != 3) {
    notify_fail("The computer chirps: Incorrect input. "+
          "Programme 'x y z' coordinates.\n");
    return 0;
  }

  write("The computer chirps: Coordinates ["+x+", "+y+", "+z+"] entered.\n");
  say(NAME+" programmes some coordinates into the conn.\n",this_player());

  destination_coordinates = ({ x, y, z, });

  for(i=0; i<sizeof(destinations); i++) {
    if(destination_coordinates == destinations[i][2]) {
      ship_sail(destinations[0][i]);
      return 1;
      break;
    }
  }

  if(destination_file) {   /* put the room back the way we found it */
    destination_file -> remove_exit(ship_name);
    destination_file -> remove_item(ship_name);
    destination_file -> set_long(destination_long);  
    tell_room(destination_file, SHIP_NAME+" "+msgout);
  }

  destination_file        = DEFAULT_DESTINATION;
  destination             = DEFAULT_DESTINATION_NAME;

  distance=calc_distance(destination_coordinates,old_destination_coordinates);
  write("Distance:"+ distance+"\n");
  write("Destination: "+destination+"\n");
  write("File: "+destination_file+"\n");

  waiting = 0;
  timer   = 0;
  set_heart_beat(1);
  return 1; 
}



status ship_sail(string str) {
  int *arr;
  if(!automated) {
    if(!check_destination(str)) {
      write("There is no such place.\n");
      return 1;
    }
  }    
  set_heart_beat(1);

  if(destination_file) {  /* put the room back the way we found it */
    write("destination_file: "+destination_file+"\n");
    destination_file -> remove_exit(ship_name);
    destination_file -> remove_item(ship_name);
    destination_file -> set_long(destination_long);  
    tell_room(destination_file, SHIP_NAME+" "+msgout);
  }

  if(automated) {
    destination             = destinations[counter][0];
    destination_file        = destinations[counter][1];
    destination_coordinates = destinations[counter][2]; 
  }

  distance = calc_distance(destination_coordinates,old_destination_coordinates);
  waiting  = 0;
  timer    = 0;
  arr = destination_coordinates;
  tell_room(this_object(), "Computer chirps: Parabolic course projected, "+
    "coordinates ["+arr[X]+"x, "+arr[Y]+"y, "+arr[Z]+"z]\n");
  return 1; 
}


status ship_scan() {
  string *ship_data, ship_file;
  int i, *my_xyz, *your_xyz, *data;
  status flag;
  
  ship_data = get_ships_data();

  write("You scan the sector.\n");
  say(NAME+" scans the sector.\n",this_player());

  if(!ship_data) {
    notify_fail("There are no ships in the sector.\n");
    return 0;
  }
  for(i=0; i<sizeof(ship_data); i++) {
    ship_file = SHIP_DIR+ship_data[i]+"/"+SHIP_FILE;
    your_xyz  = (int *)ship_file->query_coordinates();
    my_xyz    = query_coordinates();
    data      = relative_bearing(my_xyz, your_xyz);
    write(ship_data[0]+" bearing "+data[0]+", mark "+data[1]+"\n");
    flag = 1;
  }

 if(!sizeof(ship_data) || !flag) {
   notify_fail("There are no ships in the sector.\n");
   return 0;
  }
  return 1;
}


/*****************************************************************************/
/* Functions & guts of the ship */

void heart_beat() {
  mixed *arr;
  int i;

  timer += speed;
  tell_room(this_object(), "Testing heart beat: "+timer+"\n");

  if(automated) {
    if(waiting && (timer > WAIT_TIME)) {
      ship_sail(destinations[counter][0]);
      timer = 0;
      waiting = 0;
      return;
    }
  }


  if(timer >= distance) {

    destination_long =  (string)destination_file->query_long();
    destination_file -> add_exit(file_name(this_object()), ship_name);

    destination_file -> set_long(destination_long+
          SHIP_NAME+" has docked "+
          "at "+destination_file->query_short()+".\n");

    destination_file -> add_item(ship_name, 
          SHIP_NAME+" is docked to "+destination_file->query_short()+
          " and looks as though it may leave at any moment.\n");

    tell_room(destination_file, SHIP_NAME+" "+msgin+"...\n");
    tell_room(this_object(), "Computer chirps: Arrived at destination\n");

    if(automated) {
      old_destination_coordinates = destinations[counter][2];
      if(counter >= sizeof(destinations)-1)
        counter = 0;  /* next destination */
      else
        counter ++;
      waiting = 1;    /* wait for a little while before setting off */
      timer = 0;
    }
    else { /* not automated */
      tell_room(this_object(), "Computer chirps: Awaiting conn input.\n");
      set_heart_beat(0);
    }
    return;
  }    
}


int *relative_bearing(int *coordinates1, int *coordinates2) {
  int direction, elevation;
  direction = calc_direction(coordinates1, coordinates2);
  elevation = calc_elevation(coordinates1, coordinates2);
  return ({ direction, elevation, });
}


int calc_distance(int *coordinates1, int *coordinates2) {
  x1 = coordinates1[X];  y1 = coordinates1[Y];  z1 = coordinates1[Z];
  x2 = coordinates2[X];  y2 = coordinates2[Y];  z2 = coordinates2[Z];
  return square_root(
     ((x2-x1) * (x2-x1)) + 
     ((y2-y1) * (y2-y1)) +
     ((z2-z1) * (z2-z1)));
}



/* Finding absolute direction relative to this ship, in compass bearings */
int calc_direction(int *coordinates1, int *coordinates2) {
  float result;
  x1 = coordinates1[X];
  y1 = coordinates1[Y];
  x2 = coordinates2[X];
  y2 = coordinates2[Y];  /* only need x & y for relative compas bearings */
  if(x2>x1 && y2>y1)
    result = atan(to_float((x2-x1)/(y2-y1)));
  else if(x2>x1 && y2<y1)
    result = atan(to_float((y2-y1)/(x2-x1)) + 90/R_TO_D);
  else if(x2<x1 && y2<y1)
    result = atan(to_float((x1-x2)/(y1-y2)) + 180/R_TO_D);
  else 
   result = atan(to_float((y2-y1)/(x1-x2)) + 270/R_TO_D);
  result = result * R_TO_D;
  return to_int(result);
}


int calc_elevation(int *coordinates1, int *coordinates2) {
  float result;

  z1 = coordinates1[Z];
  y1 = coordinates1[Y];
  z2 = coordinates2[Z];
  y2 = coordinates2[Y];

  if(z2>z1 && y2>y1)
    result = atan(to_float((y2-y1)/(z2-z1)));
  else if(z1>z2 && y2>y1)
    result = atan(to_float((z1-z2)/(y2-y1)) + 90/R_TO_D);
  else if(z1>z2 && y1>y2)
    result = atan(to_float((y1-y2)/(z1-z2)) + 180/R_TO_D);
  else
    result = atan(to_float((z2-z1)/(y1-y2)) + 270/R_TO_D);
  result = result * R_TO_D;
  return to_int(result);
}


int square_root(int i) {  return to_int(sqrt(to_float(i)));  }

mixed *get_ships_data() {
  int i;
  int *dest_xyz, *my_xyz;
  string *ships;
  string ship_name, ship_file;
  int ship_direction;   /* as compass degrees */
  int ship_dist;
  mixed *result;
  ships = get_dir(SHIP_DIR);  /* get files in that dir */
  if(!sizeof(ships)) return 0;
  result = ({});

  for(i=0; i<sizeof(ships); i++) {
    ship_file = SHIP_DIR+ships[i]+"/"+SHIP_FILE;

    if((string)ship_file->query_ship_name() != 
      ((string)this_object()->query_ship_name())) {
      dest_xyz = (int *)call_other(ship_file, "query_coordinates");
      my_xyz   = query_coordinates();

      if(dest_xyz && my_xyz) {
        ship_direction =  calc_direction(my_xyz, dest_xyz);
        ship_dist      =  calc_distance(my_xyz, dest_xyz);
        ship_name      =  capitalize((string)ship_file->query_ship_name());
        result += ({ ({ ship_name, ship_dist, ship_direction, }), });
      }
    }
  }
  return result;
} 


mixed *query_coordinates() {
  int dx, dy, dz, x, y, z;

  if(!destination_coordinates)
    return old_destination_coordinates;

  x1 = old_destination_coordinates[X];  x2 = destination_coordinates[X];  
  y1 = old_destination_coordinates[Y];  y2 = destination_coordinates[Y];
  z1 = old_destination_coordinates[Z];  z2 = destination_coordinates[Z];

  dx = x2 - x1;
  dy = y2 - y1;
  dz = z2 - z1;

  x = (dx * timer)/distance;
  y = (dy * timer)/distance;
  z = (dz * timer)/distance;
  return ({ (x1 + x), (y1 + y), (z1 + z), });
}

status check_destination(string str) {
  int i;
  status flag;
  for(i=0; i<sizeof(destinations); i++) {
    if(str == destinations[i][0]) {
      flag = 1;
      destination_coordinates = destinations[i][2];
      destination_file        = destinations[i][1];
      destination             = destinations[i][0];
      break;
    }
  }
  return flag;
}

void msg(string msg, string ship_to_tell) {
  int i;
  string *files;

  if(!ship_to_tell)
    ship_to_tell = SHIP_DIR+"/"+SHIP_NAME;
  else
    ship_to_tell = SHIP_DIR+"/"+ship_to_tell;

  files = get_dir(ship_to_tell+"/");
  for(i=0; i<sizeof(files); i++) {
    ship_to_tell = SHIP_DIR+files[i];
    tell_room(ship_to_tell, msg);
  }
}

mixed *query_destinations() { return destinations; }