AwakeMUD-0.8.18B/
AwakeMUD-0.8.18B/doc/
AwakeMUD-0.8.18B/lib/
AwakeMUD-0.8.18B/lib/etc/
AwakeMUD-0.8.18B/lib/etc/pfiles/
AwakeMUD-0.8.18B/lib/misc/
AwakeMUD-0.8.18B/lib/text/
AwakeMUD-0.8.18B/lib/text/help/
AwakeMUD-0.8.18B/lib/text/wizhelp/
AwakeMUD-0.8.18B/lib/veh/
AwakeMUD-0.8.18B/lib/world/
AwakeMUD-0.8.18B/lib/world/mob/
AwakeMUD-0.8.18B/lib/world/mtx/
AwakeMUD-0.8.18B/lib/world/qst/
AwakeMUD-0.8.18B/lib/world/shp/
AwakeMUD-0.8.18B/lib/world/veh/
/* **********************************************************************
*  file: transport.cc                                                   *
*  author: Andrew Hynek                                                 *
*  (original monorail code, now deleted, written by Chris Dickey)       *
*  purpose: contains all routines for time- and command-based transport *
*  Copyright (c) 1998 by Andrew Hynek                                   *
*  (c) 2001 The AwakeMUD Consortium                                     *
********************************************************************** */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>

#if defined(WIN32) && !defined(__CYGWIN__)
#define strcasecmp(x, y) _stricmp(x,y)
#else
#endif

#include "structs.h"
#include "awake.h"
#include "utils.h"
#include "comm.h"
#include "interpreter.h"
#include "handler.h"
#include "db.h"
#include "transport.h"
#include "utils.h"
#include "constants.h"

SPECIAL(call_elevator);
SPECIAL(elevator_spec);
extern int find_first_step(vnum_t src, vnum_t target);
// ----------------------------------------------------------------------------

// ______________________________
//
// static vars
// ______________________________

static struct elevator_data *elevator = NULL;
static int num_elevators = 0;

static const int NUM_SEATTLE_STATIONS = 6;
static const int NUM_SEATAC_STATIONS = 4;

static struct dest_data destinations[] =
  {
    { "tacoma", "Tacoma", 2000 },
    { "afterlife", "The Afterlife", 2072 },
    { "chinatown", "ChinaTown", 2527 },
    { "evergreen", "Evergreen Complex", 2201 },
    { "twe", "Tacoma Weapons Emporium", 2514 },
    { "nybbles", "Nybbles and Bytes", 2057 },
    { "biohyde", "Biohyde Complex", 4201 },
    { "puyallup", "Central Puyallup", 2457 },
    { "park", "Seattle State Park", 4000 },
    { "seattle", "Seattle", 32679 },
    { "cinema", "Le Cinema Vieux", 32588 },
    { "vieux", "Le Cinema Vieux", 32588 },
    { "charne", "La Charne", 30548 },
    { "tarislar", "Tarislar", 4965 },
    { "reaper", "The Reaper", 32517 },
    { "platinum", "Platinum Club", 32685 },
    { "penumbra", "Club Penumbra", 32587 },
    { "big", "The Big Rhino", 32635 },
    { "epicenter", "The Epicenter", 2418 },
    { "yoshi", "Yoshi's Sushi Bar", 32751 },
    { "airport", "Seattle-Tacoma Airport", 19410 },
    { "aztech",  "Aztechnology Pyramid", 30539 },
    { "garage", "Seattle Parking Garage", 32720 },
    { "formal", "Seattle Formal Wear", 32746 },
    { "sda", "The SDA Plaza", 30610 },
    { "dante", "Dante's Inferno", 32661 },
    { "quinns", "Quinn's", 32521 },
    { "shintaru", "Shintaru", 32513 },
    { "docks", "Seattle Dockyards", 32500 },
    { "modern", "Modern Magik", 30514 },
    { "methodist", "Seattle First Methodist", 30565 },
    { "sculleys", "Sculleys", 30591 },
    { "council", "Council Island", 9149 },
    { "moonlight", "Moonlight Mall", 14373 },
    { "library", "Seattle Public Library", 30600 },
    { "kristins", "Kristin's", 30578 },
    { "mitsuhama", "Mitsuhama Towers", 32722 },
    { "chiba", "Little Chiba", 32686 },
    { "stop", "The Stop Gap", 32708 },
    { "apartment", "Redmond Apartment Block", 14337 },
    { "humana", "Humana Hospital", 2536 },
    { "hospital", "Council Island Hospital", 9161 },
    { "coffin", "Tacoma Coffin Hotel", 2045 },
    { "diver", "Easy Diver Coffin Hotel", 32644 },
    { "action", "Action Computers", 32650 },
    { "hellhound", "Hellhound Bus Stop",  32501 },
    { "lysleul", "Lysleul Plaza", 30551 },
    { "novatech", "Novatech Seattle", 32541 },
    { "syberspace", "SyberSpace", 30612 },
    { "bank", "UCASBank", 30524 },
    { "matchsticks", "Matchsticks", 30579 },
    { "homewood", "Homewood Suites", 30512 },
    { "mall", "Tacoma Mall", 2093 },
    { "racespec", "Racespec Performance", 30573 },
    { "smiths", "Smith's Pub", 32566 },
    { "\n", "", 0 } // this MUST be last
  };

static struct dest_data port_destinations[] =
  {
    { "hellhound", "Hellhound Bus Station", 14624 },
    { "postal", "Royal Postal Station", 14629 },
    { "trans-oregon", "Trans-Oregon Trucking", 14604 },
    { "thompson", "Thompson Autogroup",  14602},
    { "hard", "Hard Times", 14608 },
    { "bank", "TT-Bank", 14610 },
    { "sixth", "Sixth Street Parking", 14680 },
    { "satyricon", "The Satyricon", 14611 },
    { "rocco", "Rocco's Pizza", 14730 },
    { "annabel", "Annabel's Antiquities", 2710 },
    { "square", "O'Bryant Square", 2708 },
    { "parking", "Portland City Parking", 2703 },
    { "mary", "Mary's Bar", 14712 },
    { "tower", "TTBank Tower", 14743 },
    { "city", "City Center Parking", 14751 },
    { "habitat", "Telestrian Habitat", 18800 },
    { "hospital", "Royal Hospital", 14707 },
    { "toadstool", "The Toadstool", 14671 },
    { "powells", "Powell's Technical Books", 14724 },
    { "davis", "Davis Street Offices", 14667 },
    { "max", "Downtown MAX Station", 20800 },
    { "\n", "", 0 } // this MUST be last
 
  };

struct transport_type
{
  vnum_t transport;
  dir_t to;
  vnum_t room;
  dir_t from;
};

static struct transport_type seatac[NUM_SEATAC_STATIONS] =
  {
    { 501, SOUTH, 3018, NORTH },
    { 501, EAST, 29036, WEST },
    { 501, EAST, 9823, WEST },
    { 501, EAST, 29036, WEST },
  };
/*
static struct transport_type seattle[NUM_SEATTLE_STATION] =
  {
    { 502, SOUTH, 9824, NORTH },
  }
*/
// ______________________________
//
// func prototypes
// ______________________________

SPECIAL(taxi);
static int process_elevator(struct room_data *room,
                            struct char_data *ch,
                            int cmd,
                            char *argument);

