/* Sailing Ship v3.03, Angel January 1994.
*
* This sailing ship is designed to travel between ports of call,
* organised into an array read from the open directory within
* /room/islands/open. Any player can write a jetty of their own which
* they want the ship to visit on its route around the realms.
* It is designed to be copied, altered, and inherited as needed.
*
* The ships are also in an open dir so that players can buy ships
* with automatic writes to the directory
*/
#define PORT_FILE "/room/ships/open/ports.h"
#define SHIP_DIR "/room/ships/open/types/"
#define DISTANCE "/room/ships/distance"
#define START "/room/city/jetty"
#define ABANDON_SHIP "/room/island/beach5"
#define SHIP_OB_FILE "stern" /* where to find other ship fns */
#define NAME (string)this_player()->query_name()
#define SHIP_NAME capitalize(this_object()->query_short())
#define CAPTAIN "Captain"
#define WAIT_TIME 60 /* a few minutes */
#define X 0 /* members of an array for coords */
#define Y 1
#define SPEED 5 /* default speed of ship */
#define SIGHT_RANGE 100 /* range of the looking glass */
#define CLOSE_ENUFF 2
#define HP 1000 /* hp for the ship */
#include <mudlib.h>
#include <linewrap.h>
#include PORT_FILE
inherit ROOM;
mixed *destinations; /* places to sail to */
status sailing; /* for the init to set_heart_beat() */
status waiting; /* if the ship is waiting to move on */
string ship_name; /* name of the ship for exit array */
string captain; /* captain's name */
string port, port_file, port_long, port_list;
int timer, counter, distance, *old_port_coords, *port_coords, wait_time;
int speed, hull_points;
/*************************************************************************/
/* Fn Specs */
int query_coordinates();
mixed *check_ships();
void set_sail(string str);
void msg(string message);
/*************************************************************************/
/* Room Stuff */
void reset(status arg) {
string txt;
if(arg) return;
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_exits(({ "room/city/jetty", "gang plank", }));
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",
}));
}
void long(status wiz) {
string tmp, temp;
::long(wiz);
temp = capitalize(ship_name);
tmp = "There is a map beside the ships' wheel with the destination "+
capitalize(destinations[counter][0]+" circled in ink. ");
if(hull_points > hull_points/2)
tmp += "The "+temp+" is in excelent shape.\n";
else if(hull_points > hull_points/3)
tmp += "The "+temp+" is looking a little shabby.\n";
else if(hull_points > hull_points/4)
tmp += "The "+temp+" is showing some wear and tear.\n";
else if(hull_points > hull_points/5)
tmp += "The "+temp+" looks quite damaged.\n";
else
tmp += "The "+temp+" is falling appart!\n";
if(hull_points < 0)
tmp += "The "+temp+" is sinking!\n";
writelw(tmp);
}
void init() {
if(!sailing) {
if(!destinations) {
destinations = PORTS; /* from the included file */
destinations += ({ ({ "tempus city", START, ({ 0, 0, }), }), });
/* array is as follows: harbour file ({ x,y coords }) */
}
if(!wait_time) wait_time = WAIT_TIME;
if(!captain) captain = CAPTAIN;
if(!hull_points) hull_points = HP;
if(!ship_name) ship_name = "sutherland"; /* data's nebula ship! */
counter = 0;
port_file = START; /* where we start off */
port = "skol island";
old_port_coords = ({ 0, 0, });
port_long = port_file -> query_long();
call_out("set_sail", WAIT_TIME, destinations[0][0]);
sailing = 1;
waiting = 1;
distance = 141; /* an arbitary distance */
}
::init();
}
/*************************************************************************/
/* Special looks at functions */
status look_at(string str) {
string tmp, tmp1, tmp2;
int i, j, *ship_xy, *my_xy, *dest_xy;
string ship_file;
mixed *ships;
if(str == "map") {
tmp = "The map shows that the ship has many destinations, including ";
for(i=0; i<sizeof(destinations); i++) {
if((sizeof(destinations)-1) == i)
tmp += "and "+capitalize(destinations[i][0])+". ";
else
tmp += capitalize(destinations[i][0])+", ";
}
tmp += "From the map "+capitalize(destinations[counter][0])+
" is about "+(distance - timer)+" nautical miles away from here.\n";
writelw(tmp);
return 1;
}
if(str == "compass") {
tmp = "From the compass settings you think you're sailing in ";
my_xy = (int *)this_object()->query_coordinates();
dest_xy = (int *)this_object()->query_port_coords();
tmp1 = (string)DISTANCE -> calc_direction(my_xy, dest_xy);
if(tmp1[0] == 'e') tmp += "an "+tmp1;
else
tmp += "a "+tmp1;
tmp += "erly direction.\n";
writelw(tmp);
return 1;
}
if(str == "telescope") {
ships = check_ships(); /* placement of other ships ...except outs */
write("You look through the telescope...\n");
say(this_player()->query_name()+" looks through the telescope.\n",
this_player());
if(!sizeof(ships))
write("There are no ships within sight.\n");
else {
for(i=0; i<sizeof(ships); i++) {
if(ships[i][1] < SIGHT_RANGE) {
tmp = "You can see the ";
tmp += capitalize(ships[i][0]);
if(ships[i][1] < CLOSE_ENUFF)
tmp += ". It's only a few yards ";
else {
tmp += ". It's about "+ships[i][1]+" nautical miles ";
tmp += ships[i][2]+" from here.\n";
}
j++;
writelw(tmp);
}
}
}
if(!j) {
write("There are no ships within sight.\n");
}
if((distance - timer) < SIGHT_RANGE) {
write("You can see that "+capitalize(port)+" is only "+
(distance - timer)+" nautical miles away.\n");
}
else {
write("You can't see your destination yet.\n");
}
return 1;
}
return ::look_at(str);
}
/*************************************************************************/
/* Set Funs */
int set_ship_hp(int i) { return hull_points = i; }
int set_ship_speed(int i) { return speed = i; }
int set_wait_time(int i) { return wait_time = i; }
mixed *set_destinations(mixed *arr) { return destinations = arr; }
string set_ship_name(string str) { return ship_name = str; }
string set_captain(string str) { return captain = str; }
/*************************************************************************/
/* Major Ship Sailing Fn */
void heart_beat() {
mixed *arr;
int i;
if(!speed && hull_points > 0) speed = SPEED;
timer += speed;
/* wait for a while before setting off again */
if(waiting) {
if(timer > WAIT_TIME) {
set_sail(destinations[counter][0]);
timer = 0;
waiting = 0;
return;
}
}
if(timer >= distance) {
msg("The ship finally reaches "+capitalize(port)+".\n"+
capitalize(captain)+" says: Right then, we're here mates!\n"+
"The gang plank is pulled out toward the jetty\n");
port_long = port_file->query_long();
port_file -> set_long(port_long+
SHIP_NAME+" has dropped anchor here, "+
"in the harbour.\n");
this_object() -> add_exit(port_file, "gang plank");
port_file -> add_exit(file_name(this_object()), ship_name);
port_file -> add_item("gang plank#plank", "It leads onto the "+ship_name);
port_file -> add_item(ship_name,
SHIP_NAME+", with its gang plank set down close by.\n"+
"The ship looks as if it may set sail at any moment");
tell_room(port_file, SHIP_NAME+" sails into the harbour...\n");
old_port_coords = destinations[counter][2]; /* where we are now */
if(counter >= sizeof(destinations)-1)
counter = 0; /* next destination */
else
counter ++;
waiting = 1; /* wait for a little while before setting off */
timer = 0;
return;
}
if(!random(10)) {
if(arr = check_ships())
for(i=0; i<sizeof(arr); i++) {
if(arr[i][1] < CLOSE_ENUFF) {
msg("You notice the "+capitalize(arr[i][0])+" passing close by to "+
"the "+arr[i][2]+"...\n");
}
}
}
}
void set_sail(string str) {
msg(capitalize(captain)+" exclaims: Right then maties! Set sail for "+
capitalize(str)+" harbour!\n");
set_heart_beat(1);
if(port_file) { /* put the room back the way we found it */
port_file -> remove_exit(ship_name);
port_file -> remove_item("gang plank#plank");
port_file -> remove_item(ship_name);
port_file -> set_long(port_long);
tell_room(port_file, SHIP_NAME+" sails out of the harbour...\n");
}
this_object() -> remove_exit("gang plank");
port = destinations[counter][0];
port_file = destinations[counter][1];
port_coords = destinations[counter][2]; /* where we want to go */
/* calc distance from here to there */
distance = (int)DISTANCE->calc_distance(port_coords, old_port_coords);
msg("The anchor is pulled up onto the deck.\n");
msg("The gang plank is pulled in, and the ship sets sail.\n");
timer = 0;
waiting = 0;
return;
}
mixed *check_ships() {
int i, j, *dest_xy, *my_xy;
string *ships, tmp, ship_file, k;
mixed *result;
ships = get_dir(SHIP_DIR);
if(!sizeof(ships)) return 0;
result = ({});
for(i=0; i<sizeof(ships); i++) {
if(!sscanf(ships[i], "%s.c", tmp)) {
ship_file = SHIP_DIR+ships[i]+"/"+SHIP_OB_FILE;
if((string)ship_file->query_ship_name() !=
((string)this_object()->query_ship_name())) {
dest_xy = (int *)call_other(ship_file, "query_coordinates");
my_xy = (int *)this_object()->query_coordinates();
if(dest_xy && my_xy) {
j = (int)DISTANCE->calc_distance(my_xy, dest_xy);
tmp = capitalize((string)ship_file->query_ship_name());
k = (string)DISTANCE->calc_direction(my_xy, dest_xy);
result += ({ ({ tmp, j, k, }), });
}
}
}
}
return result;
}
mixed *query_coordinates() {
int x1, x2, y1, y2, dx, dy;
int gradient;
int x, y;
if(waiting) return old_port_coords;
if(!timer) return old_port_coords;
x1 = old_port_coords[X]; x2 = port_coords[X];
y1 = old_port_coords[Y]; y2 = port_coords[Y];
dx = x2 - x1;
dy = y2 - y1;
x = (dx * timer)/distance;
y = (dy * timer)/distance;
return ({ (x1 + x), (y1 + y), });
}
void msg(string message) {
tell_room(this_object(), message);
return;
}
int hit_ship(int dmg) {
hull_points -= dmg;
if(hull_points < 0) {
msg("The ship starts to sink!\n");
msg(capitalize(captain)+" exclaims: Abandon ship! We're sinking!\n");
set_heart_beat(0);
this_object()->add_exit(ABANDON_SHIP, "overboard");
}
else {
if(hull_points/dmg)
speed /= (hull_points/dmg);
if(speed < 1) speed = 1;
msg(SHIP_NAME+" slows in the water due to hull damage.\n");
set_heart_beat(1);
}
return hull_points;
}
int *query_port_coords() { return port_coords; }
int *query_old_port_coords() { return old_port_coords; }
int query_ship_hp() { return hull_points; }
string query_ship_name() { return ship_name; }
string query_captain() { return captain; }
mixed *query_destinations() { return destinations; }