#include "copyright.h"

/* Commands that create new objects */

#include "db.h"
#include "config.h"
#include "interface.h"
#include "externs.h"
#include "match.h"

/* utility for open and link */
static dbref parse_linkable_room (dbref player, const char *room_name)
{
  dbref room;

  /* parse room */
  if (!string_compare (room_name, "here")) {
    room = db[player].location;
  } else if (!string_compare (room_name, "home")) {
    return HOME;                /* HOME is always linkable */
  } else {
    room = parse_dbref (room_name);
  }

  /* check room */
  if (room < 0 || room >= db_top || Typeof (room) != TYPE_ROOM) {
    notify (player, "That's not a room!");
    return NOTHING;
  } else if (!can_link_to (player, room)) {
    notify (player, "You can't link to that.");
    return NOTHING;
  } else {
    return room;
  }
}

/* use this to create an exit */
void do_open (dbref player, const char *direction, const char *linkto)
{
  dbref loc;
  dbref exit;

#ifdef RESTRICTED_BUILDING
  if (!Builder (player)) {
    notify (player, "That command is restricted to authorized builders.");
    return;
  }
#endif /* RESTRICTED_BUILDING */

  if ((loc = getloc (player)) == NOTHING)
    return;
  if (!*direction) {
    notify (player, "Open where?");
    return;
  } else if (!ok_name (direction)) {
    notify (player, "That's a strange name for an exit!");
    return;
  }

  if (!controls (player, loc)) {
    notify (player, "Permission denied.");
  } else if (!payfor (player, EXIT_COST)) {
    notify (player, "Sorry, you don't have enough pennies to open an exit.");
  } else {
    /* create the exit */
    exit = new_object ();

    /* initialize everything */
    db[exit].name = alloc_string (direction);
    db[exit].owner = player;
    db[exit].flags = TYPE_EXIT;

    /* link it in */
    PUSH (exit, db[loc].exits);

    /* and we're done */
    notify (player, "Opened.");

    /* check second arg to see if we should do a link */
    if (*linkto != '\0') {
      notify (player, "Trying to link...");
      if ((loc = parse_linkable_room (player, linkto)) != NOTHING) {
        if (!payfor (player, LINK_COST)) {
          notify (player, "You don't have enough pennies to link.");
        } else {
          /* it's ok, link it */
          db[exit].location = loc;
          notify (player, "Linked.");
        }
      }
    }
  }
}

/* use this to link to a room that you own */
/* it seizes ownership of the exit */
/* costs 1 penny */
/* plus a penny transferred to the exit owner if they aren't you */
/* you must own the linked-to room AND specify it by room number */
void do_link (dbref player, const char *name, const char *room_name)
{
  dbref loc;
  dbref thing;
  dbref room;

  if ((loc = getloc (player)) == NOTHING)
    return;
  if ((room = parse_linkable_room (player, room_name)) == NOTHING)
    return;

  init_match (player, name, TYPE_EXIT);
  match_exit ();
  match_neighbor ();
  match_possession ();
  match_me ();
  match_here ();
  if (Wizard (player)) {
    match_absolute ();
    match_player ();
  }

  if ((thing = noisy_match_result ()) != NOTHING) {
    switch (Typeof (thing)) {
    case TYPE_EXIT:
      /* we're ok, check the usual stuff */
      if (db[thing].location != NOTHING) {
        if (controls (player, thing)) {
          if (Typeof (db[thing].location) == TYPE_PLAYER) {
            notify (player, "That exit is being carried.");
          } else {
            notify (player, "That exit is already linked.");
          }
        } else {
          notify (player, "Permission denied.");
        }
      } else {
        /* handle costs */
        if (db[thing].owner == player) {
          if (!payfor (player, LINK_COST)) {
            notify (player, "It costs a penny to link this exit.");
            return;
          }
        } else {
          if (!payfor (player, LINK_COST + EXIT_COST)) {
            notify (player, "It costs two pennies to link this exit.");
            return;
#ifdef RESTRICTED_BUILDING
          } else if (!Builder (player)) {
            notify (player, "Only authorized builders may seize exits.");
#endif /* RESTRICTED_BUILDING */
          } else {
            /* pay the owner for his loss */
            db[db[thing].owner].pennies += EXIT_COST;
          }
        }

        /* link has been validated and paid for; do it */
        db[thing].owner = player;
        db[thing].location = room;

        /* notify the player */
        notify (player, "Linked.");
      }
      break;
    case TYPE_THING:
    case TYPE_PLAYER:
      if (!controls (player, thing)) {
        notify (player, "Permission denied.");
      } else if (room == HOME) {
        notify (player, "Can't set home to home.");
      } else {
        /* do the link */
        db[thing].exits = room; /* home */
        notify (player, "Home set.");
      }
      break;
    case TYPE_ROOM:
      if (!controls (player, thing)) {
        notify (player, "Permission denied.");
      } else {
        /* do the link, in location */
        db[thing].location = room;      /* dropto */
        notify (player, "Dropto set.");
      }
      break;
    default:
      notify (player, "Internal error: weird object type.");
      fprintf (stderr, "PANIC weird object: Typeof(%d) = %d\n",
        thing, Typeof (thing));
      break;
    }
  }
}