// ____________________________________________________________________________
//
// Taxi
// ____________________________________________________________________________

// ______________________________
//
// utility funcs
// ______________________________

static void open_taxi_door(vnum_t room, int dir, int taxi)
{
  world[room].dir_option[dir] = new room_direction_data;
  memset((char *) world[room].dir_option[dir], 0,
         sizeof (struct room_direction_data));
  world[room].dir_option[dir]->to_room = taxi;
  world[room].dir_option[dir]->barrier = 8;
  world[room].dir_option[dir]->condition = 8;
  world[room].dir_option[dir]->material = 8;

  dir = rev_dir[dir];

  world[taxi].dir_option[dir] = new room_direction_data;
  memset((char *) world[taxi].dir_option[dir], 0,
         sizeof (struct room_direction_data));
  world[taxi].dir_option[dir]->to_room = room;
  world[taxi].dir_option[dir]->barrier = 8;
  world[taxi].dir_option[dir]->condition = 8;
  world[taxi].dir_option[dir]->material = 8;
}

static void close_taxi_door(int room, int dir, int taxi)
{
  if (world[room].dir_option[dir]->keyword)
    delete [] world[room].dir_option[dir]->keyword;
  if (world[room].dir_option[dir]->general_description)
    delete [] world[room].dir_option[dir]->general_description;
  delete world[room].dir_option[dir];
  world[room].dir_option[dir] = NULL;

  dir = rev_dir[dir];

  if (world[taxi].dir_option[dir]->keyword)
    delete [] world[taxi].dir_option[dir]->keyword;
  if (world[taxi].dir_option[dir]->general_description)
    delete [] world[taxi].dir_option[dir]->general_description;
  delete world[taxi].dir_option[dir];
  world[taxi].dir_option[dir] = NULL;
}

void taxi_leaves(void)
{
  int i, j, found = 0, to;
  struct char_data *temp;
  for (j = real_room(FIRST_CAB); j <= real_room(LAST_PORTCAB); j++) {
    found = 0;
    for (temp = world[j].people; temp; temp = temp->next_in_room)
      if (!(GET_MOB_SPEC(temp) && GET_MOB_SPEC(temp) == taxi)) {
        found = 1;
        break;
      }
    if (found)
      continue;
    for (i = NORTH; i < UP; i++)
      if (world[j].dir_option[i]) {
        to = world[j].dir_option[i]->to_room;
        close_taxi_door(to, rev_dir[i], j);
        if (world[to].people) {
          if (j >= real_room(FIRST_PORTCAB))
            sprintf(buf, "The taxi doors slide shut and it pulls off from the kerb.");
          else sprintf(buf, "The taxi door slams shut as its wheels churn up a cloud of smoke.");
          act(buf, FALSE, world[to].people, 0, 0, TO_ROOM);
          act(buf, FALSE, world[to].people, 0, 0, TO_CHAR);
        }
        if (world[j].people)
          act("The door automatically closes.",
              FALSE, world[j].people, 0, 0, TO_CHAR);
      }
    if (j == LAST_CAB)
      j = FIRST_PORTCAB - 1;
  }
}

// ______________________________
//
// hail command
// ______________________________

ACMD(do_hail)
{
  struct char_data *temp;
  int cab, dir, first, last, i = -1;
  bool found = FALSE, empty = FALSE, portland = FALSE;
  SPECIAL(taxi);

  for (dir = NORTH; dir < UP; dir++)
    if (!world[ch->in_room].dir_option[dir])
      empty = TRUE;

  if (IS_ASTRAL(ch)) {
    send_to_char("Magically active cab drivers...now I've heard everything...\n\r",ch);
    return;
  }

  if (world[ch->in_room].sector_type != SPIRIT_CITY || !empty ||
      ROOM_FLAGGED(ch->in_room, ROOM_INDOORS)) {
    send_to_char("There doesn't seem to be any cabs in the area.\r\n", ch);
    return;
  }

  if ( (i = IN_ROOM(ch)) > -1 ) {
    switch (zone_table[world[i].zone].number) {
    case 13:
    case 15:
    case 20:
    case 22:
    case 23:
    case 24:
    case 25:
    case 26:
    case 29:
    case 30:
    case 32:
    case 38:
    case 40:
    case 42:
    case 45:
    case 49:
    case 74:
    case 91:
    case 143:
    case 194:
    case 290:
    case 293:
    case 301:
    case 305:
    case 325:
    case 707:
      break;
    case 27:
    case 146:
    case 188:
    case 208:
    case 241:
      portland = TRUE;
      break;
    default:
      /* Cab doesn't service the area */
      send_to_char("There don't seem to be any cabs in the area.\n\r",ch);
      return;
    }
  }

  if (AFF_FLAGS(ch).AreAnySet(AFF_SPELLINVIS, AFF_INVISIBLE, AFF_SPELLIMPINVIS, AFF_IMP_INVIS, ENDBIT))  {
    send_to_char("A cab almost stops, but guns it at the last second, splashing you...\n\r",ch);
    return;
  }

    first = real_room(portland ? FIRST_PORTCAB : FIRST_CAB);
    last = real_room(portland ? LAST_PORTCAB : LAST_CAB);

  for (cab = first; cab <= last; cab++) {
    for (temp = world[cab].people; temp; temp = temp->next_in_room)
      if (!(GET_MOB_SPEC(temp) && GET_MOB_SPEC(temp) == taxi))
        break;
    if (!temp) {
      found = TRUE;
      for (dir = NORTH; dir < UP; dir++)
        if (world[cab].dir_option[dir])
          found = FALSE;
      if (found)
        break;
    }
  }

  if (!found) {
    send_to_char("Hail as you might, no cab answers.\r\n", ch);
    return;
  }

  for (dir = number(NORTH, UP - 1);; dir = number(NORTH, UP - 1))
    if (!world[ch->in_room].dir_option[dir]) {
      open_taxi_door(ch->in_room, dir, cab);
      if (portland)
      sprintf(buf, "A nice looking red and white cab pulls up smoothly to the kerb, "
              "and its door opens to the %s.", fulldirs[dir]);
      else sprintf(buf, "A beat-up yellow cab screeches to a halt, "
              "and its door opens to the %s.", fulldirs[dir]);
      act(buf, FALSE, ch, 0, 0, TO_ROOM);
      act(buf, FALSE, ch, 0, 0, TO_CHAR);
      return;
    }
}

// ______________________________
//
// driver spec
// ______________________________

