AwakeMUD-0.6Beta/doc/
AwakeMUD-0.6Beta/lib/
AwakeMUD-0.6Beta/lib/etc/
AwakeMUD-0.6Beta/lib/etc/pfiles/
AwakeMUD-0.6Beta/lib/fixer_data/
AwakeMUD-0.6Beta/lib/misc/
AwakeMUD-0.6Beta/lib/plrobjs/
AwakeMUD-0.6Beta/lib/plrobjs/A-E/
AwakeMUD-0.6Beta/lib/plrobjs/F-J/
AwakeMUD-0.6Beta/lib/plrobjs/K-O/
AwakeMUD-0.6Beta/lib/plrobjs/U-Z/
AwakeMUD-0.6Beta/lib/plrspells/A-E/
AwakeMUD-0.6Beta/lib/plrspells/F-J/
AwakeMUD-0.6Beta/lib/plrtext/A-E/
AwakeMUD-0.6Beta/lib/world/
AwakeMUD-0.6Beta/lib/world/mob/
AwakeMUD-0.6Beta/lib/world/obj/
AwakeMUD-0.6Beta/lib/world/qst/
AwakeMUD-0.6Beta/lib/world/shp/
AwakeMUD-0.6Beta/lib/world/wld/
AwakeMUD-0.6Beta/lib/world/zon/
/* **********************************************************************
*  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>

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

extern int rev_dir[];
extern const char *fulldirs[];
extern struct room_data *world;
extern struct index_data *obj_index;
extern struct index_data *mob_index;
extern struct zone_data *zone_table;
extern int top_of_world;

SPECIAL(call_elevator);
SPECIAL(elevator_spec);

// ----------------------------------------------------------------------------

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

/* places to add */
/* University, 5646, north */

struct dest_data destinations[] =
{
  { "tacoma", "Tacoma", 2000, 3, SOUTH },
//  { "biohyde", "Biohyde Complex", 4200, 1, NORTHWEST },
//  { "puyallup", "Central Puyallup", 2457, 5, SOUTH },
//  { "park", "Seattle State Park", 4000, 0, -1 },
//  { "seattle", "Seattle State Park", 4000, 0, -1 },
//  { "groetza", "Groetza Camp", 4300, 1, NORTHWEST },
//  { "tarislar", "Tarislar", 4965, 6, SOUTH },
//  { "redmond", "Redmond", 14310, 4, WEST },
//  { "reaper", "The Reaper", 4700, 4, SOUTH },
//  { "platinum", "Platinum Club", 6624, 6, SOUTH },
//  { "penumbra", "Club Penumbra", 6017, 6, WEST },
//  { "big", "The Big Rhino", 5767, 5, SOUTH },
//  { "epicenter", "The Epicenter", 2418, 5, NORTH },
//  { "twister", "The Titty Twister", 5373, 6, NORTHWEST },
//  { "airport", "Seattle-Tacoma Airport", 19410, 1, SOUTH },
//  { "academy", "Aztechnology Magic Academy", 6960, 4, SOUTHEAST },
  { "\n", "", 0, 0, 0 } // this MUST be last
};

