/************************************************************************** * # # # ## # # ### ## ## ### http://www.lyonesse.it * * # # # # # ## # # # # # * * # # # # # ## ## # # ## ## ## # # ## * * # # # # # ## # # # # # # # # # # # * * ### # ## # # ### ## ## ### # # #### ## Ver. 1.0 * * * * -Based on CircleMud & Smaug- Copyright (c) 2001-2002 by Mithrandir * * * * ********************************************************************** * * * * File: wild.ships.c * * * * Ships and Navigation code * * * **************************************************************************/ #include "conf.h" #include "sysdep.h" #include "structs.h" #include "utils.h" #include "comm.h" #include "db.h" #include "constants.h" #include "screen.h" #include "interpreter.h" #include "handler.h" #include "spells.h" /* external functions */ ROOM_DATA *create_wild_room( COORD_DATA *coord, bool Static ); OBJ_DATA *fread_one_obj( FILE *fp, int *location ); int save_objs(OBJ_DATA *obj, FILE *fp, int mode, int location); char *make_bar(long val, long max, long len, int color); void put_sect( int y, int x, int nSect, bool upMap ); void look_at_wild( CHAR_DATA *ch, bool quick ); void check_wild_move(CHAR_DATA *ch, VEHICLE_DATA *vehicle, SHIP_DATA *ship, FERRY_DATA *ferry, ROOM_DATA *pRoomFrom, ROOM_DATA *pRoomTo); void wild_check_for_remove( ROOM_DATA *wRoom ); void wild_remove_dequeue( ROOM_DATA *wRoom ); int get_sail_dir( SHIP_DATA *ship, COORD_DATA *cto, bool silent ); int calc_angle( int chX, int chY, int lmX, int lmY, int *ipDistan ); int angle_to_dir( int iAngle ); long event_time(EVENT_DATA *event); bitvector_t asciiflag_conv(char *flag); #if defined(KEY) #undef KEY #endif #define KEY( literal, field, value ) \ if ( !strcmp( word, literal ) ) \ { \ field = value; \ fMatch = TRUE; \ break; \ } /* globals */ SHIP_TYPE *ship_table[NUM_SHIP_TYPE]; SHIP_DATA *first_ship = NULL; SHIP_DATA *last_ship = NULL; PORT_DATA *port_table = NULL; COURSE_DATA *course_table = NULL; COURSE_DATA *rev_course_table = NULL; FERRY_DATA *first_ferry = NULL; FERRY_DATA *last_ferry = NULL; int top_ship_num = 0; int top_ship_table = 0; int top_port = 0; /* local functions */ EVENTFUNC(ship_sail_event); PORT_DATA *get_port_by_name( char *name ); PORT_DATA *get_port_by_coord( COORD_DATA *coord ); COURSE_DATA *get_course( COORD_DATA *orig, PORT_DATA *port_dest ); COURSE_DATA *get_course_by_vnum( int vnum ); COURSE_STEP *get_course_step( COURSE_DATA *course, COORD_DATA *coord ); void check_ship_speed( SHIP_DATA *ship ); void load_ship_table( void ); void load_ports( void ); void engage_course( CHAR_DATA *ch, COURSE_DATA *course, bool recover ); bool knows_course( CHAR_DATA *ch, int cnum ); char *get_port_name( COORD_DATA *coord ); /* local ferry functions */ EVENTFUNC(ferry_move_event); void ferry_move(void); /* ******************************************************************* */ /* Utilities for retrieving ship data */ /* ******************************************************************* */ SHIP_DATA *find_ship( sh_int vnum ) { SHIP_DATA *ship; if ( vnum < 0 ) return (NULL); for ( ship = first_ship; ship; ship = ship->next ) if ( ship->vnum == vnum ) return (ship); return (NULL); } SHIP_DATA *find_ship_in_room_by_name( ROOM_DATA *pRoom, char *name ) { SHIP_DATA *ship; int fnum; if ( !pRoom || !pRoom->ships ) return (NULL); if ( !name ) return (pRoom->ships); if ( !( fnum = get_number(&name) ) ) return (NULL); for ( ship = pRoom->ships; ship; ship = ship->next_in_room ) if ( isname( name, ship->name ) || !str_cmp( name, "ship" ) ) if ( --fnum == 0 ) break; return (ship); } ROOM_DATA *find_room_ship( SHIP_DATA *ship, int room ) { if ( room < 1 || room > ship->type->size ) return (NULL); return ( ship->rooms[room] ); } CHAR_DATA *find_char_in_ship( SHIP_DATA *ship, long idnum ) { CHAR_DATA *ppl; for ( ppl = ship->people; ppl; ppl = ppl->next_in_vehicle ) if ( GET_IDNUM(ppl) == idnum ) break; return (ppl); } /* ******************************************************************* */ /* Ship Authorization code */ /* ******************************************************************* */ AUTH_DATA *get_ship_auth( SHIP_DATA *ship, long idnum ) { AUTH_DATA *pAuth; bool aboard = FALSE; if ( !ship || !ship->authorized) return (NULL); for (pAuth = ship->authorized; pAuth; pAuth = pAuth->next) { if ( pAuth->id_num == idnum ) break; } return (pAuth); } bool can_go_aboard( CHAR_DATA *ch, SHIP_DATA *ship ) { if ( !ch || !ship ) return (FALSE); /* immortals can go aboard */ if ( IS_IMMORTAL(ch) ) return (TRUE); /* owner of the ship */ if ( GET_IDNUM(ch) == ship->idowner ) return (TRUE); /* captain of the ship */ if ( GET_IDNUM(ch) == ship->idcaptain ) return (TRUE); /* ppl authorized to go aboard */ if ( get_ship_auth( ship, GET_IDNUM(ch) ) ) return (TRUE); return (FALSE); } void auth_aboard( SHIP_DATA *ship, CHAR_DATA *ch, CHAR_DATA *vict, int mode ) { AUTH_DATA *pAuth; if ( !ship || !vict ) return; /* authorize */ if ( mode == 1 ) { if ( get_ship_auth( ship, GET_IDNUM(vict) ) ) { ch_printf( ch, "%s is already authorized to go aboard.\r\n", PERS(vict, ch) ); return; } CREATE(pAuth, AUTH_DATA, 1); pAuth->id_num = GET_IDNUM(vict); pAuth->name = str_dup(GET_NAME(vict)); pAuth->next = ship->authorized; ship->authorized = pAuth; ch_printf(ch, "%s is now authorized to go aboard of '%s'.\r\n", PERS(vict, ch), ship->name); ch_printf(vict, "You are now authorized to go aboard of '%s'.\r\n", ship->name); } /* revoke authorization */ else { AUTH_DATA *temp; if (!(pAuth = get_ship_auth(ship, GET_IDNUM(vict)))) { ch_printf( ch, "%s is already not authorized to go aboard.\r\n", PERS(vict, ch) ); return; } if ( find_char_in_ship( ship, GET_IDNUM(vict) ) ) { send_to_char("You cannot revoke authorization to someone that's aboard.\r\n", ch); return; } REMOVE_FROM_LIST(pAuth, ship->authorized, next); pAuth->next = NULL; STRFREE(pAuth->name); DISPOSE(pAuth); ch_printf(ch, "%s now is not authorized to go aboard of '%s'.\r\n", PERS(vict, ch), ship->name); ch_printf(vict, "Authorization to go aboard of '%s' has been revoked.\r\n", ship->name); } } /* ******************************************************************* */ /* Character/Ship/Room low-level interaction */ /* ******************************************************************* */ /* To be called when a pc enter a ship */ void char_to_ship( CHAR_DATA *ch, SHIP_DATA *ship, int room ) { int room_num = room; if ( room_num < 0 || room_num > ship->type->size) room_num = 0; ch->in_ship = ship; char_to_room(ch, ship->rooms[room_num]); ch->next_in_vehicle = ship->people; ship->people = ch; /* add ch weight to the ship */ ship->curr_val.loads += GET_WEIGHT(ch) + IS_CARRYING_W(ch); check_ship_speed( ship ); } /* To be called when a pc exit a ship */ void char_from_ship( CHAR_DATA *ch ) { CHAR_DATA *temp; /* subtract ch weight from the ship */ ch->in_ship->curr_val.loads -= GET_WEIGHT(ch) + IS_CARRYING_W(ch); check_ship_speed( ch->in_ship ); REMOVE_FROM_LIST(ch, ch->in_ship->people, next_in_vehicle); ch->in_ship = NULL; ch->next_in_vehicle = NULL; ch->player_specials->athelm = FALSE; } /* remove ship from room */ void ship_from_room( SHIP_DATA *ship ) { SHIP_DATA *temp; if ( !ship ) { log("SYSERR: NULL character or NULL room in ship_from_room"); exit(1); } ship->last_room = ship->in_room; REMOVE_FROM_LIST(ship, ship->in_room->ships, next_in_room); ship->in_room = NULL; ship->next_in_room = NULL; wild_check_for_remove(ship->last_room); } /* place ship on room */ void ship_to_room( SHIP_DATA *ship, ROOM_DATA *room ) { if (room == NULL ) { log("SYSERR: NULL is not a room pointer. Sorry."); return; } if ( ship == NULL ) { log("SYSERR: NULL is not a ship pointer. Sorry."); return; } ship->next_in_room = room->ships; room->ships = ship; ship->in_room = room; /* Handle Wild Sectors */ if ( IS_WILD(room) ) { check_wild_move( NULL, NULL, ship, NULL, ship->last_room, room ); if (ROOM_FLAGGED(room, ROOM_WILD_REMOVE)) wild_remove_dequeue(room); } } /* ******************************************************************* */ /* C O M M U N I C A T I O N S */ /* ******************************************************************* */ /* Send a message to everyone on the ship */ void send_to_ship( char *msg, SHIP_DATA *ship ) { CHAR_DATA *ch; if (!ship) return; for (ch = ship->people; ch; ch = ch->next_in_vehicle) send_to_char(msg, ch); } /* Send a message to everyone on the ship's deck */ void send_to_deck( char *msg, SHIP_DATA *ship ) { CHAR_DATA *ch; for ( ch = ship->people; ch; ch = ch->next_in_vehicle ) if ( ON_DECK(ch) ) send_to_char( msg, ch ); } /* ship tell */ int is_stell_ok( CHAR_DATA *vict ) { if (!IS_NPC(vict) && !vict->desc) /* linkless */ return (FALSE); if (PLR_FLAGGED(vict, PLR_WRITING)) return (FALSE); if ((!IS_NPC(vict) && PRF_FLAGGED(vict, PRF_NOTELL)) || ROOM_FLAGGED(vict->in_room, ROOM_SOUNDPROOF)) return (FALSE); return (TRUE); } ACMD(do_stell) { CHAR_DATA *ppl; skip_spaces(&argument); one_argument( argument, arg ); if ( !ch->in_ship ) { send_to_char( "You aren't embarked on a ship.\r\n", ch ); return; } if (!*arg) { send_to_char("What do you want to tell to people on ship?\r\n", ch); return; } if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_NOTELL)) { send_to_char("You can't tell other people while you have notell on.\r\n", ch); return; } if (ROOM_FLAGGED(ch->in_room, ROOM_SOUNDPROOF)) { send_to_char("The walls seem to absorb your words.\r\n", ch); return; } if (PRF_FLAGGED(ch,PRF_NOREPEAT)) sprintf(buf, OK); else sprintf(buf, "&1You tell to everyone on ship, '%s'&0\r\n", arg ); send_to_char(buf, ch); sprintf( buf, "&1$n tells to ship, '%s'&0", arg); for ( ppl = ch->in_ship->people; ppl; ppl = ppl->next_in_vehicle ) { if ( ppl == ch ) continue; if ( !is_stell_ok(ppl) ) continue; act(buf, FALSE, ch, 0, ppl, TO_VICT | TO_SLEEP); } } /* ******************************************************************* */ /* I N F O R M A T I O N S */ /* ******************************************************************* */ void list_one_ship( SHIP_DATA *ship, CHAR_DATA *ch ) { if ( !ship || !ch ) return; ch_printf( ch, "&b&6%s %s named '&7%s&6' is here at anchor.&0\r\n", UAN(ship->type->name), ship->type->name, ship->name ); } void list_ship_to_char( SHIP_DATA *shiplist, CHAR_DATA *ch ) { SHIP_DATA *ship; if ( !shiplist || !ch || IS_NPC(ch) ) return; for ( ship = shiplist; ship; ship = ship->next_in_room ) list_one_ship( ship, ch ); } /* ******************************************************************* */ /* C O M M A N D S */ /* ******************************************************************* */ ACMD(do_embark) { SHIP_DATA *ship; one_argument(argument, arg); if ( !*arg ) { send_to_char( "Embark on which ship?\r\n", ch ); return; } if ( ch->in_ship ) { send_to_char( "But you are currently embarked on a ship.. disembark first.\r\n", ch ); return; } if ( !ch->in_room->ships ) { send_to_char( "No ships here.\r\n", ch ); return; } if ( !( ship = find_ship_in_room_by_name( ch->in_room, arg ) ) ) { ch_printf( ch, "No ship named '%s' around.\r\n", arg ); return; } if ( RIDING(ch) ) { send_to_char( "No way you can go aboard while riding.\r\n", ch ); return; } if ( WAGONER(ch) ) { send_to_char( "No way you can go aboard while driving a vehicle.\r\n", ch ); return; } if ( !can_go_aboard( ch, ship ) ) { ch_printf( ch, "You are not authorized to go aboard of '%s'.\r\n", ship->name ); return; } char_from_room(ch); char_to_ship(ch, ship, 0); ch_printf( ch, "You go aboard of '%s'.\r\n", ship->name ); } ACMD(do_disembark) { ROOM_DATA *pRoom; if ( !ch->in_ship ) { send_to_char( "But you aren't aboard a ship.\r\n", ch ); return; } if ( !SHIP_FLAGGED(ch->in_ship, SHIP_IN_PORT) ) { send_to_char( "You cannot disembark from a ship that's not in a port.\r\n", ch ); return; } if ( SECT(ch->in_room) != SECT_SHIP_STERN ) { send_to_char( "You must be astern to disembark.\r\n", ch ); return; } if ( !( pRoom = get_wild_room( ch->in_ship->port ) ) ) { log( "SYSERR: no wilderness room as harbour at coord %d %d.", ch->in_ship->port->y, ch->in_ship->port->x ); send_to_char( "Sorry, at the moment you cannot disembark.\r\n", ch ); return; } ch_printf( ch, "You disembark from '%s'.\r\n", ch->in_ship->name ); char_from_ship(ch); char_from_room(ch); char_to_room(ch, pRoom); } ACMD(do_courselist) { COURSE_DATA *course; COURSE_STEP *cstep; PORT_DATA *port_orig, *port_dest; char cbuf[MAX_STRING_LENGTH]; if ( !course_table ) { send_to_char("No course loaded.\r\n", ch); return; } strcpy( cbuf, "List of Sea Course:\r\n" "---------------------------------------------\r\n" ); for (course = course_table; course; course = course->next) { port_orig = get_port_by_coord( course->port_orig ); port_dest = get_port_by_coord( course->port_end ); sprintf(cbuf + strlen(cbuf), "From Port: %s\r\nTo Port : %s\r\n", port_orig->name, port_dest->name ); for ( cstep = course->first_step; cstep; cstep = cstep->next ) sprintf(cbuf + strlen(cbuf), " Step: %d %d\r\n", cstep->coord.y, cstep->coord.x ); } strcat( cbuf, "---------------------------------------------\r\n" ); page_string( ch->desc, cbuf, 1 ); } /* * commands for ships: * * load - carica merce a bordo * unload - scarica merce * drive - si mette al timone / lascia il timone * anchor - butta l'ancora / recupera l'ancora * sail <porto> - fa rotta verso un porto * repair - mette in cantiere la nave per riparare i danni * auth <ch> - autorizza un giocatore a salire a bordo */ ACMD(do_ship) { SHIP_DATA *ship; argument = one_argument(argument, arg); if (!ch->in_ship) { send_to_char( "To be aboard a ship would surely help.. he he\r\n", ch ); return; } if ( !*arg ) { send_to_char( "Available commands for ships are:\r\n" "-------------------------------------------------------------------" "<status> print informations about the ship\r\n" "<drive> grab/let go the helm to drive the ship\r\n" "*<charge> list goods aboard\r\n" "*<load 'good'> load good aboard\r\n" "*<unload 'good'> unload good from ship\r\n" "<anchor> place/remove anchor\r\n" "<sail 'port'> automatic sailing to the given port destination\r\n" "<stop> stops automatic sailing\r\n" "<captain 'name'> nominate 'name' captain of the ship\r\n" "<captain> revoke captaincy\r\n" "-------------------------------------------------------------------\r\n" "* = Uninmplemented.\r\n" , ch ); return; } ship = ch->in_ship; if (is_abbrev(arg, "drive")) { if ( SECT(ch->in_room) != SECT_SHIP_STERN ) { send_to_char("You must be at the stern to drive a ship.\r\n", ch ); return; } if ( GET_IDNUM(ch) != ship->idcaptain ) { send_to_char("You must be the captain to drive the ship.\r\n", ch ); return; } if ( !GET_SKILL(ch, SKILL_NAVIGATION) ) { send_to_char( "You have no idea of how to drive a ship.\r\n", ch ); return; } if ( GET_SKILL(ch, SKILL_NAVIGATION) < ship->type->skill_min ) { send_to_char("You aren't skilled enough to drive a ship of this size.\r\n", ch); return; } /* first of all, check if ship helmperson and ch are the same */ if ( ship->helmperson && ship->helmperson != ch ) { send_to_char( "Someone else is driving the ship.\r\n", ch ); return; } if ( ch->player_specials->athelm ) { ch->player_specials->athelm = FALSE; ship->helmperson = NULL; send_to_char( "You let off the helm.\r\n", ch ); } else { ch->player_specials->athelm = TRUE; ship->helmperson = ch; send_to_char( "You grab the helm and start to drive the ship.\r\n", ch ); } } else if (is_abbrev(arg, "status")) { char sflags[128]; sprintbit(ship->flags, ship_flags, sflags); sprintf(buf, "---------------------------------------------------------------\r\n" "Name : '%s'\r\nType : %s\r\nFlags : %s\r\n", ship->name, ship->type->name, sflags ); send_to_char(buf, ch); sprintf(buf, "---------------------------------------------------------------\r\n" "Power : %s (%5d/%5d)\r\n" "Defense: %s (%5d/%5d)\r\n" "Health : %s (%5d/%5d)\r\n" "Speed : %s (%5d/%5d)\r\n" "Loads : %s (%5d/%5d)\r\n" "---------------------------------------------------------------\r\n", make_bar( ship->curr_val.power, ship->max_val.power, 40, 6 ), ship->curr_val.power, ship->max_val.power, make_bar( ship->curr_val.defense, ship->max_val.defense, 40, 6 ), ship->curr_val.defense, ship->max_val.defense, make_bar( ship->curr_val.health, ship->max_val.health, 40, 6 ), ship->curr_val.health, ship->max_val.health, make_bar( ship->curr_val.speed, ship->max_val.speed, 40, 6 ), ship->curr_val.speed, ship->max_val.speed, make_bar( ship->curr_val.loads, ship->max_val.loads, 40, 6 ), ship->curr_val.loads, ship->max_val.loads ); send_to_char(buf, ch); if ( SHIP_FLAGGED(ship, SHIP_IN_COURSE) ) { sprintf(buf, "&b&2In course for %s harbour, heading to the %s.&0\r\n" "Next move in %ld ticks.\r\n", get_port_name( ship->course->port_end), dirs[ship->direction], event_time(ship->action) ); send_to_char(buf, ch); } } else if (is_abbrev(arg, "sail")) { COURSE_DATA *course; PORT_DATA *port_dest; char arg2[MAX_STRING_LENGTH]; argument = one_argument( argument, arg2 ); if ( SHIP_FLAGGED(ship, SHIP_AT_ANCHOR) ) { send_to_char("Anchored ships cannot move.\r\n", ch ); return; } if ( SHIP_FLAGGED(ship, SHIP_IN_COURSE) ) { send_to_char("You are already following a course, use <ship stop> to stop the ship.\r\n", ch ); return; } /* first of all, check if ship helmperson and ch are the same */ if ( ship->helmperson && ship->helmperson != ch ) { send_to_char( "Someone else is driving the ship.\r\n", ch ); return; } if ( !GET_SKILL(ch, SKILL_NAVIGATION) ) { send_to_char( "You have no idea of how set a course.\r\n", ch ); return; } if ( GET_SKILL(ch, SKILL_NAVIGATION) < ship->type->skill_min ) { send_to_char("You aren't skilled enough to drive a ship of this size.\r\n", ch); return; } if ( !*arg2 ) { if ( ship->course ) { ch_printf( ch, "You recover the sailing to '%s' harbour.\r\n", get_port_name(ship->course->port_end) ); engage_course( ch, ship->course, TRUE ); return; } send_to_char( "Sail to which port?\r\n", ch ); return; } if ( !( port_dest = get_port_by_name( arg2 ) ) ) { ch_printf( ch, "No port called %s is known.\r\n", arg2 ); return; } if ( SHIP_FLAGGED(ship, SHIP_IN_PORT) ) { if ( ship->port->y == port_dest->coord->y && ship->port->x == port_dest->coord->x ) { send_to_char( "The shorter history sail. There you are.\r\n", ch ); return; } } if ( SHIP_FLAGGED(ship, SHIP_IN_PORT) ) course = get_course( ship->port, port_dest ); else { send_to_char( "You can follow sea courses only when leaving a port.\r\n", ch ); return; } if ( !course ) { ch_printf( ch, "There is not a direct course to '%s' harbour.\r\n", arg2 ); return; } if ( !knows_course( ch, course->vnum ) ) { ch_printf( ch, "You don't know a course to '%s' harbour.\r\n", arg2 ); return; } engage_course( ch, course, FALSE ); } else if (!str_cmp(arg, "stop")) { if ( !SHIP_FLAGGED(ship, SHIP_IN_COURSE)) { send_to_char( "You aren't following a course.\r\n", ch ); return; } event_cancel( ship->action ); ship->action = NULL; REMOVE_BIT(SHIP_FLAGS(ship), SHIP_IN_COURSE); send_to_char( "You stop follow the sea course.\r\n", ch ); send_to_ship("The ship stops.\r\n", ship); } else if (is_abbrev(arg, "captain")) { CHAR_DATA *vict; ROOM_DATA *pRoom; char arg2[MAX_STRING_LENGTH]; argument = one_argument( argument, arg2 ); if ( !*arg2 ) { if ( ship->idcaptain != -1 ) { ship->idcaptain = -1; send_to_char("The ship is now without a captain.\r\n", ch); } else send_to_char( "Nominate captain who?\r\n", ch ); return; } if ( ship->idcaptain != -1 ) { send_to_char("The ship already has a captain.\r\n", ch); return; } if ( !SHIP_FLAGGED(ship, SHIP_IN_PORT) || !( pRoom = get_wild_room(ship->port) ) ) { send_to_char("You can nominate only when ship is at one port.\r\n", ch); return; } if ( !( vict = get_char_room_vis( ch, arg2, NULL ) ) ) { ch_printf( ch, "No one called '%s' around.\r\n", arg2 ); return; } /* new introduction system */ if ( !is_char_known(ch, vict) ) { send_to_char("You cannot nominate captain someone you don't know.\r\n", ch ); return; } /* assume command! */ ship->idcaptain = GET_IDNUM(vict); act("$N is now the captain of the ship.", FALSE, ch, NULL, vict, TO_CHAR); act("$N is now the captain of the ship.", FALSE, ch, NULL, vict, TO_ROOM); ch_printf(vict, "You have been nominated captain of '&7%s&0'. Congratulations!!\r\n", ship->name); } // toggle anchor else if (is_abbrev(arg, "anchor")) { if (ship->idcaptain != GET_IDNUM(ch)) { send_to_char("You must be the captain to place/remove the anchor.\r\n", ch ); return; } if (SHIP_FLAGGED(ship, SHIP_AT_ANCHOR)) { REMOVE_BIT(SHIP_FLAGS(ship), SHIP_AT_ANCHOR); send_to_char("You remove the anchor.\r\n", ch); } else { if ( SHIP_FLAGGED(ship, SHIP_IN_COURSE)) { event_cancel( ship->action ); ship->action = NULL; REMOVE_BIT(SHIP_FLAGS(ship), SHIP_IN_COURSE); send_to_char( "You stop follow the sea course.\r\n", ch ); send_to_ship("The ship stops.\r\n", ship); } SET_BIT(SHIP_FLAGS(ship), SHIP_AT_ANCHOR); send_to_char("You place the anchor.\r\n", ch); } } else send_to_char( "Not yet implemented, sorry.\r\n", ch ); } /* ******************************************************************** * * N A V I G A T I O N * * ******************************************************************** * * * * Legenda of Ship Movement Functions * * * * check_ship_speed: calculate ship speed * * ship_can_sail: check to see if the ship can sail * * engage_course: inits the automatic sailing * * ship_to_port: handle the arrival in a port * * ship_move: called from perform_move() - manual sailing * * create_sail_event: setup the delayed sail event * * ship_sail_event: the delayed sail event * * * * ******************************************************************** */ /* * When ch and goods are loaded into ship, they affect ship speed as: * * - no affection if < of 50% max_val.loads * - reduction of 1 pt speed between 51-70% (Min speed is always 1) * - reduction of 2 pt speed between 71-80% (Min speed is always 1) * - reduction of 3 pt speed between 81-90% (Min speed is always 1) * - reduction of 4 pt speed between 91-99% (Min speed is always 1) * - 100% speed is always 1 * - > 100% speed is 0 -- ship can't move */ void check_ship_speed( SHIP_DATA *ship ) { int plusw, malus, orig; char msg[MAX_STRING_LENGTH]; if ( !ship ) return; orig = ship->curr_val.speed; plusw = percentage( ship->curr_val.loads, ship->max_val.loads ); /* calculate speed penality */ if ( plusw < 50 ) malus = 0; else if ( plusw < 70 ) malus = 1; else if ( plusw < 80 ) malus = 2; else if ( plusw < 90 ) malus = 3; else if ( plusw < 99 ) malus = 4; else if ( plusw == 100 ) malus = ship->max_val.speed - 1; else // > 100% { send_to_ship( "The ship cannot move.. too weight aboard!\r\n", ship ); ship->curr_val.speed = 0; return; } /* set up current speed */ ship->curr_val.speed = MAX( 1, ship->max_val.speed - malus ); if ( orig == ship->curr_val.speed ) return; sprintf(msg, "The ship speed capacity is now %d nodes.\r\n", ship->curr_val.speed ); send_to_ship( msg, ship ); } bool ship_can_sail( CHAR_DATA *ch, SHIP_DATA *ship ) { /* check speed */ if ( ship->curr_val.speed <= 0 ) { send_to_char( "The ship cannot sail, too weight aboard.\r\n", ch ); return (FALSE); } /* check health status (but only before leaving a port) */ if ( percentage(ship->curr_val.health, ship->max_val.health) < 10 && SHIP_FLAGGED(ship, SHIP_IN_PORT) ) { send_to_char( "The ship is too damaged to leave the port.\r\n", ch ); return (FALSE); } if (SHIP_FLAGGED(ship, SHIP_AT_ANCHOR)) { send_to_char("Anchored ships cannot move.\r\n", ch); return (FALSE); } return (TRUE); } void ship_to_port( SHIP_DATA *ship, ROOM_DATA *pRoom ) { PORT_DATA *port; if ( !( port = get_port_by_coord( pRoom->coord ) ) ) { log( "SYSERR: no port found at coord %d %d.", GET_RY(pRoom), GET_RX(pRoom) ); send_to_ship( "Argh.. there is a problem, call an Immortal.\r\n", ship ); return; } SET_BIT(SHIP_FLAGS(ship), SHIP_IN_PORT); REMOVE_BIT(SHIP_FLAGS(ship), SHIP_SAIL); if ( SHIP_FLAGGED(ship, SHIP_IN_COURSE) ) { REMOVE_BIT(SHIP_FLAGS(ship), SHIP_IN_COURSE); ship->course = NULL; DISPOSE(ship->cstep); } ship->action = NULL; CREATE(ship->port, COORD_DATA, 1); ship->port->y = GET_RY(pRoom); ship->port->x = GET_RX(pRoom); sprintf( buf, "%s sails to %s.\r\n", ship->name, port->name ); send_to_room( buf, ship->in_room ); ship_from_room( ship ); ship_to_room( ship, pRoom ); sprintf( buf, "%s sails from the %s.\r\n", ship->name, dirs[rev_dir[ship->direction]] ); send_to_room( buf, ship->in_room ); sprintf( buf, "You enter %s harbour.\r\n", port->name ); send_to_ship( buf, ship ); } void create_sail_event( SHIP_DATA *ship, sh_int type ) { SAIL_EVENT *sail; int delay; if ( !ship ) return; if ( ship->curr_val.speed <= 0 ) return; if ( ship->action ) return; CREATE( sail, SAIL_EVENT, 1 ); sail->ship = ship; sail->type = type; delay = SHIP_SPEED_BASE - ship->curr_val.speed; ship->action = event_create(ship_sail_event, sail, delay); } void engage_course( CHAR_DATA *ch, COURSE_DATA *course, bool recover ) { SHIP_DATA *ship; EXIT_DATA *pexit; int dir; if ( !ch || !course ) return; ship = ch->in_ship; if ( ship->action ) { send_to_char( "You can't sail at the moment.\r\n", ch ); return; } if ( !ship_can_sail( ch, ship ) ) return; if ( !recover ) { ship->course = course; ship->cstep = course->first_step; } dir = get_sail_dir( ship, &ship->cstep->coord, FALSE ); if ( !( pexit = get_exit( ship->in_room, dir ) ) ) { send_to_char("Alas, you cannot go that way...\r\n", ch); ship->course = NULL; ship->cstep = NULL; return; } // here.. if ship recover course immediately out of a port, we must handle.. /* the ship enter a port */ if ( SECT(pexit->to_room) == SECT_PORT ) { ship_to_port( ship, pexit->to_room ); return; } if ( !water_sector(SECT(pexit->to_room)) ) { send_to_char("You can't go on landmasses with a ship.\r\n", ch); ship->course = NULL; ship->cstep = NULL; return; } SET_BIT(SHIP_FLAGS(ship), SHIP_IN_COURSE); /* first move out of the port */ if ( SECT(ship->in_room) == SECT_PORT ) { REMOVE_BIT(SHIP_FLAGS(ship), SHIP_IN_PORT); SET_BIT(SHIP_FLAGS(ship), SHIP_SAIL); DISPOSE(ship->port); } /* dir = get_sail_dir( ship, &ship->cstep->coord, FALSE ); if ( !( pexit = get_exit( ship->in_room, dir ) ) ) { send_to_char("Alas, you cannot go that way...\r\n", ch); return; } if ( !water_sector(SECT(pexit->to_room)) ) { send_to_char("You can't go on landmasses with a ship.\r\n", ch); return; } */ /* save the direction for automatic sailing */ ship->direction = dir; create_sail_event(ship, SAIL_COURSE); } void ship_move( CHAR_DATA *ch, int dir, int special_check ) { SHIP_DATA *ship; EXIT_DATA *pexit; if ( !ch || !ch->in_ship || !ch->player_specials->athelm ) return; ship = ch->in_ship; if ( dir < 0 || dir >= NUM_OF_DIRS ) { send_to_char("Invalid direction.\r\n", ch ); return; } if ( SHIP_FLAGGED(ship, SHIP_AT_ANCHOR) ) { send_to_char("Anchored ships cannot move.\r\n", ch ); return; } /* hmmm.. to check again later */ if ( ship->action ) { if ( SHIP_FLAGGED(ship, SHIP_IN_COURSE ) ) { event_cancel( ship->action ); ship->action = NULL; REMOVE_BIT(SHIP_FLAGS(ship), SHIP_IN_COURSE); send_to_char( "You stop the course sailing.\r\n", ch ); } else { send_to_char("The ship is currently performing another action.\r\n", ch ); return; } } if ( !ship_can_sail( ch, ship ) ) return; if ( !( pexit = get_exit( ship->in_room, dir ) ) ) { send_to_char("Alas, you cannot go that way...\r\n", ch); return; } /* the ship enter a port */ if ( SECT(pexit->to_room) == SECT_PORT ) { ship_to_port( ship, pexit->to_room ); return; } if ( !water_sector(SECT(pexit->to_room)) ) { send_to_char("You can't go on landmasses with a ship.\r\n", ch); return; } /* first move out of the port */ if ( SECT(ship->in_room) == SECT_PORT ) { REMOVE_BIT(SHIP_FLAGS(ship), SHIP_IN_PORT); SET_BIT(SHIP_FLAGS(ship), SHIP_SAIL); DISPOSE(ship->port); } /* save the direction for automatic sailing */ ship->direction = dir; create_sail_event(ship, SAIL_MANUAL); } /* Ship movement.. */ EVENTFUNC(ship_sail_event) { SAIL_EVENT *sail = (SAIL_EVENT *) (event_obj); SHIP_DATA *ship; EXIT_DATA *pexit; CHAR_DATA *ppl; ship = sail->ship; if ( !ship || !ship->action) { DISPOSE(event_obj); return (0); } if ( sail->type == SAIL_MANUAL ) ship->action = NULL; /* clear ship action */ // check for speed if ( ship->curr_val.speed <= 0 ) { DISPOSE(event_obj); return (0); } // check for exit if ( !( pexit = get_exit( ship->in_room, ship->direction ) ) ) { log("SYSERR: sail_event() -- invalid exit to %d for ship %s.", ship->direction, ship->name ); DISPOSE(event_obj); return (0); } /* the ship enter a port */ if ( SECT(pexit->to_room) == SECT_PORT ) { ship_to_port( ship, pexit->to_room ); DISPOSE(event_obj); return (0); } // check for water if (!water_sector(SECT(pexit->to_room))) { log("SYSERR: sail_event() -- not sea exit to %s for ship %s.", dirs[ship->direction], ship->name ); DISPOSE(event_obj); return (0); } sprintf( buf, "%s sails to the %s.\r\n", ship->name, dirs[ship->direction] ); send_to_room( buf, ship->in_room ); ship_from_room( ship ); ship_to_room( ship, pexit->to_room ); sprintf( buf, "%s sails from the %s.\r\n", ship->name, dirs[rev_dir[ship->direction]] ); send_to_room( buf, ship->in_room ); for ( ppl = ship->people; ppl; ppl = ppl->next_in_vehicle ) { if ( ON_DECK(ppl) && !FIGHTING(ppl) ) look_at_wild(ppl, TRUE); } if ( sail->type == SAIL_COURSE ) { int dir; /* have we reached the step? */ if ( ship->in_room->coord->y == ship->cstep->coord.y && ship->in_room->coord->x == ship->cstep->coord.x ) { /* check for last step */ if ( !ship->cstep->next ) { COURSE_STEP *csnew; CREATE(csnew, COURSE_STEP, 1); csnew->next = NULL; csnew->prev = NULL; csnew->coord.y = ship->course->port_end->y; csnew->coord.x = ship->course->port_end->x; /* next step will be the port itself */ ship->cstep = csnew; } else ship->cstep = ship->cstep->next; } dir = get_sail_dir( ship, &ship->cstep->coord, FALSE ); if ( dir == NOWHERE ) { log("SYSERR: ship_sail_event() - cannot get a direction for next step %d %d.", ship->cstep->coord.y, ship->cstep->coord.x); REMOVE_BIT(SHIP_FLAGS(ship), SHIP_IN_COURSE); REMOVE_BIT(SHIP_FLAGS(ship), SHIP_SAIL); DISPOSE(event_obj); return (0); } ship->direction = dir; return (SHIP_SPEED_BASE - ship->curr_val.speed); } else { DISPOSE(event_obj); return (0); } } /* ******************************************************************* */ /* Ship making */ /* ******************************************************************* */ void free_ship( SHIP_DATA *ship ) { SHIP_DATA *temp; /* cut off from the list, if needed */ if ( ship->next ) UNLINK(ship, first_ship, last_ship, next, prev); if ( ship->next_in_room && ship->in_room ) REMOVE_FROM_LIST( ship, ship->in_room->ships, next_in_room ); if ( ship->people ) { /* transfer people to limbo */ CHAR_DATA *ppl; while (ship->people) { ppl = ship->people; char_from_ship(ppl); char_from_room(ppl); char_to_room(ppl, get_room(1)); } } if ( ship->rooms[0] ) { } ship->action = NULL; ship->helmperson = NULL; ship->in_room = NULL; ship->last_room = NULL; ship->next = NULL; ship->next_in_room = NULL; ship->people = NULL; ship->storeroom = NULL; if ( ship->name ) free(ship->name ); if ( ship->port ) free(ship->port ); ship->authorized = NULL; ship->type = NULL; DISPOSE(ship); } SHIP_DATA *new_ship( void ) { SHIP_DATA *ship; CREATE( ship, SHIP_DATA, 1 ); ship->name = NULL; ship->in_room = NULL; ship->last_room = NULL; ship->people = NULL; ship->next = NULL; ship->prev = NULL; ship->next_in_room = NULL; ship->action = NULL; ship->storeroom = NULL; ship->helmperson = NULL; ship->port = NULL; ship->type = NULL; ship->authorized = NULL; ship->course = NULL; ship->cstep = NULL; ship->flags = 0; ship->direction = NOWHERE; ship->idowner = 0; ship->idcaptain = 0; ship->vnum = NOTHING; return (ship); } /* make the ship inside */ bool create_ship_rooms(SHIP_DATA *ship) { FILE *fp; EXTRA_DESCR *new_descr; char fname[128]; char letter, *flags; int room, door; sprintf(fname, "%s%d.ship", SHIP_PREFIX, ship->type->vnum); if (!(fp = fopen(fname, "r"))) { log("SYSERR: Unable to open ship template file %s.", fname); return (FALSE); } CREATE(ship->rooms, ROOM_DATA *, ship->type->size); for (room = 0; room < ship->type->size; room++) { CREATE(ship->rooms[room], ROOM_DATA, 1); ship->rooms[room]->number = room; ship->rooms[room]->zone = SHIP_ZONE; CREATE(ship->rooms[room]->extra_data, ROOM_EXTRA, 1); ship->rooms[room]->extra_data->vnum = ship->vnum; } for ( ;; ) { letter = fread_letter(fp); if (feof(fp)) break; if (letter == '$') break; if (letter == '*') { fread_to_eol(fp); continue; } if (letter != '#') { log("create_ship_rooms(): # not found."); break; } room = fread_number(fp); if (room < 0 || room > ship->type->size) break; ship->rooms[room]->number = room; ship->rooms[room]->name = fread_string_nospace(fp); ship->rooms[room]->description = fread_string_nospace(fp); flags = fread_word(fp); ship->rooms[room]->room_flags = asciiflag_conv(flags); ship->rooms[room]->sector_type = fread_number(fp); if (ship->rooms[room]->sector_type == SECT_SHIP_HOLD) ship->storeroom = ship->rooms[room]; for ( ;; ) { letter = fread_letter(fp); if (letter == '*') { fread_to_eol(fp); continue; } if (letter == 'S' || letter == '$') break; switch (letter) { case 'D': door = fread_number(fp); if ( door < 0 || door > NUM_OF_DIRS ) { log( "create_ship_rooms: vnum %d has bad door number %d.", room, door ); break; } else { EXIT_DATA *pexit; char flags[128]; char *ln; int x1, x2; pexit = make_exit(ship->rooms[room], NULL, door); pexit->description = fread_string_nospace(fp); pexit->keyword = fread_string_nospace(fp); ln = fread_line(fp); x1=x2=0; sscanf( ln, "%s %d %d ", &flags, &x1, &x2 ); pexit->key = x1; pexit->vnum = x2; pexit->vdir = door; pexit->exit_info = asciiflag_conv(flags); pexit->to_room = ship->rooms[pexit->vnum]; /* sanity check */ if (pexit->exit_info && !EXIT_FLAGGED(pexit, EX_ISDOOR)) SET_BIT(pexit->exit_info, EX_ISDOOR); } break; case 'E': CREATE(new_descr, EXTRA_DESCR, 1); new_descr->keyword = fread_string(fp, buf2); new_descr->description = fread_string(fp, buf2); new_descr->next = ship->rooms[room]->ex_description; ship->rooms[room]->ex_description = new_descr; break; } } if (letter == '$') break; } fclose(fp); return (TRUE); } SHIP_DATA *create_ship( CHAR_DATA *ch, SHIP_TYPE *tShip, PORT_DATA *port, char *arg) { SHIP_DATA *ship; int hp; if ( !tShip || !port ) { log( "SYSERR: Create_ship() - no proto or port data" ); return (NULL); } ship = new_ship(); ship->name = ( *arg ? str_dup(arg) : str_dup(tShip->name) ); ship->idowner = GET_IDNUM(ch); ship->idcaptain = GET_IDNUM(ch); /* hmmmmm... */ ship->vnum = ++top_ship_num; ship->type = tShip; CREATE( ship->port, COORD_DATA, 1 ); ship->port->y = port->coord->y; ship->port->x = port->coord->x; hp = tShip->value.health * tShip->size; ship->curr_val.health = ship->max_val.health = hp; ship->curr_val.defense = ship->max_val.defense = tShip->value.defense; ship->curr_val.equip = ship->max_val.equip = tShip->value.equip; ship->curr_val.power = ship->max_val.power = tShip->value.power; ship->curr_val.speed = ship->max_val.speed = tShip->value.speed; ship->max_val.loads = tShip->value.loads; ship->curr_val.loads = 0; create_ship_rooms( ship ); SET_BIT(SHIP_FLAGS(ship), SHIP_IN_PORT); /* add to the list */ LINK(ship, first_ship, last_ship, next, prev); return (ship); } /* Imms command */ ACMD(do_shipsetup) { SHIP_DATA *ship; COORD_DATA *coord; ROOM_DATA *pRoom; PORT_DATA *port; char arg1[MAX_STRING_LENGTH], arg2[MAX_STRING_LENGTH]; char *shipname; int sh_type = 0; argument = one_argument( argument, arg ); argument = two_arguments( argument, arg1, arg2 ); shipname = strtok(argument, "'"); if (shipname == NULL) { send_to_char("Which name?\r\n", ch); return; } shipname = strtok(NULL, "'"); if (shipname == NULL) { send_to_char("Ship names must be enclosed in the Holy Magic Symbols: '\r\n", ch); return; } if ( !*arg || !*arg1 || !*arg2 || !*shipname ) { send_to_char( "Usage: shipsetup <type> <y> <x> 'name'\r\n" " <type> = type of ship\r\n" " <y> <x> = port coordinates\r\n" " 'name' = name of the ship\r\n", ch ); return; } sh_type = atoi(arg); if ( sh_type < 0 || sh_type > top_ship_table - 1 ) { ch_printf( ch, "Valid ship types goes from 0 to %d.\r\n", top_ship_table ); return; } CREATE(coord, COORD_DATA, 1); coord->y = atoi(arg1); coord->x = atoi(arg2); if ( !check_coord( coord->y, coord->x ) ) return; if ( !( port = get_port_by_coord( coord ) ) ) { ch_printf( ch, "No port found at coord %d %d.\r\n", coord->y, coord->x ); return; } pRoom = get_wild_room( coord ); if ( !pRoom || SECT(pRoom) != SECT_PORT ) { send_to_char("Invalid coordinates.\r\n", ch ); return; } ship = create_ship( ch, ship_table[sh_type], port, shipname ); ship_to_room( ship, pRoom ); } /* ******************************************************************* */ /* Ship Files handling */ /* ******************************************************************* */ /* write on file the building inside */ void fwrite_ship_rooms(SHIP_DATA *ship, FILE *fp) { ROOM_DATA *room; EXIT_DATA *pexit; char dflags[128]; int num; for (num = 0; num < ship->type->size; num++) { room = ship->rooms[num]; if (!room) break; /* Copy the description and strip off trailing newlines */ strcpy(buf, room->description ? room->description : "Empty room."); strip_cr(buf); sprintascii(buf2, room->room_flags); fprintf(fp, "#%d\n" "%s~\n" "%s~\n" "%s %d\n", room->number, room->name ? room->name : "Untitled", buf, buf2, room->sector_type ); /* Now you write out the exits for the room */ for (pexit = room->first_exit; pexit; pexit = pexit->next) { /* check for non-building exits */ if (!IS_SHIP(pexit->to_room)) continue; if (pexit->description) { strcpy(buf, pexit->description); strip_cr(buf); } else *buf = '\0'; if (pexit->keyword) strcpy(buf1, pexit->keyword); else *buf1 = '\0'; /* New door flags handling -- Fab 2000 */ REMOVE_BIT(EXIT_FLAGS(pexit), EX_LOCKED); REMOVE_BIT(EXIT_FLAGS(pexit), EX_CLOSED); REMOVE_BIT(EXIT_FLAGS(pexit), EX_HIDDEN); /* sanity check */ if (EXIT_FLAGS(pexit) && !EXIT_FLAGGED(pexit, EX_ISDOOR)) SET_BIT(EXIT_FLAGS(pexit), EX_ISDOOR); sprintascii(dflags, pexit->exit_info); fprintf(fp, "D%d\n" "%s~\n" "%s~\n" "%s %d %d\n", pexit->vdir, buf, buf1, dflags, pexit->key, ( pexit->to_room != NULL ? pexit->to_room->number : NOWHERE ) ); } if (room->ex_description) { EXTRA_DESCR *xdesc; for (xdesc = room->ex_description; xdesc; xdesc = xdesc->next) { strcpy(buf, xdesc->description); strip_cr(buf); fprintf(fp, "E\n" "%s~\n" "%s~\n", xdesc->keyword, buf); } } fprintf(fp, "S\n"); } /* Write the final line */ fprintf(fp, "$\n\n"); } void fwrite_ship( SHIP_DATA *ship ) { FILE *fp; char fname[128]; int num; sprintf(fname, "%s%d.ship", LIB_SHIPS, ship->vnum); if ( !(fp = fopen( fname, "w" ) ) ) { log( "Cannot open ship file %s", fname ); return; } fprintf( fp, "#SHIP\n" ); fprintf( fp, "Vnum %d\n", ship->vnum ); fprintf( fp, "Name %s~\n", ship->name ); fprintf( fp, "Type %s~\n", ship->type->name ); fprintf( fp, "Flags %d\n", ship->flags ); fprintf( fp, "Val_Defense %hd %hd\n", ship->curr_val.defense, ship->max_val.defense ); fprintf( fp, "Val_Equip %hd %hd\n", ship->curr_val.equip, ship->max_val.equip ); fprintf( fp, "Val_Health %hd %hd\n", ship->curr_val.health, ship->max_val.health ); fprintf( fp, "Val_Loads %hd %hd\n", ship->curr_val.loads, ship->max_val.loads ); fprintf( fp, "Val_Power %hd %hd\n", ship->curr_val.power, ship->max_val.power ); fprintf( fp, "Val_Speed %hd %hd\n", ship->curr_val.speed, ship->max_val.speed ); fprintf( fp, "IdOwner %ld\n", ship->idowner ); fprintf( fp, "IdCaptain %ld\n", ship->idcaptain ); if ( ship->authorized ) { AUTH_DATA *pAuth; for (pAuth = ship->authorized; pAuth; pAuth = pAuth->next) fprintf(fp, "IdAuth %ld %s\n", pAuth->id_num, pAuth->name); } if ( SHIP_FLAGGED(ship, SHIP_IN_PORT) ) fprintf( fp, "Port %hd %hd\n", ship->port->y, ship->port->x ); else if ( SHIP_FLAGGED(ship, SHIP_AT_ANCHOR) ) fprintf( fp, "Anchored %hd %hd\n", GET_Y(ship), GET_X(ship) ); else fprintf( fp, "Sailing %hd %hd\n", GET_Y(ship), GET_X(ship) ); if ( SHIP_FLAGGED(ship, SHIP_IN_COURSE) ) { fprintf( fp, "Course %d\r\n", ship->course ); fprintf( fp, "CStep %hd %hd\r\n", ship->cstep->coord.y, ship->cstep->coord.x ); } fprintf( fp, "End\n\n" ); fprintf(fp, "#ROOMS\n"); fwrite_ship_rooms(ship, fp); for (num = 0; num < ship->type->size; num++) { if (ship->rooms[num] && ship->rooms[num]->first_content) { fprintf(fp, "#ROOMCONTENT\n"); fprintf(fp, "Room %d\n", num); save_objs( ship->rooms[num]->last_content, fp, 0, 0); fprintf(fp, "End\n\n"); } } fprintf( fp, "#END\n" ); fclose(fp); } void SaveShips( void ) { FILE *fp; SHIP_DATA *ship; char fname[128]; if ( !first_ship ) return; sprintf( fname, "%sindex", LIB_SHIPS ); if ( !( fp = fopen( fname, "w" ) ) ) { log( "SYSERR: unable to write index file for ships." ); return; } for ( ship = first_ship; ship; ship = ship->next ) { if ( ship->vnum == NOTHING ) continue; fprintf( fp, "%d.ship\n", ship->vnum ); fwrite_ship( ship ); } fprintf( fp, "$\n" ); fclose(fp); } /* READING */ SHIP_TYPE *parse_ship_type( char *tname ) { int y; for ( y = 0; y < top_ship_table; y++ ) { if ( !ship_table[y] || !ship_table[y]->name ) continue; if ( !str_cmp( tname, ship_table[y]->name ) ) return ( ship_table[y] ); } return (NULL); } bool fread_one_ship( SHIP_DATA *ship, FILE *fp ) { char *word; bool fMatch; for ( ; ; ) { word = feof( fp ) ? "End" : fread_word( fp ); fMatch = FALSE; switch ( UPPER(word[0]) ) { case '*': fMatch = TRUE; fread_to_eol( fp ); break; case 'A': if ( !str_cmp( word, "Anchored" ) ) { ROOM_DATA *pRoom; CREATE( ship->port, COORD_DATA, 1 ); ship->port->y = fread_number(fp); ship->port->x = fread_number(fp); pRoom = create_wild_room( ship->port, FALSE ); fMatch = TRUE; break; } break; case 'C': if ( !str_cmp( word, "Course" ) ) { COURSE_DATA *course; int vnum = fread_number(fp); course = get_course_by_vnum( vnum ); ship->course = course; /* should set on the course flag?? hmmmm */ SET_BIT(SHIP_FLAGS(ship), SHIP_IN_COURSE); fMatch = TRUE; break; } if ( !str_cmp( word, "CStep" ) ) { COORD_DATA coord; coord.y = fread_number(fp); coord.x = fread_number(fp); if ( ship->course ) ship->cstep = get_course_step( ship->course, &coord ); fMatch = TRUE; break; } break; case 'E': if ( !str_cmp( word, "End" ) ) { if ( ship->vnum == NOTHING || !ship->type ) { if ( ship->port ) DISPOSE(ship->port); DISPOSE(ship); return (FALSE); } create_ship_rooms( ship ); return (TRUE); } break; case 'F': KEY( "Flags", ship->flags, fread_number(fp) ); break; case 'I': KEY( "IdOwner", ship->idowner, fread_number(fp) ); KEY( "IdCaptain", ship->idcaptain, fread_number(fp) ); if ( !str_cmp(word, "IdAuth")) { AUTH_DATA *pAuth; CREATE(pAuth, AUTH_DATA, 1); pAuth->id_num = fread_number(fp); pAuth->name = str_dup(fread_word(fp)); // add to the list pAuth->next = ship->authorized; ship->authorized = pAuth; fMatch = TRUE; break; } break; case 'N': KEY( "Name", ship->name, fread_string_nospace(fp) ); break; case 'P': if ( !str_cmp( word, "Port" ) ) { CREATE( ship->port, COORD_DATA, 1 ); ship->port->y = fread_number(fp); ship->port->x = fread_number(fp); fMatch = TRUE; break; } break; case 'S': if ( !str_cmp( word, "Sailing" ) ) { ROOM_DATA *pRoom; CREATE( ship->port, COORD_DATA, 1 ); ship->port->y = fread_number(fp); ship->port->x = fread_number(fp); pRoom = create_wild_room( ship->port, FALSE ); fMatch = TRUE; break; } break; case 'T': if ( !str_cmp( word, "Type" ) ) { ship->type = parse_ship_type( fread_string_nospace(fp) ); fMatch = TRUE; break; } break; case 'V': KEY( "Vnum", ship->vnum, fread_number(fp) ); if ( !str_cmp( word, "Val_Defense" ) ) { ship->curr_val.defense = fread_number(fp); ship->max_val.defense = fread_number(fp); fMatch = TRUE; break; } if ( !str_cmp( word, "Val_Equip" ) ) { ship->curr_val.equip = fread_number(fp); ship->max_val.equip = fread_number(fp); fMatch = TRUE; break; } if ( !str_cmp( word, "Val_Health" ) ) { ship->curr_val.health = fread_number(fp); ship->max_val.health = fread_number(fp); fMatch = TRUE; break; } if ( !str_cmp( word, "Val_Loads" ) ) { ship->curr_val.loads = fread_number(fp); ship->max_val.loads = fread_number(fp); fMatch = TRUE; break; } if ( !str_cmp( word, "Val_Power" ) ) { ship->curr_val.power = fread_number(fp); ship->max_val.power = fread_number(fp); fMatch = TRUE; break; } if ( !str_cmp( word, "Val_Speed" ) ) { ship->curr_val.speed = fread_number(fp); ship->max_val.speed = fread_number(fp); fMatch = TRUE; break; } break; } if ( !fMatch ) log( "fread_ship_type: no match: %s", word ); } return (FALSE); } #define MAX_BAG_ROWS 5 /* load contents of a ship room from file */ void fread_ship_contents( SHIP_DATA *ship, FILE *fp ) { OBJ_DATA *obj, *obj2, *cont_row[MAX_BAG_ROWS]; int location, j, roomnum; char *word; bool fMatch; /* Empty all of the container lists (you never know ...) */ for (j = 0; j < MAX_BAG_ROWS; j++) cont_row[j] = NULL; for ( ; ; ) { word = feof( fp ) ? "End" : fread_word( fp ); fMatch = FALSE; switch ( UPPER(word[0]) ) { case '*': fMatch = TRUE; fread_to_eol( fp ); break; case 'E': if ( !str_cmp( word, "End" ) ) return; case 'R': KEY( "Room", roomnum, fread_number(fp) ); break; case '#': // skip #OBJECT line.. fread_to_eol( fp ); if ( ( obj = fread_one_obj( fp, &location ) ) == NULL ) continue; obj_to_room( obj, ship->rooms[roomnum] ); for (j = MAX_BAG_ROWS - 1; j > -location; j--) { if (cont_row[j]) /* No container, back to inventory. */ { for (; cont_row[j]; cont_row[j] = obj2) { obj2 = cont_row[j]->next_content; obj_to_room( cont_row[j], ship->rooms[roomnum] ); } cont_row[j] = NULL; } } if (j == -location && cont_row[j]) /* Content list exists. */ { if (GET_OBJ_TYPE(obj) == ITEM_CONTAINER || GET_OBJ_TYPE(obj) == ITEM_MISSILE_CONT ) { /* Take the item, fill it, and give it back. */ obj_from_room(obj); obj->first_content = NULL; obj->last_content = NULL; for (; cont_row[j]; cont_row[j] = obj2) { obj2 = cont_row[j]->next_content; obj_to_obj(cont_row[j], obj); } obj_to_room( obj, ship->rooms[roomnum] ); } else /* Object isn't container, empty content list. */ { for (; cont_row[j]; cont_row[j] = obj2) { obj2 = cont_row[j]->next_content; obj_to_room( cont_row[j], ship->rooms[roomnum] ); } cont_row[j] = NULL; } } if (location < 0 && location >= -MAX_BAG_ROWS) { obj_from_room(obj); if ((obj2 = cont_row[-location - 1]) != NULL) { while (obj2->next_content) obj2 = obj2->next_content; obj2->next_content = obj; } else cont_row[-location - 1] = obj; } break; } } } /* load from file the building inside */ void fread_ship_rooms(SHIP_DATA *ship, FILE *fp) { EXTRA_DESCR *new_descr; char letter, *flags; int room, door; CREATE(ship->rooms, ROOM_DATA *, ship->type->size); for (room = 0; room < ship->type->size; room++) { CREATE(ship->rooms[room], ROOM_DATA, 1); ship->rooms[room]->zone = SHIP_ZONE; CREATE(ship->rooms[room]->extra_data, ROOM_EXTRA, 1); ship->rooms[room]->extra_data->vnum = ship->vnum; } for ( ;; ) { letter = fread_letter(fp); if (feof(fp)) break; if (letter == '$') break; if (letter == '*') { fread_to_eol(fp); continue; } if (letter != '#') { log("fread_ship_rooms(): # not found."); break; } room = fread_number(fp); if (room < 0 || room > ship->type->size) break; ship->rooms[room]->number = room; ship->rooms[room]->name = fread_string_nospace(fp); ship->rooms[room]->description = fread_string_nospace(fp); flags = fread_word(fp); ship->rooms[room]->room_flags = asciiflag_conv(flags); ship->rooms[room]->sector_type = fread_number(fp); for (;;) { letter = fread_letter(fp); if (letter == '*') { fread_to_eol(fp); continue; } if (letter == 'S' || letter == '$') break; switch (letter) { case 'D': door = fread_number(fp); if ( door < 0 || door > NUM_OF_DIRS ) { log("fread_ship_rooms: vnum %d has bad door number %d.", room, door); break; } else { EXIT_DATA *pexit; char flags[128]; char *ln; int x1, x2; pexit = make_exit( ship->rooms[room], NULL, door ); pexit->description = fread_string_nospace(fp); pexit->keyword = fread_string_nospace(fp); ln = fread_line(fp); x1=x2=0; sscanf( ln, "%s %d %d ", &flags, &x1, &x2 ); pexit->key = x1; pexit->vnum = x2; pexit->vdir = door; pexit->exit_info = asciiflag_conv( flags ); pexit->to_room = ship->rooms[pexit->vnum]; /* sanity check */ if ( pexit->exit_info && !EXIT_FLAGGED( pexit, EX_ISDOOR ) ) SET_BIT( pexit->exit_info, EX_ISDOOR ); } break; case 'E': CREATE(new_descr, EXTRA_DESCR, 1); new_descr->keyword = fread_string(fp, buf2); new_descr->description = fread_string(fp, buf2); new_descr->next = ship->rooms[room]->ex_description; ship->rooms[room]->ex_description = new_descr; break; } } if (letter == '$') break; } } SHIP_DATA *fread_ship( char *sname ) { FILE *fp; SHIP_DATA *ship; char fname[128]; char letter; char *word; sprintf( fname, "%s%s", LIB_SHIPS, sname ); if ( !( fp = fopen(fname, "r") ) ) return (NULL); ship = new_ship(); for ( ;; ) { letter = fread_letter( fp ); if ( letter == '*' ) { fread_to_eol( fp ); continue; } if ( letter != '#' ) { log( "fread_ship: # not found." ); break; } word = fread_word( fp ); if ( !str_cmp( word, "SHIP" ) ) { if ( !fread_one_ship( ship, fp ) ) { fclose(fp); return (NULL); } } else if (!strcmp(word, "ROOMS")) fread_ship_rooms(ship, fp); else if ( !str_cmp( word, "ROOMCONTENT" ) ) fread_ship_contents( ship, fp ); else if ( !str_cmp( word, "END" ) ) break; else { log( "fread_ship: bad section." ); continue; } } fclose( fp ); return (ship); } /* load all saved rooms */ void LoadShips( void ) { FILE *fp; SHIP_DATA *ship; char fname[128]; sprintf( fname, "%sindex", LIB_SHIPS ); if ( !( fp = fopen(fname, "r") ) ) return; while (!feof(fp)) { char *shipname = fread_word( fp ); if ( shipname[0] == '$' ) break; if ( !( ship = fread_ship( shipname ) ) ) log( "SYSERR: LoadShips() unable to read ship file %s.", shipname ); else { ROOM_DATA *pRoom; /* add to ship list */ LINK(ship, first_ship, last_ship, next, prev); top_ship_num++; /* place in the world */ if ( SHIP_FLAGGED(ship, SHIP_IN_PORT ) ) pRoom = get_wild_room( ship->port ); else if ( SHIP_FLAGGED(ship, SHIP_SAIL) || SHIP_FLAGGED(ship, SHIP_AT_ANCHOR) ) { pRoom = get_wild_room( ship->port ); DISPOSE( ship->port ); // not a port, destroy } else { log( "SYSERR: no coord to place ship %d.", ship->vnum ); if ( !port_table ) { log( "SYSERR: no ports loaded." ); free_ship(ship); continue; } pRoom = get_wild_room( port_table->coord ); } ship_to_room( ship, pRoom ); } } fclose (fp); } ACMD(do_shipread) { SHIP_DATA *ship; ROOM_DATA *pRoom; one_argument(argument, arg); if ( !*arg ) return; ship = fread_ship( arg ); if ( !ship ) { log("SYSERR: unable to load ship file %s.", arg ); return; } if ( SHIP_FLAGGED(ship, SHIP_IN_PORT ) ) pRoom = get_wild_room( ship->port ); else if ( SHIP_FLAGGED(ship, SHIP_SAIL) || SHIP_FLAGGED(ship, SHIP_AT_ANCHOR) ) { pRoom = get_wild_room( ship->port ); DISPOSE( ship->port ); // not a port, destroy } else { log( "SYSERR: no coord to place ship %d.", ship->vnum ); if ( !port_table ) { log( "SYSERR: no ports loaded." ); return; } pRoom = get_wild_room( port_table->coord ); } ship_to_room( ship, pRoom ); } /* ******************************************************************* */ /* Ship prototypes */ /* ******************************************************************* */ SHIP_TYPE *fread_ship_type( FILE *fp ) { SHIP_TYPE *tShip; char *word; bool fMatch; CREATE( tShip, SHIP_TYPE, 1 ); tShip->name = NULL; tShip->short_descr = NULL; tShip->vnum = NOTHING; tShip->skill_min = 1; tShip->size = 0; tShip->value.defense = 0; tShip->value.equip = 0; tShip->value.health = 0; tShip->value.loads = 0; tShip->value.power = 0; tShip->value.speed = 0; for ( ; ; ) { word = feof( fp ) ? "End" : fread_word( fp ); fMatch = FALSE; switch ( UPPER(word[0]) ) { case '*': fMatch = TRUE; fread_to_eol( fp ); break; case 'D': KEY( "Defense", tShip->value.defense, fread_number(fp) ); KEY( "Descr", tShip->short_descr, fread_string_nospace(fp) ); break; case 'E': KEY( "Equip", tShip->value.equip, fread_number(fp) ); if ( !str_cmp( word, "End" ) ) { if ( tShip->vnum == NOTHING ) { log("SYSERR: ship prototipe has no vnum."); exit(1); } if ( !tShip->name ) tShip->name = str_dup("ship error"); if ( !tShip->short_descr ) tShip->short_descr = str_dup("Ship Error"); return (tShip); } break; case 'H': KEY( "Health", tShip->value.health, fread_number(fp) ); break; case 'L': KEY( "Loads", tShip->value.loads, fread_number(fp) ); break; case 'N': KEY( "Name", tShip->name, fread_string_nospace(fp) ); break; case 'P': KEY( "Power", tShip->value.power, fread_number(fp) ); break; case 'S': KEY( "Size", tShip->size, fread_number(fp) ); KEY( "Speed", tShip->value.speed, fread_number(fp) ); KEY( "Skill", tShip->skill_min, fread_number(fp) ); break; case 'V': KEY("Vnum", tShip->vnum, fread_number(fp)); break; } if ( !fMatch ) log( "fread_ship_type: no match: %s", word ); } return (NULL); } void load_ship_table( void ) { FILE *fp; char indname[256]; char letter; char *word; sprintf(indname, "%sships.txt", SHIP_PREFIX); if (!(fp = fopen(indname, "r"))) { log( "Cannot open ship table file %s", indname ); exit(0); } top_ship_table = 0; for ( ;; ) { letter = fread_letter( fp ); if ( letter == '*' ) { fread_to_eol( fp ); continue; } if ( letter != '#' ) { log( "Load_ship_table: # not found." ); break; } word = fread_word( fp ); if ( !str_cmp( word, "SHIP" ) ) { if ( top_ship_table >= NUM_SHIP_TYPE ) { log( "load_ship_table: more ships than NUM_SHIP_TYPE %d", NUM_SHIP_TYPE ); fclose( fp ); return; } ship_table[top_ship_table++] = fread_ship_type( fp ); continue; } else if ( !str_cmp( word, "END" ) ) break; else { log( "Load_ship_table: bad section." ); continue; } } fclose( fp ); } /* ******************************************************************* */ /* Special Procedures for buying ships */ /* ******************************************************************* */ SPECIAL(dock) { if (CMD_IS("list")) { int y; send_to_char("You can buy the following ships:\r\n", ch); for ( y = 0; y < top_ship_table; y++ ) ch_printf(ch, " %-20s %d\r\n", ship_table[y]->name, ship_table[y]->size * ship_table[y]->value.loads * 20); return (1); } if (CMD_IS("buy")) { SHIP_TYPE *tShip; PORT_DATA *port; SHIP_DATA *pShip; char arg[MAX_STRING_LENGTH], *shipname; int price, money; argument = one_argument( argument, arg ); shipname = strtok(argument, "'"); if (shipname == NULL) { send_to_char("Which name?\r\n", ch); return (1); } shipname = strtok(NULL, "'"); if (shipname == NULL) { send_to_char("Ship names must be enclosed in the Holy Magic Symbols: '\r\n", ch); return (1); } if ( !*arg || !*shipname ) { send_to_char("Usage: buy <type> 'ship name'\r\n", ch); return (1); } if (!(port = get_port_by_coord(ch->in_room->coord))) { log( "SYSERR: SPECIAL(dock) - No port found at coord %d %d.\r\n", GET_Y(ch), GET_X(ch) ); return (1); } /* get ship type */ if (!(tShip = parse_ship_type(arg))) { int y, price; ch_printf(ch, "Unknown ship type '%s'.\r\nYou can buy the following ships:\r\n", arg); for ( y = 0; y < top_ship_table; y++ ) { price = ship_table[y]->size * ship_table[y]->value.loads * 20; ch_printf(ch, " %40s %d\r\n", ship_table[y]->short_descr, price); } return (1); } /* Calc price & pay ship */ price = tShip->size * tShip->value.loads * 20; money = get_gold(ch) + GET_BANK_GOLD(ch); if ( price > money ) { ch_printf(ch, "You need %d gold coins to buy %s %s.\r\n", price, AN(tShip->name), tShip->name); if (IS_IMMORTAL(ch)) price = 0; else return (1); } if ( price > get_gold(ch) ) { int diff = price - get_gold(ch); sub_gold(ch, get_gold(ch)); GET_BANK_GOLD(ch) -= diff; } else sub_gold(ch, price); pShip = create_ship(ch, tShip, port, shipname); ship_to_room(pShip, ch->in_room); ch_printf(ch, "Now you are the owner and captain of %s %s named '%s'\r\n", AN(tShip->name), tShip->name, pShip->name); return (1); } return (0); } /* ******************************************************************* */ /* Ports & Courses */ /* ******************************************************************* */ PORT_DATA *get_port_by_name( char *name ) { PORT_DATA *port; if ( !port_table || !name ) return (NULL); for ( port = port_table; port; port = port->next ) if ( isname( name, port->name ) ) break; return (port); } PORT_DATA *get_port_by_coord( COORD_DATA *coord ) { PORT_DATA *port; if ( !port_table || !coord ) return (NULL); for ( port = port_table; port; port = port->next ) if ( coord->y == GET_RY(port) && coord->x == GET_RX(port) ) break; return (port); } char *get_port_name( COORD_DATA *coord ) { PORT_DATA *port = get_port_by_coord( coord ); if ( !port ) return ("None"); return ( port->name ); } /* * given port coordinates and the destination port, returns the course */ COURSE_DATA *get_course(COORD_DATA *orig, PORT_DATA *port_dest) { COURSE_DATA *course; if ( !course_table ) return (NULL); for ( course = course_table; course; course = course->next ) { if ( course->port_orig->y == orig->y && course->port_orig->x == orig->x && course->port_end->y == port_dest->coord->y && course->port_end->x == port_dest->coord->x ) break; } /* if not found, try the reverse course */ if ( !course ) { for ( course = rev_course_table; course; course = course->next ) { if ( course->port_orig->y == orig->y && course->port_orig->x == orig->x && course->port_end->y == port_dest->coord->y && course->port_end->x == port_dest->coord->x ) break; } } return (course); } COURSE_DATA *get_course_by_vnum( int vnum ) { COURSE_DATA *course; if ( !course_table ) return (NULL); for ( course = course_table; course; course = course->next ) if ( course->vnum == vnum ) break; return (course); } COURSE_STEP *get_course_step( COURSE_DATA *course, COORD_DATA *coord ) { COURSE_STEP *cstep; if ( !course || !coord ) return (NULL); for ( cstep = course->first_step; cstep; cstep = cstep->next ) if ( cstep->coord.y == coord->y && cstep->coord.x == coord->x ) break; return (cstep); } COURSE_DATA *fread_course( FILE *fp ) { COURSE_DATA *course; char *word; bool fMatch; CREATE( course, COURSE_DATA, 1 ); course->name = NULL; course->vnum = NOTHING; course->first_step = NULL; course->last_step = NULL; course->next = NULL; for ( ; ; ) { word = feof( fp ) ? "End" : fread_word( fp ); fMatch = FALSE; switch ( UPPER(word[0]) ) { case '*': fMatch = TRUE; fread_to_eol( fp ); break; case 'E': if ( !str_cmp( word, "End" ) ) { /* add to the list */ course->next = course_table; course_table = course; return (course); } break; case 'N': KEY( "Name", course->name, fread_string_nospace(fp) ); break; case 'P': if ( !str_cmp( word, "Port_Dest" ) ) { CREATE( course->port_end, COORD_DATA, 1 ); course->port_end->y = fread_number(fp); course->port_end->x = fread_number(fp); fMatch = TRUE; break; } if ( !str_cmp( word, "Port_Orig" ) ) { CREATE( course->port_orig, COORD_DATA, 1 ); course->port_orig->y = fread_number(fp); course->port_orig->x = fread_number(fp); fMatch = TRUE; break; } break; case 'S': if ( !str_cmp( word, "Step" ) ) { COURSE_STEP *cstep; CREATE( cstep, COURSE_STEP, 1 ); cstep->coord.y = fread_number(fp); cstep->coord.x = fread_number(fp); LINK( cstep, course->first_step, course->last_step, next, prev ); fMatch = TRUE; break; } break; case 'V': KEY( "Vnum", course->vnum, fread_number(fp) ); break; } } return (NULL); } void ReverseCourse( void ) { COURSE_DATA *cnew, *course; COURSE_STEP *cstep, *newstep; if ( !course_table ) return; log( "Inverting Courses table" ); for ( course = course_table; course; course = course->next ) { CREATE( cnew, COURSE_DATA, 1 ); cnew->name = str_dup(course->name); cnew->vnum = course->vnum; CREATE( cnew->port_orig, COORD_DATA, 1 ); CREATE( cnew->port_end, COORD_DATA, 1 ); cnew->port_orig->y = course->port_end->y; cnew->port_orig->x = course->port_end->x; cnew->port_end->y = course->port_orig->y; cnew->port_end->x = course->port_orig->x; for ( cstep = course->last_step; cstep; cstep = cstep->prev ) { CREATE( newstep, COURSE_STEP, 1 ); newstep->coord.y = cstep->coord.y; newstep->coord.x = cstep->coord.x; LINK( newstep, cnew->first_step, cnew->last_step, next, prev ); } cnew->next = rev_course_table; rev_course_table = cnew; } } void load_ports( void ) { FILE *fp; PORT_DATA *port; ROOM_DATA *pRoom; char fname[128]; char letter; char *word; sprintf(fname, "%sharbours.txt", SHIP_PREFIX); if (!(fp = fopen(fname, "r"))) { log( "Cannot open ports file %s", fname ); exit(0); } for ( ;; ) { letter = fread_letter( fp ); if ( letter == '*' ) { fread_to_eol( fp ); continue; } if ( letter != '#' ) { log( "load_ports: # not found." ); break; } word = fread_word( fp ); if ( !str_cmp( word, "HARBOUR" ) ) { CREATE(port, PORT_DATA, 1); CREATE(port->coord, COORD_DATA, 1); port->coord->y = fread_number(fp); port->coord->x = fread_number(fp); port->name = fread_string_nospace(fp); port->next = port_table; port_table = port; } else if ( !str_cmp( word, "COURSE" ) ) { fread_course( fp ); } else if ( !str_cmp( word, "END" ) ) break; else { log( "load_ports: bad section %s.", word ); continue; } } fclose( fp ); /* setup wild rooms as harbours */ for ( port = port_table; port; port = port->next ) { pRoom = create_wild_room(port->coord, TRUE); pRoom->func = dock; if ( SECT(pRoom) != SECT_PORT ) { put_sect( GET_RY(pRoom), GET_RX(pRoom), SECT_PORT, TRUE ); SECT(pRoom) = SECT_PORT; } } ReverseCourse(); } /* ******************************************************************* */ /* Player courses handling */ /* ******************************************************************* */ bool knows_course( CHAR_DATA *ch, int cnum ) { KNOWN_COURSE *kCourse; if (cnum < 0) return (FALSE); if (IS_IMMORTAL(ch) || IS_NPC(ch)) return (TRUE); for (kCourse = ch->player_specials->courses; kCourse; kCourse = kCourse->next) { if (kCourse->coursenum == cnum) break; } return (kCourse ? TRUE : FALSE); } int learn_course(CHAR_DATA *ch, int cnum) { KNOWN_COURSE *kCourse; if (cnum < 0) return (-1); if (knows_course(ch, cnum)) return (0); CREATE(kCourse, KNOWN_COURSE, 1); kCourse->coursenum = cnum; // add to the list kCourse->next = ch->player_specials->courses; ch->player_specials->courses = kCourse; return (1); } /* ******************************************************************* */ /* F E R R Y B O A T S */ /* ******************************************************************* */ FERRY_DATA *get_ferry(int vnum) { FERRY_DATA *pFerry; if (!first_ferry) return (NULL); for (pFerry = first_ferry; pFerry; pFerry = pFerry->next) { if (pFerry->vnum == vnum) break; } return (pFerry); } void ferry_to_port(FERRY_DATA *pFerry) { EXIT_DATA *fexit, *rexit; // link ferry to port fexit = make_exit(pFerry->room, NULL, DOWN); fexit->to_room = pFerry->in_room; rexit = make_exit(pFerry->in_room, NULL, UP); rexit->to_room = pFerry->room; } /* ***************************************************** */ EVENTFUNC(ferry_move_event) { FERRY_EVENT *fmove = (FERRY_EVENT *) (event_obj); FERRY_DATA *pFerry; EXIT_DATA *pexit; CHAR_DATA *ppl; ROOM_DATA *last_room; sh_int dir; pFerry = fmove->ferry; dir = fmove->dir; if (!pFerry || !pFerry->action) { free(event_obj); return (0); } pexit = get_exit(pFerry->in_room, dir); if (!pexit || !pexit->to_room) { free(event_obj); return (0); } send_to_room("The ferryboat has left.", pFerry->in_room); pFerry->in_room->ferryboat = NULL; last_room = pFerry->in_room; // stanziamolo.. pFerry->in_room = pexit->to_room; pFerry->in_room->ferryboat = pFerry; send_to_room("The ferryboat has arrived.", pFerry->in_room); /* Handle Wild Sectors */ if ( IS_WILD(pFerry->in_room) ) { check_wild_move( NULL, NULL, NULL, pFerry, last_room, pFerry->in_room ); if (ROOM_FLAGGED(pFerry->in_room, ROOM_WILD_REMOVE)) wild_remove_dequeue(pFerry->in_room); if (!ROOM_FLAGGED(pFerry->in_room, ROOM_WILD_STATIC)) SET_BIT(ROOM_FLAGS(pFerry->in_room), ROOM_WILD_STATIC); } for ( ppl = pFerry->room->people; ppl; ppl = ppl->next_in_room ) { if ( !FIGHTING(ppl) ) look_at_wild(ppl, TRUE); } // check for port at next step if (SECT(pFerry->in_room) == SECT_PORT) { send_to_room("The ferryboat has arrived in port. Go down to disembark.", pFerry->room); // setup ferry data pFerry->timer = FERRY_WAIT + number(-2, 3); pFerry->action = NULL; if (dir == pFerry->dir) pFerry->place = 2; else pFerry->place = 1; ferry_to_port(pFerry); return (0); } else if (!water_sector(SECT(pexit->to_room))) { log("SYSERR: ferry %d moved in a non-water sector.", pFerry->vnum); free(event_obj); return(0); } send_to_room("The ferryboat moves...", pFerry->room); // yet another step return (FERRY_SPEED); } /* * called every minute from heartbeat() in comm.c */ void ferry_move(void) { FERRY_DATA *pFerry; FERRY_EVENT *fmove; sh_int dir; if (!first_ferry) return; for (pFerry = first_ferry; pFerry; pFerry = pFerry->next) { // if action is not null, the ferry is moving... if (pFerry->action) continue; // countdown to departure if (--pFerry->timer > 0) continue; // reverse dir for sailing from site2 to site1 if (pFerry->place == 2) dir = rev_dir[pFerry->dir]; else dir = pFerry->dir; extract_exit(pFerry->room, get_exit(pFerry->room, DOWN)); extract_exit(pFerry->in_room, get_exit(pFerry->in_room, UP)); // initialize ferry move event CREATE(fmove, FERRY_EVENT, 1); fmove->ferry = pFerry; fmove->dir = dir; // create event pFerry->action = event_create(ferry_move_event, fmove, FERRY_SPEED); send_to_room("The ferryboat leave the port and begin to cross the river.\r\n", pFerry->room); send_to_room("The ferryboat leave the port and begin to cross the river.\r\n", pFerry->in_room); } } /* ********************************************************* */ FERRY_DATA *new_ferry(void) { FERRY_DATA *pFerry; CREATE(pFerry, FERRY_DATA, 1); pFerry->action = NULL; pFerry->in_room = NULL; pFerry->mob = NULL; pFerry->next = NULL; pFerry->prev = NULL; pFerry->vnum = NOTHING; pFerry->cost = 0; pFerry->dir = NOWHERE; // default values pFerry->place = 1; pFerry->timer = FERRY_WAIT; // setup ferry room pFerry->room = new_room(); pFerry->room->name = str_dup("Aboard the ferryboat"); pFerry->room->sector_type = SECT_FERRY_DECK; pFerry->room->zone = FERRY_ZONE; pFerry->room->description = str_dup(" You are aboard the ferryboat.\r\n"); CREATE(pFerry->room->extra_data, ROOM_EXTRA, 1); pFerry->room->extra_data->max_hp = 50; pFerry->room->extra_data->curr_hp = 50; return (pFerry); } bool fread_one_ferry(FERRY_DATA *pFerry, FILE *fp) { char *word; bool fMatch; for ( ; ; ) { word = feof( fp ) ? "End" : fread_word( fp ); fMatch = FALSE; switch ( UPPER(word[0]) ) { case '*': fMatch = TRUE; fread_to_eol( fp ); break; case 'C': if (!strcmp(word, "Coord")) { fMatch = TRUE; CREATE(pFerry->coord, COORD_DATA, 1); pFerry->coord->y = fread_number(fp); pFerry->coord->x = fread_number(fp); if (!get_port_by_coord(pFerry->coord)) { log("SYSERR: ferryboat must load in a port."); return (FALSE); } break; } KEY("Cost", pFerry->cost, fread_number(fp)); break; case 'D': KEY("Dir", pFerry->dir, fread_number(fp)); break; case 'E': if (!strcmp(word, "End")) return (TRUE); break; case 'M': if (!strcmp(word, "Mob")) { int vnum = fread_number(fp); if (!(pFerry->mob = read_mobile(vnum, VIRTUAL))) log("SYSERR: ferryboat's mob has invalid vnum %d.", vnum); fMatch = TRUE; break; } break; case 'V': if (!strcmp(word, "Vnum")) { pFerry->vnum = fread_number(fp); pFerry->room->extra_data->vnum = pFerry->vnum; fMatch = TRUE; break; } break; } } return (FALSE); } FERRY_DATA *fread_ferry( char *sname ) { FILE *fp; FERRY_DATA *pFerry; char fname[128]; char letter; char *word; sprintf( fname, "%s%s", LIB_SHIPS, sname ); if ( !( fp = fopen(fname, "r") ) ) return (NULL); pFerry = new_ferry(); for ( ;; ) { letter = fread_letter( fp ); if ( letter == '*' ) { fread_to_eol( fp ); continue; } if ( letter != '#' ) { log( "fread_ferry(): # not found." ); break; } word = fread_word( fp ); if ( !str_cmp( word, "FERRY" ) ) { if ( !fread_one_ferry( pFerry, fp ) ) { fclose(fp); return (NULL); } } else if (!str_cmp(word, "END")) break; else { log( "fread_ferry(): bad section." ); continue; } } fclose( fp ); return (pFerry); } /* load all saved rooms */ void LoadFerryboats( void ) { FILE *fp; FERRY_DATA *pFerry; char fname[128]; sprintf(fname, "%sferryindex", LIB_SHIPS); if ( !( fp = fopen(fname, "r") ) ) return; while (!feof(fp)) { char ferryname[128]; strcpy(ferryname, fread_word(fp)); if (ferryname[0] == '$') break; if (!( pFerry = fread_ferry(ferryname))) log("SYSERR: LoadFerryboats() unable to read ferry file %s.", ferryname); else { ROOM_DATA *pRoom; // add to the list LINK(pFerry, first_ferry, last_ferry, next, prev); /* place in the world */ if (!(pRoom = get_wild_room(pFerry->coord))) { log("SYSERR: LoadFerryboats() - port room must exist!"); exit(1); } pRoom->ferryboat = pFerry; pFerry->in_room = pRoom; if (pFerry->mob) char_to_room(pFerry->mob, pFerry->room); ferry_to_port(pFerry); } } fclose (fp); }