SPECIAL(taxi)
{
  extern bool memory(struct char_data *ch, struct char_data *vict);
  ACMD(do_say);
  ACMD(do_action);

  struct char_data *temp = NULL, *driver = (struct char_data *) me;
  int comm = CMD_NONE, i = 0, j;
  char say[MAX_STRING_LENGTH];
  vnum_t dest = 0;
  bool portland = FALSE;
  if (GET_MOB_VNUM(driver) == 650)
    portland = TRUE;
  if (!cmd) {
    for (temp = world[driver->in_room].people; temp; temp = temp->next_in_room)
      if (temp != driver && memory(driver, temp))
        break;
    if (!temp) {
      GET_SPARE1(driver) = 0;
      GET_SPARE2(driver) = 0;
      GET_ACTIVE(driver) = ACT_AWAIT_CMD;
    } else
      switch (GET_ACTIVE(driver)) {
      case ACT_REPLY_DEST:
        if (portland)
          sprintf(say, "%s?  Sure, that will be %d nuyen.",
                  port_destinations[GET_SPARE2(driver)].str, (int)GET_SPARE1(driver));
        else sprintf(say, "%s?  Yeah, sure...it'll cost ya %d nuyen, whaddya say?",
                  destinations[GET_SPARE2(driver)].str, (int)GET_SPARE1(driver));
        do_say(driver, say, 0, 0);
        if (GET_EXTRA(driver) == 1) {
          do_say(driver, "But seeing as you're new around here, I'll waive my usual fee, okay?", 0, 0);
          GET_SPARE1(driver) = 0;
        }
        GET_EXTRA(driver) = 0;
        GET_ACTIVE(driver) = ACT_AWAIT_YESNO;
        break;
      case ACT_REPLY_NOTOK:
        if (portland)
          do_say(driver, "You don't seem to have enough nuyen!", 0, 0);
        else do_say(driver, "Ya ain't got the nuyen!", 0, 0);
        forget(driver, temp);
        GET_SPARE1(driver) = 0;
        GET_SPARE2(driver) = 0;
        GET_ACTIVE(driver) = ACT_AWAIT_CMD;
        break;
      case ACT_REPLY_TOOBAD:
        if (portland)
          do_say(driver, "Somewhere else then, chummer?", 0, 0);
        else do_say(driver, "Whatever, chum.", 0, 0);
        forget(driver, temp);
        GET_SPARE1(driver) = 0;
        GET_SPARE2(driver) = 0;
        GET_ACTIVE(driver) = ACT_AWAIT_CMD;
        break;
      case ACT_DRIVING:
        if (GET_SPARE1(driver) > 0)
          GET_SPARE1(driver)--;
        else {
          int x[] = { 0, 0, 0, 0, 0, 0, 0, 0 }, y = 0;
          for (j = number(NORTH, NORTHWEST);; j = number(NORTH, NORTHWEST)) {
            if (!x[j]) {
              x[j] = 1;
              y++;
            }
            if (y == NORTHWEST)
              return FALSE;
            dest = real_room(GET_SPARE2(driver));
            if (!world[dest].dir_option[j]) {
              open_taxi_door(dest, j, driver->in_room);
              do_say(driver, "Ok, here we are.", 0, 0);
              forget(driver, temp);
              GET_SPARE2(driver) = 0;
              GET_ACTIVE(driver) = ACT_AWAIT_CMD;
              if (world[dest].people) {
                act("A taxi pulls to a stop, its door sliding open.",
                    FALSE, world[dest].people, 0, 0, TO_ROOM);
                act("A taxi pulls to a stop, its door sliding open.",
                    FALSE, world[dest].people, 0, 0, TO_CHAR);
              }
              sprintf(buf, "The door, rather noisily, slides open to the %s.",
                      fulldirs[rev_dir[j]]);
              act(buf, FALSE, driver, 0, 0, TO_ROOM);
              act(buf, FALSE, driver, 0, 0, TO_CHAR);
              break;
            }
          }
        }
        break;
      }
    return FALSE;
  }

  if (!IS_NPC(ch) && memory(driver, ch) && (CMD_IS("north") ||
      CMD_IS("east") || CMD_IS("west") || CMD_IS("south") || CMD_IS("ne") ||
      CMD_IS("se") || CMD_IS("sw") || CMD_IS("nw") || CMD_IS("northeast") ||
      CMD_IS("southeast") || CMD_IS("southwest") || CMD_IS("northwest")) && GET_ACTIVE(driver) != ACT_DRIVING) {
    forget(driver, ch);
    return FALSE;
  }

  if (!CAN_SEE(driver, ch) || IS_NPC(ch) ||
      (GET_ACTIVE(driver) != ACT_AWAIT_CMD &&
       GET_ACTIVE(driver) != ACT_AWAIT_YESNO))
    return FALSE;

  skip_spaces(&argument);

  if (CMD_IS("say") || CMD_IS("'")) {
    bool found = FALSE;
    if (GET_ACTIVE(driver) == ACT_AWAIT_CMD)
      for (dest = 0; (portland ? *port_destinations[dest].keyword : *destinations[dest].keyword) != '\n'; dest++)
        if ( str_str((const char *)argument, (portland ? port_destinations[dest].keyword : destinations[dest].keyword))) {
          comm = CMD_DEST;
          found = TRUE;
          break;
        }
    if (!found) {
      if (str_str(argument, "yes") || str_str(argument, "sure") ||
          str_str(argument, "yea") || str_str(argument, "okay"))
        comm = CMD_YES;
      else if (strstr(argument, "no"))
        comm = CMD_NO;
    }
    do_say(ch, argument, 0, 0);
  } else if (CMD_IS("nod")) {
    comm = CMD_YES;
    do_action(ch, argument, cmd, 0);
  } else if (CMD_IS("shake") && !*argument) {
    comm = CMD_NO;
    do_action(ch, argument, cmd, 0);
  } else
    return FALSE;

  if (comm == CMD_DEST && !memory(driver, ch) &&
      (i = real_room(GET_LASTROOM(ch))) > -1 &&
      GET_ACTIVE(driver) == ACT_AWAIT_CMD) {
    for (i = NORTH; i < UP; i++)
      if (world[ch->in_room].dir_option[i]) {
        i = world[ch->in_room].dir_option[i]->to_room;
        break;
      }
    int dist = 0;
    while (i != -1) {
      int x = find_first_step(i, real_room((portland ? port_destinations[dest].vnum : destinations[dest].vnum)));
      if (x == -2)
        break;
      else if (x < 0) {
        i = -1;
        break;
      }
      i = world[i].dir_option[x]->to_room;
      dist++;
    }
    if (i == -1)
      GET_SPARE1(driver) = 250;
    else
      GET_SPARE1(driver) = MIN(250, 5 + dist);
    GET_SPARE2(driver) = dest;
    GET_ACTIVE(driver) = ACT_REPLY_DEST;
    if (PLR_FLAGGED(ch, PLR_NEWBIE))
      GET_EXTRA(driver) = 1;
    else GET_EXTRA(driver) = 0;
    remember(driver, ch);
  } else if (comm == CMD_YES && memory(driver, ch) &&
             GET_ACTIVE(driver) == ACT_AWAIT_YESNO) {
    if (GET_NUYEN(ch) < GET_SPARE1(driver) && !IS_SENATOR(ch)) {
      GET_ACTIVE(driver) = ACT_REPLY_NOTOK;
      return TRUE;
    }
    if (!IS_SENATOR(ch))
      GET_NUYEN(ch) -= GET_SPARE1(driver);
    GET_SPARE1(driver) = (int)(GET_SPARE1(driver) / 50);
    GET_SPARE2(driver) = portland ? port_destinations[GET_SPARE2(driver)].vnum : destinations[GET_SPARE2(driver)].vnum;
    GET_ACTIVE(driver) = ACT_DRIVING;

    for (i = NORTH; i < UP; i++)
      if (world[ch->in_room].dir_option[i]) {
        dest = world[ch->in_room].dir_option[i]->to_room;
        close_taxi_door(dest, rev_dir[i], ch->in_room);
        if (world[dest].people) {
          if (portland)
            sprintf(buf, "The taxi doors slide shut and it pulls off from the kerb.");
          else sprintf(buf, "The taxi door slams shut as its wheels churn up a cloud of smoke.");
          act(buf, FALSE, world[dest].people, 0, 0, TO_ROOM);
          act(buf, FALSE, world[dest].people, 0, 0, TO_CHAR);
        }
        act("The door shuts as the taxi begins to accelerate.",
            FALSE, ch, 0, 0, TO_ROOM);
        act("The door shuts as the taxi begins to accelerate.",
            FALSE, ch, 0, 0, TO_CHAR);
      }
  } else if (comm == CMD_NO && memory(driver, ch) &&
             GET_ACTIVE(driver) == ACT_AWAIT_YESNO)
    GET_ACTIVE(driver) = ACT_REPLY_TOOBAD;

  return TRUE;
}