/* use this to create a room */
void do_dig (dbref player, const char *name)
{
  dbref room;
  char buf[BUFFER_LEN];

#ifdef RESTRICTED_BUILDING
  if (!Builder (player)) {
    notify (player, "That command is restricted to authorized builders.");
    return;
  }
#endif /* RESTRICTED_BUILDING */

  /* we don't need to know player's location!  hooray! */
  if (*name == '\0') {
    notify (player, "Dig what?");
  } else if (!ok_name (name)) {
    notify (player, "That's a silly name for a room!");
  } else if (!payfor (player, ROOM_COST)) {
    notify (player, "Sorry, you don't have enough pennies to dig a room.");
  } else {
    room = new_object ();

    /* Initialize everything */
    db[room].name = alloc_string (name);
    db[room].owner = player;
    db[room].flags = TYPE_ROOM;

    sprintf (buf, "%s created with room number %d.", name, room);
    notify (player, buf);
  }
}

/* use this to create an object */
void do_create (dbref player, char *name, int cost)
{
  dbref loc;
  dbref thing;

#ifdef RESTRICTED_BUILDING
  if (!Builder (player)) {
    notify (player, "That command is restricted to authorized builders.");
    return;
  }
#endif /* RESTRICTED_BUILDING */

  if (*name == '\0') {
    notify (player, "Create what?");
    return;
  } else if (!ok_name (name)) {
    notify (player, "That's a silly name for a thing!");
    return;
  } else if (cost < 0) {
    notify (player, "You can't create an object for less than nothing!");
    return;
  } else if (cost < OBJECT_COST) {
    cost = OBJECT_COST;
  }

  if (!payfor (player, cost)) {
    notify (player, "Sorry, you don't have enough pennies.");
  } else {
    /* create the object */
    thing = new_object ();

    /* initialize everything */
    db[thing].name = alloc_string (name);
    db[thing].location = player;
    db[thing].owner = player;
    db[thing].pennies = OBJECT_ENDOWMENT (cost);
    db[thing].flags = TYPE_THING;

    /* endow the object */
    if (db[thing].pennies > MAX_OBJECT_ENDOWMENT) {
      db[thing].pennies = MAX_OBJECT_ENDOWMENT;
    }

    /* home is here (if we can link to it) or player's home */
    if ((loc = db[player].location) != NOTHING && can_link_to (player, loc)) {
      db[thing].exits = loc;    /* home */
    } else {
      db[thing].exits = db[player].exits;       /* home */
    }

    /* link it in */
    PUSH (thing, db[player].contents);

    /* and we're done */
    notify (player, "Created.");
  }
}