void open_taxi_door(int 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;
}

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;
}

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

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

  if (world[ch->in_room].sector_type != SECT_CITY || !empty ||
      ROOM_FLAGGED(ch->in_room, ROOM_INDOORS)) {
    send_to_char("There are no cabs to hail here.\r\n", ch);
    return;
  }

  first = real_room(FIRST_CAB);
  last = real_room(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);
      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;
    }

  send_to_char("Hail as you might, no cab answers.\r\n", ch);
}

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 dest = 0, comm = CMD_NONE, i = 0, j, dist = -1, dir = -1;
  char say[80];

  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:
        sprintf(say, "%s?  Yeah, sure...it'll cost ya %d nuyen, whaddya say?",
                destinations[GET_SPARE2(driver)].str, GET_SPARE1(driver));
        do_say(driver, say, 0, 0);
        GET_ACTIVE(driver) = ACT_AWAIT_YESNO;
        break;
      case ACT_REPLY_NOTOK:
        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:
        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 {
          do_say(driver, "Ok, heres we are.", 0, 0);
          forget(driver, temp);
          dest = real_room(GET_SPARE2(driver));
          GET_SPARE2(driver) = 0;
          GET_ACTIVE(driver) = ACT_AWAIT_CMD;
          for (j = number(NORTH, NORTHWEST);; j = number(NORTH, NORTHWEST))
            if (!world[dest].dir_option[j]) {
              open_taxi_door(dest, j, driver->in_room);
              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"))) {
    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("'")) {
    if (strstr(argument, "yes") || strstr(argument, "sure") ||
        strstr(argument, "yea"))
      comm = CMD_YES;
    else if (strstr(argument, "no"))
      comm = CMD_NO;
    else for (dest = 0; *destinations[dest].keyword != '\n'; dest++)
      if (strstr((const char *)argument, destinations[dest].keyword)) {
        comm = CMD_DEST;
        break;
      }

    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) {
    switch (zone_table[world[i].zone].number) {
      case 35: case 37: case 40: case 50: case 51: case 55:
      case 60: case 65: case 74: case 194: case 143:
        dist = 0; dir = -1; break;
      case 20: case 22: case 30: case 29: case 25: case 32:
        dist = 3; dir = SOUTH; break;
      case 23: case 24: case 26:
        dist = 5; dir = SOUTH; break;
      case 49:
        dist = 6; dir = SOUTH; break;
      case 38: case 45:
        dist = 1; dir = NORTH; break;
      case 42:
        dist = 1; dir = NORTHWEST; break;
      default:
	do_say(driver, "Sorry, Commuter TaxiCorp doesn't service this area..", 0, 0);
        return TRUE;
    }

    if (destinations[dest].dir == dir)
      GET_SPARE1(driver) = MAX(25, (abs)(destinations[dest].dist - dist) * 50);
    else if (destinations[dest].dir == -1)
      GET_SPARE1(driver) = dist * 50;
    else if (dir == -1)
      GET_SPARE1(driver) = destinations[dest].dist * 50;
    else if (destinations[dest].dir == rev_dir[dir])
      GET_SPARE1(driver) = (destinations[dest].dist + dist) * 50;
    else if (destinations[dest].dir == (dir - 1) ||
        destinations[dest].dir == (dir + 1))
      GET_SPARE1(driver) = (int)((destinations[dest].dist + dist) * 25 / 2);
    else if (destinations[dest].dir == (dir - 2) ||
        destinations[dest].dir == (dir + 2))
      GET_SPARE1(driver) = (destinations[dest].dist + dist) * 25;
    else GET_SPARE1(driver) = (int)((destinations[dest].dist + dist) * 75 / 2);

    GET_SPARE2(driver) = dest;
    GET_ACTIVE(driver) = ACT_REPLY_DEST;
    remember(driver, ch);
  } else if (comm == CMD_YES && memory(driver, ch) &&
      GET_ACTIVE(driver) == ACT_AWAIT_YESNO) {
    if (GET_NUYEN(ch) < GET_SPARE1(driver) && GET_LEVEL(ch) < LVL_LEGEND) {
      GET_ACTIVE(driver) = ACT_REPLY_NOTOK;
      return TRUE;
    }
    if (GET_LEVEL(ch) < LVL_LEGEND)
      GET_NUYEN(ch) -= GET_SPARE1(driver);
    GET_SPARE1(driver) = (int)(GET_SPARE1(driver) / 25);
    GET_SPARE2(driver) = 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) {
          act("The taxi door slams shut as its wheels churn up a cloud "
              "of dirt.", FALSE, world[dest].people, 0, 0, TO_ROOM);
          act("The taxi door slams shut as its wheels churn up a cloud "
              "of dirt.", 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;
}

void taxi_leaves(void)
{
  int i, j, found = 0, to;
  struct char_data *temp;

  for (j = real_room(FIRST_CAB); j <= real_room(LAST_CAB); 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) {
          act("The taxi door slams shut as its wheels churn up a "
              "cloud of dirt.", FALSE, world[to].people, 0, 0, TO_ROOM);
          act("The taxi door slams shut as its wheels churn up a "
              "cloud of dirt.", 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);
      }
  }
}

void init_elevators(void)
{
  FILE *fl;
  char line[256];
  int i, j, t[4], rnum;

  if (!(fl = fopen(ELEVATOR_FILE, "r"))) {
    log("Error opening elevator file.");
    exit(1);
  }

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

  elevator = new struct elevator_data[num_elevators];

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

    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, "%d %d", t, t + 1) != 2) {
          fprintf(stderr, "Format error in elevator #%d, floor #%d\n", i, j);
          exit(1);
        }
        elevator[i].floor[j].vnum = t[0];
        if ((rnum = 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);
}

void open_elevator_doors(struct room_data *room, int num, int floor)
{
  int dir, 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);
  }
}

void close_elevator_doors(struct room_data *room, int num, int floor)
{
  int rnum, 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);
  }
}