// ______________________________
//
// Elevators
// ______________________________

// ______________________________
//
// utility funcs
// ______________________________

static void init_elevators(void)
{
  FILE *fl;
  char line[256];
  int i, j, t[3];
  vnum_t room[1], rnum;
  if (!(fl = fopen(ELEVATOR_FILE, "r"))) {
    log("Error opening elevator file.");
    shutdown();
  }

  if (!get_line(fl, line) || sscanf(line, "%d", &num_elevators) != 1) {
    log("Error at beginning of elevator file.");
    shutdown();
  }

  elevator = new struct elevator_data[num_elevators];

  for (i = 0; i < num_elevators && !feof(fl); i++) {
    get_line(fl, line);
    if (sscanf(line, "%ld %d %d %d", room, t, t + 1, t + 2) != 4) {
      fprintf(stderr, "Format error in elevator #%d, expecting # # # #\n", i);
      shutdown();
    }
    elevator[i].room = room[0];
    if ((rnum = real_room(elevator[i].room)) > -1) {
      world[rnum].func = elevator_spec;
      world[rnum].rating = 0;
    } else
      log("Nonexistent elevator.");
    elevator[i].columns = t[0];
    elevator[i].time_left = 0;
    elevator[i].dir = -1;
    elevator[i].destination = 0;
    elevator[i].num_floors = t[1];
    elevator[i].start_floor = t[2];

    if (elevator[i].num_floors > 0) {
      elevator[i].floor = new struct floor_data[elevator[i].num_floors];
      for (j = 0; j < elevator[i].num_floors; j++) {
        get_line(fl, line);
        if (sscanf(line, "%ld %d", room, t + 1) != 2) {
          fprintf(stderr, "Format error in elevator #%d, floor #%d\n", i, j);
          shutdown();
        }
        elevator[i].floor[j].vnum = room[0];
        if ((rnum = real_room(elevator[i].floor[j].vnum)) > -1)
          world[rnum].func = call_elevator;
        else {
          elevator[i].floor[j].vnum = -1;
          log("Nonexistent elevator destination -- blocking.");
        }
        elevator[i].floor[j].doors = t[1];
      }
    } else
      elevator[i].floor = NULL;
  }
  fclose(fl);
}

static void open_elevator_doors(struct room_data *room, int num, int floor)
{
  int dir;
  long rnum;

  rnum = real_room(elevator[num].floor[floor].vnum);
  dir = elevator[num].floor[floor].doors;

  room->dir_option[dir] = new room_direction_data;
  memset((char *) room->dir_option[dir], 0, sizeof (struct room_direction_data));
  room->dir_option[dir]->to_room = rnum;
  room->dir_option[dir]->barrier = 8;
  room->dir_option[dir]->condition = 8;
  room->dir_option[dir]->material = 8;

  dir = rev_dir[dir];

  world[rnum].dir_option[dir] = new room_direction_data;
  memset((char *) world[rnum].dir_option[dir], 0, sizeof (struct room_direction_data));
  world[rnum].dir_option[dir]->to_room = real_room(room->number);
  world[rnum].dir_option[dir]->barrier = 8;
  world[rnum].dir_option[dir]->condition = 8;
  world[rnum].dir_option[dir]->material = 8;

  elevator[num].dir = UP - 1;
  if (world[rnum].people)
  {
    sprintf(buf, "The elevator doors open to the %s.", fulldirs[dir]);
    act(buf, FALSE, world[rnum].people, 0, 0, TO_ROOM);
    act(buf, FALSE, world[rnum].people, 0, 0, TO_CHAR);
  }
}

static void close_elevator_doors(struct room_data *room, int num, int floor)
{
  long rnum;
  int dir;

  dir = elevator[num].floor[floor].doors;
  rnum = room->dir_option[dir]->to_room;

  if (room->dir_option[dir]->keyword)
    delete [] room->dir_option[dir]->keyword;
  if (room->dir_option[dir]->general_description)
    delete [] room->dir_option[dir]->general_description;
  delete room->dir_option[dir];
  room->dir_option[dir] = NULL;

  dir = rev_dir[dir];

  if (world[rnum].dir_option[dir]->keyword)
    delete [] world[rnum].dir_option[dir]->keyword;
  if (world[rnum].dir_option[dir]->general_description)
    delete [] world[rnum].dir_option[dir]->general_description;
  delete world[rnum].dir_option[dir];
  world[rnum].dir_option[dir] = NULL;

  if (world[rnum].people)
  {
    act("The elevator doors close.",
        FALSE, world[rnum].people, 0, 0, TO_ROOM);
    act("The elevator doors close.",
        FALSE, world[rnum].people, 0, 0, TO_CHAR);
  }
}

// ______________________________
//
// elevator lobby / call-button spec
// ______________________________

SPECIAL(call_elevator)
{
  int i = 0, j, index = -1;
  long rnum;
  if (!cmd)
    return FALSE;

  for (i = 0; i < num_elevators && index < 0; i++)
    for (j = 0; j < elevator[i].num_floors && index < 0; j++)
      if (elevator[i].floor[j].vnum == world[ch->in_room].number)
        index = i;

  if (CMD_IS("push")) {
    skip_spaces(&argument);
    if (!*argument || !(!strcasecmp("elevator", argument) ||
                        !strcasecmp("button", argument)))
      send_to_char("Press what?\r\n", ch);
    else {
      if (IS_ASTRAL(ch)) {
        send_to_char("You can't do that in your current state.\r\n", ch);
        return TRUE;
      }
      if (index < 0 || elevator[index].destination) {
        send_to_char("You press the call button, "
                     "but nothing seems to happen.\r\n", ch);
        return TRUE;
      }
      rnum = real_room(elevator[index].room);
      for (i = 0; i < UP; i++)
        if (world[rnum].dir_option[i] &&
            world[rnum].dir_option[i]->to_room == ch->in_room) {
          send_to_char("The door is already open!\r\n", ch);
          elevator[index].destination = 0;
          return TRUE;
        }
      send_to_char("You press the call button, "
                   "and the small light turns on.\r\n", ch);
      elevator[index].destination = world[ch->in_room].number;
    }
    return TRUE;
  }

  if (CMD_IS("look")) {
    one_argument(argument, arg);
    if (!*arg || index < 0 || !(!strcasecmp("panel", arg) ||
                                !strcasecmp("elevator", arg)))
      return FALSE;

    rnum = real_room(elevator[index].room);

    i = world[rnum].rating + 1 - elevator[index].num_floors - elevator[index].start_floor;
    if (i > 0)
      send_to_char(ch, "The floor indicator shows that the elevator is "
                   "currently at B%d.\r\n", i);
    else if (i == 0)
      send_to_char(ch, "The floor indicator shows that the elevator is "
                   "currently at the ground floor.\r\n");
    else
      send_to_char(ch, "The floor indicator shows that the elevator is "
                   "current at floor %d.\r\n", 0 - i);
    return TRUE;
  }

  return FALSE;
}

// ______________________________
//
// elevator spec
// ______________________________

SPECIAL(elevator_spec)
{
  struct room_data *room = (struct room_data *) me;

  if (cmd && process_elevator(room, ch, cmd, argument))
    return TRUE;

  return FALSE;
}

// ______________________________
//
// processing funcs
// ______________________________

static int process_elevator(struct room_data *room,
                            struct char_data *ch,
                            int cmd,
                            char *argument)
{
  int num, temp, number, floor = 0;

  for (num = 0; num < num_elevators; num++)
    if (elevator[num].room == room->number)
      break;

  if (num >= num_elevators)
    return 0;

  if (!cmd)
  {
    if (elevator[num].destination && elevator[num].dir == -1) {
      for (temp = 0; temp <= elevator[num].num_floors; temp++)
        if (elevator[num].floor[temp].vnum == elevator[num].destination)
          floor = temp;
      if (floor >= room->rating) {
        elevator[num].dir = DOWN;
        elevator[num].time_left = floor - room->rating;
      } else if (floor < room->rating) {
        elevator[num].dir = UP;
        elevator[num].time_left = room->rating - floor;
      }
      elevator[num].destination = 0;
    }
    if (elevator[num].time_left > 0) {
      elevator[num].time_left--;
      if (elevator[num].dir == DOWN)
        room->rating++;
      else
        room->rating--;
    } else if (elevator[num].dir == UP || elevator[num].dir == DOWN) {
      temp = room->rating + 1 - elevator[num].num_floors - elevator[num].start_floor;
      if (temp > 0)
        sprintf(buf, "The elevator stops at B%d, "
                "and the doors open to the %s.", temp,
                fulldirs[elevator[num].floor[room->rating].doors]);
      else if (temp == 0)
        sprintf(buf, "The elevator stops at the ground floor, "
                "and the doors open to the %s.", fulldirs[elevator[num].floor[room->rating].doors]);
      else
        sprintf(buf, "The elevator stops at floor %d, "
                "and the doors open to the %s.", 0 - temp,
                fulldirs[elevator[num].floor[room->rating].doors]);
      if (room->people) {
        act(buf, FALSE, room->people, 0, 0, TO_ROOM);
        act(buf, FALSE, room->people, 0, 0, TO_CHAR);
      }
      open_elevator_doors(room, num, room->rating);
    } else if (elevator[num].dir > 0)
      elevator[num].dir--;
    else if (!elevator[num].dir) {
      if (room->people) {
        act("The elevator doors close.", FALSE, room->people, 0, 0, TO_ROOM);
        act("The elevator doors close.", FALSE, room->people, 0, 0, TO_CHAR);
      }
      close_elevator_doors(room, num, room->rating);
      elevator[num].dir = -1;
    }
  } else if (CMD_IS("push"))
  {
    if (IS_ASTRAL(ch)) {
      send_to_char("You can't do that in your current state.\r\n", ch);
      return TRUE;
    }
    if (!*argument) {
      send_to_char("Press which button?\r\n", ch);
      return TRUE;
    }

    if (elevator[num].dir >= UP) {
      send_to_char("The elevator has already been activated.\r\n", ch);
      return TRUE;
    }

    skip_spaces(&argument);
    if (LOWER(*argument) == 'b' && (number = atoi(argument + 1)) > 0)
      number = elevator[num].num_floors + elevator[num].start_floor + number - 1;
    else if (LOWER(*argument) == 'g' && elevator[num].start_floor <= 0)
      number = elevator[num].num_floors + elevator[num].start_floor - 1;
    else if ((number = atoi(argument)) > 0)
      number = elevator[num].num_floors + elevator[num].start_floor - 1 - number;
    else
      number = -1;

    if (number < 0 || number >= elevator[num].num_floors ||
        elevator[num].floor[number].vnum < 0)
      send_to_char(ch, "'%s' isn't a button.\r\n", argument);
    else if (number == room->rating) {
      if (room->dir_option[elevator[num].floor[number].doors]) {
        temp = room->rating + 1 - elevator[num].num_floors - elevator[num].start_floor;
        if (temp > 0)
          send_to_char(ch, "You are already at B%d!\r\n", temp);
        else if (temp == 0)
          send_to_char(ch, "You are already at the ground floor!\r\n");
        else
          send_to_char(ch, "You are already at floor %d!\r\n", 0 - temp);
      } else {
        sprintf(buf, "The elevator doors open to the %s.",
                fulldirs[elevator[num].floor[room->rating].doors]);
        act(buf, FALSE, ch, 0, 0, TO_ROOM);
        act(buf, FALSE, ch, 0, 0, TO_CHAR);
        open_elevator_doors(room, num, room->rating);
      }
    } else {
      if (number > room->rating) {
        elevator[num].dir = DOWN;
        elevator[num].time_left = MAX(1, number - room->rating);
      } else {
        elevator[num].dir = UP;
        elevator[num].time_left = MAX(1, room->rating - number);
      }
      if (!room->dir_option[elevator[num].floor[room->rating].doors])
        sprintf(buf, "The elevator begins to %s.",
                (elevator[num].dir == UP ? "ascend" : "descend"));
      else {
        sprintf(buf, "The elevator doors close and it begins to %s.",
                (elevator[num].dir == UP ? "ascend" : "descend"));
        close_elevator_doors(room, num, room->rating);
      }
      act(buf, FALSE, ch, 0, 0, TO_ROOM);
      act(buf, FALSE, ch, 0, 0, TO_CHAR);
    }
    return TRUE;
  } else if (CMD_IS("look"))
  {
    one_argument(argument, arg);
    if (!*arg || !(!strcasecmp("panel", arg) || !strcasecmp("elevator", arg)
                   || !strcasecmp("buttons", arg)))
      return FALSE;

    strcpy(buf, "The elevator panel displays the following buttons:\r\n");
    number = 0;
    for (floor = 0; floor < elevator[num].num_floors; floor++)
      if (elevator[num].floor[floor].vnum > -1) {
        temp = elevator[num].start_floor + floor;
        if (temp < 0)
          sprintf(buf + strlen(buf), "  B%-2d", 0 - temp);
        else if (temp == 0)
          sprintf(buf + strlen(buf), "  G ");
        else
          sprintf(buf + strlen(buf), "  %-2d", temp);
        number++;
        if (!(number % elevator[num].columns))
          strcat(buf, "\r\n");
      }
    if ((number % elevator[num].columns))
      strcat(buf, "\r\n");
    temp = room->rating + 1 - elevator[num].num_floors - elevator[num].start_floor;
    if (temp > 0)
      sprintf(buf + strlen(buf), "The floor indicator shows that the "
              "elevator is currently at B%d.\r\n", temp);
    else if (temp == 0)
      sprintf(buf + strlen(buf), "The floor indicator shows that the "
              "elevator is currently at the ground floor.\r\n");
    else
      sprintf(buf + strlen(buf), "The floor indicator shows that the "
              "elevator is currently at floor %d.\r\n", 0 - temp);
    send_to_char(buf, ch);
    return TRUE;
  }
  return FALSE;
}