SPECIAL(call_elevator)
{
  int i = 0, j, index = -1, 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 (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 + elevator[index].start_floor;
    if (i < 1)
      send_to_char(ch, "The floor indicator shows that the elevator is "
                       "currently at B%d.\r\n", 1 - i);
    else send_to_char(ch, "The floor indicator shows that the elevator is "
                       "current at floor %d.\r\n", i);
    return TRUE;
  }

  return FALSE;
}

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 = UP;
        elevator[num].time_left = floor - room->rating;
      } else if (floor && floor < room->rating) {
        elevator[num].dir = DOWN;
        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 + elevator[num].start_floor;
      if (temp < 1)
        sprintf(buf, "The elevator stops at B%d, "
                "and the doors open to the %s.", 1 - temp,
                fulldirs[elevator[num].floor[room->rating].doors]);
      else sprintf(buf, "The elevator stops at floor %d, "
                   "and the doors open to the %s.", 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 (!*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 = 1 - elevator[num].start_floor - number;
    else if ((number = atoi(argument)) > 0)
      number -= elevator[num].start_floor;
    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 + elevator[num].start_floor;
        if (temp < 1)
          send_to_char(ch, "You are already at B%d!\r\n", 1 - temp);
        else send_to_char(ch, "You are already at floor %d!\r\n", 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 = UP;
        elevator[num].time_left = MAX(1, number - room->rating);
      } else {
        elevator[num].dir = DOWN;
        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 = floor + elevator[num].start_floor;
        if (temp < 1)
          sprintf(buf + strlen(buf), "  B%-2d", 1 - temp);
        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 + elevator[num].start_floor;
    if (temp < 1)
      sprintf(buf + strlen(buf), "The floor indicator shows that the "
              "elevator is currently at B%d.\r\n", 1 - temp);
    else sprintf(buf + strlen(buf), "The floor indicator shows that the "
                 "elevator is currently at floor %d.\r\n", temp);
    send_to_char(buf, ch);
    return TRUE;
  }
  return FALSE;
}

void process_elevators(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, "");
}

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

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

  return FALSE;
}

SPECIAL(escalator)
{
  return FALSE;
}

void process_escalators(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 < UP; 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;
          }
      }
}

struct transport_type
{
  sh_int transport;
  sh_int to;
  sh_int room;
  sh_int from;
};