void ElevatorProcess(void)
{
  int i, rnum;

  for (i = 0; i < num_elevators; i++)
    if (elevator && (rnum = real_room(elevator[i].room)) > -1)
      process_elevator(&world[rnum], NULL, 0, "");
}

// ______________________________
//
// Escalators
// ______________________________

// ______________________________
//
// spec
// ______________________________


SPECIAL(escalator)
{
  return FALSE;
}

// ______________________________
//
// processing funcs
// ______________________________

void EscalatorProcess(void)
{
  int i, dir;
  struct char_data *temp, *next;

  for (i = 0; i <= top_of_world; i++)
    if (world[i].func && world[i].func == escalator)
      for (temp = world[i].people; temp; temp = next) {
        next = temp->next_in_room;
        if (GET_LASTROOM(temp) > 0 || GET_LASTROOM(temp) < -3)
          GET_LASTROOM(temp) = -3;
        else if (GET_LASTROOM(temp) < 0)
          GET_LASTROOM(temp)++;
        else
          for (dir = NORTH; dir <= DOWN; dir++)
            if (world[i].dir_option[dir] &&
                world[i].dir_option[dir]->to_room > 0) {
              act("As you reach the end, you step off the escalator.",
                  FALSE, temp, 0, 0, TO_CHAR);
              act("$n steps off of the escalator.", TRUE, temp, 0, 0, TO_ROOM);
              char_from_room(temp);
              GET_LASTROOM(temp) = world[i].number;
              char_to_room(temp, world[i].dir_option[dir]->to_room);
              if (temp->desc)
                look_at_room(temp, 0);
              break;
            }
      }
}

// ______________________________
//
// Monorail
// ______________________________

// ______________________________
//
// utility funcs
// ______________________________

static void open_doors(int car, int to, int room, int from)
{
  if (!world[car].dir_option[to]) {
    world[car].dir_option[to] = new room_direction_data;
    memset((char *) world[car].dir_option[to], 0,
           sizeof(struct room_direction_data));
    world[car].dir_option[to]->to_room = room;
    world[car].dir_option[to]->to_room_vnum = world[room].number;
    world[car].dir_option[to]->barrier = 8;
    world[car].dir_option[to]->condition = 8;
    world[car].dir_option[to]->material = 8;
  }
  if (!world[room].dir_option[from]) {
    world[room].dir_option[from] = new room_direction_data;
    memset((char *) world[room].dir_option[from], 0,
           sizeof(struct room_direction_data));
    world[room].dir_option[from]->to_room = car;
    world[room].dir_option[from]->to_room_vnum = world[car].number;
    world[room].dir_option[from]->barrier = 8;
    world[room].dir_option[from]->condition = 8;
    world[room].dir_option[from]->material = 8;
  }
  sprintf(buf, "The monorail stops and the doors open to %s.\r\n", thedirs[to]);
  send_to_room(buf, car);
  sprintf(buf, "The monorail stops and the doors open to %s.\r\n", thedirs[from]);
  send_to_room(buf, room);
}

static void close_doors(int car, int to, int room, int from)
{
  if (world[car].dir_option[to]->keyword)
    delete [] world[car].dir_option[to]->keyword;
  if (world[car].dir_option[to]->general_description)
    delete [] world[car].dir_option[to]->general_description;
  delete world[car].dir_option[to];
  world[car].dir_option[to] = NULL;

  if (world[room].dir_option[from]->keyword)
    delete [] world[room].dir_option[from]->keyword;
  if (world[room].dir_option[from]->general_description)
    delete [] world[room].dir_option[from]->general_description;
  delete world[room].dir_option[from];
  world[room].dir_option[from] = NULL;

  send_to_room("The monorail doors close and it begins accelerating.\r\n", car);
  send_to_room("The monorail doors close and it begins accelerating.\r\n", room);
}

// ______________________________
//
// processing funcs
// ______________________________

void process_seatac_monorail(void)
{
  int carnum, roomnum, ind;
  static int where = 0;

  if (where >= 16)
    where = 0;

  ind = (int)(where / 4);

  carnum = real_room(seatac[ind].transport);
  roomnum = real_room(seatac[ind].room);

  switch (where) {
  case 0:
  case 4:
    send_to_room("Lights flash along the runway as the monorail approaches.\r\n",
                 roomnum);
    break;
  case 1:
  case 5:
  case 9:
  case 13:
    open_doors(carnum, seatac[ind].to, roomnum, seatac[ind].from);
    break;
  case 2:
  case 6:
  case 10:
  case 14:
    close_doors(carnum, seatac[ind].to, roomnum, seatac[ind].from);
    break;
  case 3:
    send_to_room("A voice announces, \"Next stop: Auburn\"\r\n", carnum);
    break;
  case 7:
    send_to_room("A voice announces, \"Next stop: Seattle. Change here for Downtown Shuttle\"\r\n", carnum);
    break;
  case 11:
    send_to_room("A voice announces, \"Next stop: Auburn\"\r\n", carnum);
    break;
  case 15:
    send_to_room("A voice announces, \"Next stop: West Tacoma.\"\r\n", carnum);
    break;
  }

  where++;
}

// ______________________________
//
// Ferries and busses
// ______________________________

/* Seattle/Tacoma Ferry */

struct transport_type seattle_ferry[2] =
  {
    {
      12620, SOUTH, 12613, NORTH
    },
    {
      12620, SOUTHEAST, 2007, NORTHWEST
    },
  };

void extend_walkway_st(int ferry, int to, int room, int from)
{
  if (!world[ferry].dir_option[to]) {
    world[ferry].dir_option[to] = new room_direction_data;
    memset((char *) world[ferry].dir_option[to], 0,
           sizeof(struct room_direction_data));
    world[ferry].dir_option[to]->to_room = room;
    world[ferry].dir_option[to]->to_room_vnum = world[room].number;
    world[ferry].dir_option[to]->barrier = 8;
    world[ferry].dir_option[to]->condition = 8;
    world[ferry].dir_option[to]->material = 8;
  }
  if (!world[room].dir_option[from]) {
    world[room].dir_option[from] = new room_direction_data;
    memset((char *) world[room].dir_option[from], 0,
           sizeof(struct room_direction_data));
    world[room].dir_option[from]->to_room = ferry;
    world[room].dir_option[from]->to_room_vnum = world[ferry].number;
    world[room].dir_option[from]->barrier = 8;
    world[room].dir_option[from]->condition = 8;
    world[room].dir_option[from]->material = 8;
  }
  send_to_room("The ferry docks at the pier, and extends its walkway.\r\n", room);
  send_to_room("The ferry docks at the pier, and extends its walkway.\r\n", ferry);
}
void contract_walkway_st(int ferry, int to, int room, int from)
{
  if (world[ferry].dir_option[to]->keyword)
    delete [] world[ferry].dir_option[to]->keyword;
  if (world[ferry].dir_option[to]->general_description)
    delete [] world[ferry].dir_option[to]->general_description;
  delete world[ferry].dir_option[to];
  world[ferry].dir_option[to] = NULL;
  if (world[room].dir_option[from]->keyword)
    delete [] world[room].dir_option[from]->keyword;
  if (world[room].dir_option[from]->general_description)
    delete [] world[room].dir_option[from]->general_description;
  delete world[room].dir_option[from];
  world[room].dir_option[from] = NULL;
  send_to_room("The walkway recedes, and the ferry departs.\r\n", room);
  send_to_room("The walkway recedes, and the ferry departs.\r\n", ferry);
}

void process_seattle_ferry(void)
{
  static int where = 0;
  int ferry, dock, ind;

  if (where >= 26)
    where = 0;

  ind = (where >= 13 ? 1 : 0);

  ferry = real_room(seattle_ferry[ind].transport);
  dock = real_room(seattle_ferry[ind].room);

  switch (where) {
  case 0:
    send_to_room("The ferry approaches, gliding across the bay towards "
                 "the dock.\r\n", dock);
    break;
  case 1:
  case 14:
    extend_walkway_st(ferry, seattle_ferry[ind].to, dock, seattle_ferry[ind].from);
    break;
  case 4:
  case 17:
    contract_walkway_st(ferry, seattle_ferry[ind].to, dock, seattle_ferry[ind].from);
    break;
  case 5:
    send_to_room("A voice announces through a rusting speaker, "
                 "\"Next stop: Tacoma.\"\r\n", ferry);
    break;
  case 13:
    send_to_room("The ferry approaches, gliding across the bay towards "
                 "the dock.\r\n", dock);
    break;
  case 18:
    send_to_room("A voice announces through a rusting speaker, "
                 "\"Next stop: Seattle.\"\r\n", ferry);
    break;
  }

  where++;
}

/* Hellhound Bus Spec
 * Bus from Seattle to Portland and back
 */



struct transport_type hellhound[2] =
  {
    {
      670, NORTHWEST, 32763, SOUTHEAST
    },
    {  670, SOUTHWEST, 14700, NORTHEAST
    },
  };

void open_busdoor(int bus, int to, int room, int from)
{
  if (!world[bus].dir_option[to]) {
    world[bus].dir_option[to] = new room_direction_data;
    memset((char *) world[bus].dir_option[to], 0,
           sizeof(struct room_direction_data));
    world[bus].dir_option[to]->to_room = room;
    world[bus].dir_option[to]->to_room_vnum = world[room].number;
    world[bus].dir_option[to]->barrier = 8;
    world[bus].dir_option[to]->condition = 8;
    world[bus].dir_option[to]->material = 8;
  }
  if (!world[room].dir_option[from]) {
    world[room].dir_option[from] = new room_direction_data;
    memset((char *) world[room].dir_option[from], 0,
           sizeof(struct room_direction_data));
    world[room].dir_option[from]->to_room = bus;
    world[room].dir_option[from]->to_room_vnum = world[bus].number;
    world[room].dir_option[from]->barrier = 8;
    world[room].dir_option[from]->condition = 8;
    world[room].dir_option[from]->material = 8;
  }
  send_to_room("The bus rolls up to the platform, and the door opens.\r\n", room);
  send_to_room("The bus rolls up to the platform, and the door opens.\r\n", bus);
}

void close_busdoor(int bus, int to, int room, int from)
{
  if (world[bus].dir_option[to]->keyword)
    delete [] world[bus].dir_option[to]->keyword;
  if (world[bus].dir_option[to]->general_description)
    delete [] world[bus].dir_option[to]->general_description;
  delete world[bus].dir_option[to];
  world[bus].dir_option[to] = NULL;
  if (world[room].dir_option[from]->keyword)
    delete [] world[room].dir_option[from]->keyword;
  if (world[room].dir_option[from]->general_description)
    delete [] world[room].dir_option[from]->general_description;
  delete world[room].dir_option[from];
  world[room].dir_option[from] = NULL;
  send_to_room("The bus door shuts, the driver yells \"^Wall aboard!^n\", and begins driving.\r\n", room);
  send_to_room("The bus door shuts, the driver yells \"^Wall aboard!^n\", and begins driving.\r\n", bus);
}

void process_hellhound_bus(void)
{
  static int where = 0;
  int bus, stop, ind;

  if (where >= 52)
    where = 0;

  ind = (where >= 26 ? 1 : 0);

  bus = real_room(hellhound[ind].transport);
  stop = real_room(hellhound[ind].room);

  switch (where) {
  case 0:
    send_to_room("The bus pulls into the garage, and slowly moves to the platform.\r\n", stop);
    break;
  case 1:
  case 28:
    open_busdoor(bus, hellhound[ind].to, stop, hellhound[ind].from);
    break;
  case 8:
  case 34:
    close_busdoor(bus, hellhound[ind].to, stop, hellhound[ind].from);
    break;
  case 23:
    send_to_room("The driver shouts from the front, \"Next stop: Portland\"\r\n", bus);
    break;
  case 26:
    send_to_room("The bus pulls into the garage, and slowly moves to the platform.\r\n", stop);
    break;
  case 49:
    send_to_room("The driver shouts from the front, \"Next stop: Seattle\".\r\n", bus);
    break;
  }
  where++;
}

//FILEPOINTER
//Downtown Portlan, 60th Street Hospital, Gresham, 60th Street back from Gresham
//Lightrail
struct transport_type lightrail[4] =
  {
    {
      14799, SOUTH, 14701, NORTH
    }
    , //Downtown Portlan
    { 14799, EAST, 14702, WEST }, //60thStreet/Hospital
    { 14799, WEST, 14711, EAST }, //Gresham
    { 14799, EAST, 14702, WEST }, //60thStreet/BackfromGresham
  };

void open_lightraildoor(int lightrail, int to, int room, int from)
{
  if (!world[lightrail].dir_option[to]) {
    world[lightrail].dir_option[to] = new room_direction_data;
    memset((char *) world[lightrail].dir_option[to], 0,
           sizeof(struct room_direction_data));
    world[lightrail].dir_option[to]->to_room = room;
    world[lightrail].dir_option[to]->to_room_vnum = world[room].number;
    world[lightrail].dir_option[to]->barrier = 8;
    world[lightrail].dir_option[to]->condition = 8;
    world[lightrail].dir_option[to]->material = 8;
  }
  if (!world[room].dir_option[from]) {
    world[room].dir_option[from] = new room_direction_data;
    memset((char *) world[room].dir_option[from], 0,
           sizeof(struct room_direction_data));
    world[room].dir_option[from]->to_room = lightrail;
    world[room].dir_option[from]->to_room_vnum = world[lightrail].number;
    world[room].dir_option[from]->barrier = 8;
    world[room].dir_option[from]->condition = 8;
    world[room].dir_option[from]->material = 8;
  }
  send_to_room("The incoming lightrail grinds to a halt and its doors slide open with a hiss.\r\n", room);
  send_to_room("The lightrail grinds to a halt and the doors hiss open.\r\n", lightrail);
}