/*
struct transport_type seattle1[12] =
{
  { 503, NORTH, 7703, SOUTH },
  { 503, EAST, 7706, WEST },
  { 503, EAST, 7710, WEST },
  { 503, SOUTHEAST, 7714, NORTHWEST },
  { 503, SOUTHWEST, 7718, NORTHEAST },
  { 503, SOUTHWEST, 7722, NORTHEAST },
  { 503, SOUTH, 7726, NORTH },
  { 503, WEST, 7730, EAST },
  { 503, NORTHEAST, 7734, SOUTHWEST },
  { 503, NORTHEAST, 7738, SOUTHWEST },
  { 503, NORTHEAST, 7742, SOUTHWEST },
  { 503, NORTHEAST, 7746, SOUTHWEST }
};

struct transport_type seattle2[12] =
{
  { 502, SOUTH, 7702, NORTH },
  { 502, SOUTHWEST, 7747, NORTHEAST },
  { 502, SOUTHWEST, 7743, NORTHEAST },
  { 502, SOUTHWEST, 7739, NORTHEAST },
  { 502, EAST, 7735, WEST },
  { 502, NORTH, 7731, SOUTH },
  { 502, SOUTHWEST, 7727, NORTHEAST },
  { 502, NORTHEAST, 7723, SOUTHWEST },
  { 502, NORTHEAST, 7719, SOUTHWEST },
  { 502, WEST, 7715, EAST },
  { 502, WEST, 7711, EAST },
  { 502, NORTH, 7707, WEST }
};

struct transport_type seatac[2] =
{
  { 501, WEST, 3018, EAST },
  { 501, EAST, 9823, WEST }
};



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;
  }
  send_to_room("The monorail stops and the doors open.\r\n", car);
  send_to_room("The monorail stops and the doors open.\r\n", room);
}

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);
}

void process_seattle_monorail(void)
{
  int car1, room1, car2, room2, ind;
  static int where = 0;

  if (where >= 36)
    where = 0;

  ind = (int)(where / 3);

  car1 = real_room(seattle1[ind].transport);
  room1 = real_room(seattle1[ind].room);
  car2 = real_room(seattle2[ind].transport);
  room2 = real_room(seattle2[ind].room);

  switch (where) {
    case 0:  case 3:  case 6:  case 9:  case 12: case 15:
    case 18: case 21: case 24: case 27: case 30: case 33:
      send_to_room("Lights flash along the runway as the monorail approaches.\r\n",
                   room1);
      send_to_room("Lights flash along the runway as the monorail approaches.\r\n",
                   room2);
      break;
    case 1:  case 4:  case 7:  case 10: case 13: case 16:
    case 19: case 22: case 25: case 28: case 31: case 34:
      open_doors(car1, seattle1[ind].to, room1, seattle1[ind].from);
      open_doors(car2, seattle2[ind].to, room2, seattle2[ind].from);
      break;
    case 2:  case 5:  case 8:  case 11: case 14: case 17:
    case 20: case 23: case 26: case 29: case 32: case 35:
      close_doors(car1, seattle1[ind].to, room1, seattle1[ind].from);
      close_doors(car2, seattle2[ind].to, room2, seattle2[ind].from);
      break;
  }
  switch (where) {
    case 0:
      send_to_room("A voice announces, \"Next stop: Renraku Arcology.\"\r\n", car1);
      send_to_room("A voice announces, \"Next stop: Renraku Arcology.\"\r\n", car2);
      break;
    case 3:
      send_to_room("A voice announces, \"Next stop: 7th & South Dearborn.\"\r\n", car1);
      send_to_room("A voice announces, \"Next stop: 3rd & Marion.\"\r\n", car2);
      break;
    case 6:
      send_to_room("A voice announces, \"Next stop: Yesler Avenue.\"\r\n", car1);
      send_to_room("A voice announces, \"Next stop: 3rd & Union.\"\r\n", car2);
      break;
    case 9:
      send_to_room("A voice announces, \"Next stop: Boren & Cherry.\"\r\n", car1);
      send_to_room("A voice announces, \"Next stop: 5th & Stewart.\"\r\n", car2);
      break;
    case 12:
      send_to_room("A voice announces, \"Next stop: Broadway & Union.\"\r\n", car1);
      send_to_room("A voice announces, \"Next stop: 5th & Denny.\"\r\n", car2);
      break;
    case 15:
      send_to_room("A voice announces, \"Next stop: Yale & Denny.\"\r\n", car1);
      send_to_room("A voice announces, \"Next stop: Seattle Center.\"\r\n", car2);
      break;
    case 18:
      send_to_room("A voice announces, \"Next stop: Fairview & Thomas.\"\r\n", car1);
      send_to_room("A voice announces, \"Next stop: Fairview & Thomas.\"\r\n", car2);
      break;
    case 21:
      send_to_room("A voice announces, \"Next stop: Seattle Center.\"\r\n", car1);
      send_to_room("A voice announces, \"Next stop: Yale & Denny.\"\r\n", car2);
      break;
    case 24:
      send_to_room("A voice announces, \"Next stop: 5th & Denny.\"\r\n", car1);
      send_to_room("A voice announces, \"Next stop: Broadway & Union.\"\r\n", car2);
      break;
    case 27:
      send_to_room("A voice announces, \"Next stop: 5th & Stewart.\"\r\n", car1);
      send_to_room("A voice announces, \"Next stop: Boren & Cherry.\"\r\n", car2);
      break;
    case 30:
      send_to_room("A voice announces, \"Next stop: 3rd & Union.\"\r\n", car1);
      send_to_room("A voice announces, \"Next stop: Yesler Avenue.\"\r\n", car2);
      break;
    case 33:
      send_to_room("A voice announces, \"Next stop: 3rd & Marion.\"\r\n", car1);
      send_to_room("A voice announces, \"Next stop: 7th & South Dearborn.\"\r\n", car2);
      break;
  }

  where++;
}

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

  if (where >= 8)
    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:
      open_doors(carnum, seatac[ind].to, roomnum, seatac[ind].from);
      break;
    case 2: case 6:
      close_doors(carnum, seatac[ind].to, roomnum, seatac[ind].from);
      break;
    case 3:
      send_to_room("A voice announces, \"Next stop: Seattle.\"\r\n", carnum);
      break;
    case 7:
      send_to_room("A voice announces, \"Next stop: Tacoma.\"\r\n", carnum);
      break;
  }

  where++;
}

*/
/*
struct transport_type tacsea[2] =
{
  { ?, ?, ?, ? },
  { ?, ?, ?, ? }
};

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 SeaTac 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 2: case 15:
      contract_walkway(ferry, tacsea[ind].to, dock, tacsea[ind].from);
      break;
    case 3:


      send_to_room("A voice announces through a rusting speaker, "
                   "\"Next stop: Seattle.\"\r\n", ferry);
      break;
    case 13:
      send_to_room("The SeaTac ferry approaches, gliding across the bay towards "
                   "the dock.\r\n", dock);
      break;
    case 16:
      send_to_room("A voice announces through a rusting speaker, "
                   "\"Next stop: Tacoma.\"\r\n", ferry);
      break;
  }

  where++;
}*/

void process_transportation(void)
{
//  process_seattle_monorail();
//  process_seatac_monorail();
//  process_seatac_ferry();
}