void close_lightraildoor(int lightrail, int to, int room, int from)
{
  if (world[lightrail].dir_option[to]->keyword)
    delete [] world[lightrail].dir_option[to]->keyword;
  if (world[lightrail].dir_option[to]->general_description)
    delete [] world[lightrail].dir_option[to]->general_description;
  delete world[lightrail].dir_option[to];
  world[lightrail].dir_option[to] = NULL;
  if (world[room].dir_option[from]->keyword)
    delete [] world[room].dir_option[from]->keyword;
  if (world[room].dir_option[from]->general_description)
    delete [] world[room].dir_option[from]->general_description;
  delete world[room].dir_option[from];
  world[room].dir_option[from] = NULL;
  send_to_room("The lightrail's doors slide shut and a tone eminates around the platform, signaling its departure.", room);
  send_to_room("The lightrail's doors slide shut and a tone signals as it begins moving.\r\n", lightrail);
}

void process_lightrail_train(void)
{
  static int where = 0;
  int train, stop;
  static int ind = 0;
  if (where >= 40)
    where = 0;

  //  if (where <= 0)
  //    ind = 0;
  //  if (where >= 10)
  //    ind = 1;
  //  if (where >= 20)
  //    ind = 2;
  //  if (where >= 30)
  //    ind = 3;

  train = real_room(lightrail[ind].transport);
  stop = real_room(lightrail[ind].room);

  switch (where) {
    //Downtown Stop Stuff
  case 39:
    send_to_room("An LCD Panel Flashes: \"Next Stop: Downtown Portland\".\r\n", train);
    break;
  case 0:
    send_to_room("The lightrail emits a loud grind as it brakes into the station.\r\n", stop);
    break;
  case 1:
    open_lightraildoor(train, lightrail[ind].to, stop, lightrail[ind].from);
    break;
  case 5:
    close_lightraildoor(train, lightrail[ind].to, stop, lightrail[ind].from);
    ind = 1;
    break;
    //60th Stop Stuff (1)
  case 9:
    send_to_room("An LCD Panel Flashes: \"Next Stop: 60th Street\".\r\n", train);
    break;
  case 10:
    send_to_room("The lightrail emits a loud grind as it brakes into the station.\r\n", stop);
    break;
  case 11:
    open_lightraildoor(train, lightrail[ind].to, stop, lightrail[ind].from);
    break;
  case 15:
    close_lightraildoor(train, lightrail[ind].to, stop, lightrail[ind].from);
    ind = 2;
    break;
    //Gresham Stop Stuff
  case 19:
    send_to_room("An LCD Panel Flashes: \"Next Stop: Gresham\".\r\n", train);
    break;
  case 20:
    send_to_room("The lightrail emits a loud grind as it brakes into the station.\r\n", stop);
    break;
  case 21:
    open_lightraildoor(train, lightrail[ind].to, stop, lightrail[ind].from);
    break;
  case 25:
    close_lightraildoor(train, lightrail[ind].to, stop, lightrail[ind].from);
    ind = 3;
    break;
    //To60th
  case 29:
    send_to_room("An LCD Panel Flashes: \"Next Stop: 60th Street\".\r\n", train);
    break;
  case 30:
    send_to_room("The lightrail emits a loud grind as it brakes into the station.\r\n", stop);
    break;
  case 31:
    open_lightraildoor(train, lightrail[ind].to, stop, lightrail[ind].from);
    break;
  case 35:
    close_lightraildoor(train, lightrail[ind].to, stop, lightrail[ind].from);
    ind = 0;
    break;
  }
  where++;
}


struct transport_type tacsea[2] =
  {
    {
      2099, SOUTH, 2007, NORTH
    },
    { 2099, NORTH, 14500, SOUTH }
  };

void extend_walkway(int ferry, int to, int room, int from)
{
  if (!world[ferry].dir_option[to]) {
    world[ferry].dir_option[to] = new room_direction_data;
    memset((char *) world[ferry].dir_option[to], 0,
           sizeof(struct room_direction_data));
    world[ferry].dir_option[to]->to_room = room;
    world[ferry].dir_option[to]->to_room_vnum = world[room].number;
    world[ferry].dir_option[to]->barrier = 8;
    world[ferry].dir_option[to]->condition = 8;
    world[ferry].dir_option[to]->material = 8;
  }
  if (!world[room].dir_option[from]) {
    world[room].dir_option[from] = new room_direction_data;
    memset((char *) world[room].dir_option[from], 0,
           sizeof(struct room_direction_data));
    world[room].dir_option[from]->to_room = ferry;
    world[room].dir_option[from]->to_room_vnum = world[ferry].number;
    world[room].dir_option[from]->barrier = 8;
    world[room].dir_option[from]->condition = 8;
    world[room].dir_option[from]->material = 8;
  }
  send_to_room("The ferry docks, and the walkway extends.\r\n", room);
  send_to_room("The ferry docks, and the walkway extends.\r\n", ferry);
}

void contract_walkway(int ferry, int to, int room, int from)
{
  if (world[ferry].dir_option[to]->keyword)
    delete [] world[ferry].dir_option[to]->keyword;
  if (world[ferry].dir_option[to]->general_description)
    delete [] world[ferry].dir_option[to]->general_description;
  delete world[ferry].dir_option[to];
  world[ferry].dir_option[to] = NULL;
  if (world[room].dir_option[from]->keyword)
    delete [] world[room].dir_option[from]->keyword;
  if (world[room].dir_option[from]->general_description)
    delete [] world[room].dir_option[from]->general_description;
  delete world[room].dir_option[from];
  world[room].dir_option[from] = NULL;
  send_to_room("The walkway recedes, and the ferry departs.\r\n", room);
  send_to_room("The walkway recedes, and the ferry departs.\r\n", ferry);
}

void process_seatac_ferry(void)
{
  static int where = 0;
  int ferry, dock, ind;

  if (where >= 26)
    where = 0;

  ind = (where >= 13 ? 1 : 0);

  ferry = real_room(tacsea[ind].transport);
  dock = real_room(tacsea[ind].room);

  switch (where) {
  case 0:
    send_to_room("The ferry approaches, gliding across the bay towards "
                 "the dock.\r\n", dock);
    break;
  case 1:
  case 14:
    extend_walkway(ferry, tacsea[ind].to, dock, tacsea[ind].from);
    break;
  case 4:
  case 17:
    contract_walkway(ferry, tacsea[ind].to, dock, tacsea[ind].from);
    break;
  case 5:
    send_to_room("A voice announces through a rusting speaker, "
                 "\"Next stop: Bradenton.\"\r\n", ferry);
    break;
  case 13:
    send_to_room("The ferry approaches, gliding across the bay towards "
                 "the dock.\r\n", dock);
    break;
  case 18:
    send_to_room("A voice announces through a rusting speaker, "
                 "\"Next stop: Tacoma.\"\r\n", ferry);
    break;
  }

  where++;
}

// ______________________________
//
// external interface funcs
// ______________________________

void TransportInit()
{
  init_elevators();
}

void MonorailProcess(void)
{
/*  process_seatac_monorail();
  process_seattle_ferry();
  process_seatac_ferry();
  process_hellhound_bus();
  process_lightrail_train();
*/
}

void TransportEnd()
{}