untermud/DOC/
untermud/DOC/U/
untermud/DOC/U/U-examples/
untermud/DOC/internals/
untermud/DOC/wizard/
untermud/MISC/
untermud/MISC/dbchk/
untermud/RWHO/
untermud/RWHO/rwhod/
/*
    Copyright (C) 1991, Marcus J. Ranum. All rights reserved.
*/

/* configure all options BEFORE including system stuff. */
#include    "config.h"
#include    "mud.h"
#include    "vars.h"
#include    "match.h"

/*
create new objects for our mini-universe.
*/

static int buildobj(char *who, char *aswho, char *name, char *desc);
static int buildplayer(char *who, char *aswho, char *name, char *loc, char *pass);
static int build_canlink(char *who, char *aswho, char *to, char *from, int remoteflg);
static int build_goodname(char *nam, int exitflag);
static int buildexit(char *who, char *aswho, char *name, char *from, char *to);
static int buildroom(char *who, char *aswho, char *name, char *exnam, char *retnam);
static int buildlink(char *who, char *aswho, char *name, char *from, char *to);


/* create a standard-carrying-around-type thang */
static int buildobj (who, aswho, name, desc)
char *who;
char *aswho;
char *name;
char *desc;
{
  char nuf[MAXOID];
  char hm[MAXOID];
  char *op;

  if (!build_goodname (name, 0)) {
    say (who, "bad name.\n", (char *) 0);
    return (UERR_ILLASGN);
  }

  if (ut_objnew (who, nuf))
    return (UERR_FATAL);
  eval_cmd_returnstr (nuf);

  /* add the object to player's inventory */
  if (ut_listadd (who, who, var_cont, nuf))
    return (UERR_FATAL);

  /* set owner */
  op = ut_getatt (aswho, 0, typ_list, var_owner, (char *) 0);
  if (op != (char *) 0 && ut_set (who, nuf, typ_list, var_owner, op))
    return (UERR_FATAL);

  /* set location of the object (on the player) */
  if (ut_set (who, nuf, typ_obj, var_loc, who))
    return (UERR_FATAL);

  /* set home of the object (on the player) */
  (void) strcpy (hm, who);
  ut_delocaliz (hm);
  if (ut_set (who, nuf, typ_obj, var_home, hm))
    return (UERR_FATAL);

  /* set name if one given */
  if (name != (char *) 0 && ut_set (who, nuf, typ_str, var_nam, name))
    return (UERR_FATAL);

  /* set desc if one given */
  if (desc != (char *) 0 && ut_set (who, nuf, typ_str, var_desc, desc))
    return (UERR_FATAL);

  if (run_level () == 0)
    say (who, "Created object ", nuf, ".\n", (char *) 0);
  return (UERR_NONE);
}




/* make a new person! */
static int buildplayer (who, aswho, name, loc, pass)
char *who;
char *aswho;
char *name;
char *loc;
char *pass;
{
  char nuf[MAXOID];
  char hm[MAXOID];
  char *limbo;

  if (!ut_flagged (aswho, var_wiz)) {
    say (who, "Only a wizard can bring forth new life.\n", (char *) 0);
    return (UERR_PERM);
  }

  if (ut_objnew (who, nuf))
    return (UERR_FATAL);
  eval_cmd_returnstr (nuf);

  /* add the object to room */
  if (ut_listadd (who, loc, var_ply, nuf))
    return (UERR_FATAL);

  /* set owner - player owns itself ! */
  if (ut_set (who, nuf, typ_list, var_owner, nuf))
    return (UERR_FATAL);

  /* set password */
  if (pass == (char *) 0) {
    /* set an empty password */
    if (ut_set (who, nuf, typ_str, var_pass, ""))
      return (UERR_FATAL);
  } else {
    if (ut_setpass (nuf, pass))
      return (UERR_FATAL);
  }

  /* make it a player */
  if (ut_set (who, nuf, typ_flag, var_isplay, ""))
    return (UERR_FATAL);

  /* set location of the object (in the room) */
  if (ut_set (who, nuf, typ_obj, var_loc, loc))
    return (UERR_FATAL);

  /* set home for the player (limbo) */
  limbo = ut_getatt (system_object, 0, typ_obj, var_syslimbo, (char *) 0);
  if (limbo == (char *) 0) {
    plogf ("build player %s: no limbo; home is room %s\n", nuf, loc);
    say (who, "no limbo; player home is here\n", (char *) 0);
    limbo = loc;
  }
  (void) strcpy (hm, limbo);
  ut_delocaliz (hm);
  if (ut_set (who, nuf, typ_obj, var_home, hm))
    return (UERR_FATAL);

  /* set name if one given */
  if (name != (char *) 0 && ut_set (who, nuf, typ_str, var_nam, name))
    return (UERR_FATAL);

  if (run_level () == 0)
    say (who, "Created player ", nuf, ".\n", (char *) 0);
  return (UERR_NONE);
}




static int build_canlink (who, aswho, to, from, remoteflg)
char *who;
char *aswho;
char *to;
char *from;
int remoteflg;
{
  int wiz = ut_flagged (aswho, var_wiz);

  /* If not to 'home', check the dest busily */
  if (!strcmp (to, "home"))
    return (1);

  if (remoteflg && !wiz && !cache_check (to)) {
    /* Try to make a remote link */
    if (xact_addlink (to, from, aswho)) {
      say (who, "No such destination locally. Could not make ",
        "remote link to ", to, ".\n", (char *) 0);
      return (0);
    }
  } else {

    /* is the destination link ok ? */
    if (!wiz && !ut_isobjown (aswho, to) &&
      bool_locked (aswho, to, (char *) 0, var_link, 1)) {
      say (who, "Cannot link to ", to, ".\n", (char *) 0);
      return (0);
    }

    /* is it really a room ? */
    if (!wiz && !ut_flagged (to, var_isroom)) {
      say (who, "You cannot link into a non-room.\n", (char *) 0);
      return (0);
    }
  }
  return (1);
}




/*
check if a string is a valid thing-name. Basically, nothing can start with
and @ character.
*/
static int build_goodname (nam, exitflag)
char *nam;
int exitflag;
{
  int ok = 1;

  if (nam == (char *) 0)
    return (0);
  /* Don't let people build things that will confuse the matcher. */
  if (strcmp (nam, "here") == 0 || strcmp (nam, "me") == 0)
    return (0);

  if (exitflag) {               /* Check an exit name */
    if (*nam == '#')
      return (0);
    while ((nam = index (nam, ';')) != (char *) 0 && ok)
      ok = (*(++nam) != '#');
    return (ok);
  } else {                      /* Check other stuff */
    return (*nam != '#');
  }
}




/* create an exit */
static int buildexit (who, aswho, name, from, to)
char *who;
char *aswho;
char *name;
char *to;
char *from;
{
  char nuf[MAXOID];
  char *op;

  if (!build_goodname (name, 1)) {
    say (who, "bad name.\n", (char *) 0);
    return (UERR_ILLASGN);
  }
  /* do we own this room ? */
  if (ut_flagged (aswho, var_wiz) == 0 && !ut_isobjown (aswho, from)) {
    say (who, "Cannot open exit. Not owner.\n", (char *) 0);
    return (UERR_PERM);
  }

  if (!strcmp ("here", to))
    to = ut_loc (run_actor ());

  if (to != (char *) 0 && !build_canlink (who, aswho, to, from, 1)) {
    say (who, "Exit not created.\n", (char *) 0);
    return (UERR_PERM);
  }

  if (ut_objnew (who, nuf))
    return (UERR_FATAL);
  eval_cmd_returnstr (nuf);

  /* chown it inherited from effective user-id */
  op = ut_getatt (aswho, 0, typ_list, var_owner, (char *) 0);
  if (op != (char *) 0 && ut_set (who, nuf, typ_list, var_owner, op))
    return (UERR_FATAL);

  if (run_level () == 0)
    say (who, "Opened exit ", nuf, ".\n", (char *) 0);

  /* name it */
  if (name != (char *) 0 && ut_set (who, nuf, typ_str, var_nam, name))
    return (UERR_FATAL);

  /* link it to its destination - TODO - add checking, etc. */
  if (to != (char *) 0) {
    if (ut_set (who, nuf, typ_obj, var_dest, to))
      return (UERR_FATAL);

    if (run_level () == 0)
      say (who, "Linked exit to ", to, ".\n", (char *) 0);
  }

  /* set the exits location */
  if (ut_set (who, nuf, typ_obj, var_loc, from))
    return (UERR_FATAL);

  /* add the object to room's exit list */
  if (ut_listadd (who, from, var_xit, nuf))
    return (UERR_FATAL);
  return (UERR_NONE);
}




/* create a room */
static int buildroom (who, aswho, name, exnam, retnam)
char *who;
char *aswho;
char *name;
char *exnam;
char *retnam;
{
  char *op;
  char nuf[MAXOID];
  int xx;

  if (!build_goodname (name, 0)) {
    say (who, "bad room name.\n", (char *) 0);
    return (UERR_ILLASGN);
  }
  if ((exnam != (char *) 0 && !build_goodname (exnam, 1))
    || (retnam != (char *) 0 && !build_goodname (retnam, 1))) {
    say (who, "bad exit name.\n", (char *) 0);
    return (UERR_ILLASGN);
  }

  if (ut_objnew (who, nuf))
    return (UERR_FATAL);

  /* chown it */
  op = ut_getatt (aswho, 0, typ_list, var_owner, (char *) 0);
  if (op != (char *) 0 && ut_set (who, nuf, typ_list, var_owner, op))
    return (UERR_FATAL);

  /* make it a room */
  if (ut_set (who, nuf, typ_flag, var_isroom, ""))
    return (UERR_FATAL);

  /* name it */
  if (name != (char *) 0 && ut_set (who, nuf, typ_str, var_nam, name))
    return (UERR_FATAL);

  if (exnam != (char *) 0 &&
    (xx = buildexit (who, aswho, exnam, ut_loc (who), nuf)) != UERR_NONE)
    return (xx);

  if (retnam != (char *) 0 &&
    (xx = buildexit (who, aswho, retnam, nuf, ut_loc (who))) != UERR_NONE)
    return (xx);

  /* down here to return the OID of the room, not the exits */
  eval_cmd_returnstr (nuf);

  if (run_level () == 0)
    say (who, "Dug room ", nuf, ".\n", (char *) 0);
  return (UERR_NONE);
}




/* new destination for an existing exit */
static int buildlink (who, aswho, name, from, to)
char *who;
char *aswho;
char *name;
char *to;
char *from;
{
  char nuf[MAXOID];

  if (matchexit (who, name, from, MTCH_EXACT | MTCH_NONLOC | MTCH_UNIQ, nuf))
    return (UERR_NOMATCH);

  /* do we own this exit ? */
  if (ut_flagged (aswho, var_wiz) == 0 && !ut_isobjown (aswho, nuf)) {
    say (who, "Cannot link exit. Not owner.\n", (char *) 0);
    return (UERR_PERM);
  }

  if (to != (char *) 0 && !build_canlink (who, aswho, to, from, 1)) {
    say (who, "Cannot link exit. Permission denied.\n", (char *) 0);
    return (UERR_PERM);
  }

  if (to != (char *) 0) {
    if (ut_set (who, nuf, typ_obj, var_dest, to))
      return (UERR_FATAL);

    if (run_level () == 0)
      say (who, "Linked exit to ", to, ".\n", (char *) 0);
  }
  return (UERR_NONE);
}




/* figure out what the hell the goober is trying to do - modularize */
/* ARGSUSED */
int cmd_build (int ac, char *av[], char *who, char *aswho)
{
  if (ac < 2) {
    say (who, av[0], " a what?\n", (char *) 0);
    return (UERR_ARGCNT);
  }

  if (ac >= 2 && !strncmp (av[1], "object", strlen (av[1]))) {
    char *name = (char *) 0;
    char *desc = (char *) 0;

    if (ac > 2)
      name = av[2];
    if (ac > 3)
      desc = av[3];
    return (buildobj (who, aswho, name, desc));
  }

  if (ac >= 2 && !strncmp (av[1], "room", strlen (av[1]))) {
    char *name = (char *) 0;
    char *exnam = (char *) 0;
    char *retnam = (char *) 0;

    if (ac > 2)
      name = av[2];
    if (ac > 3)
      exnam = av[3];
    if (ac > 4)
      retnam = av[4];
    return (buildroom (who, aswho, name, exnam, retnam));
  }

  if (ac >= 2 && !strncmp (av[1], "exit", strlen (av[1]))) {
    char *name = (char *) 0;
    char *dest = (char *) 0;

    if (ac < 4) {
      say (who, "usage: ", av[0], " exit name destination-room\n",
        (char *) 0);
      return (UERR_ARGCNT);
    }
    name = av[2];
    dest = av[3];
    return (buildexit (who, aswho, name, ut_loc (who), dest));
  }

  if (ac >= 2 && !strncmp (av[1], "link", strlen (av[1]))) {
    char *name = (char *) 0;
    char *dest = (char *) 0;

    if (ac < 4) {
      say (who, "usage: ", av[0], " link existing-exit destination-room\n",
        (char *) 0);
      return (UERR_ARGCNT);
    }
    name = av[2];
    dest = av[3];
    return (buildlink (who, aswho, name, ut_loc (who), dest));
  }

  if (ac >= 2 && !strncmp (av[1], "player", strlen (av[1]))) {
    char *name = (char *) 0;
    char *pass = (char *) 0;

    if (ac > 2)
      name = av[2];
    if (ac > 3)
      pass = av[3];
    return (buildplayer (who, aswho, name, ut_loc (who), pass));
  }

  if (!strcmp (av[1], "help")) {
    say (who, av[0], " object [name] [description]\n", (char *) 0);
    say (who, av[0], " room [name] [exit-to-name] [exit-back-name]\n",
      (char *) 0);
    say (who, av[0], " exit name destination-room\n", (char *) 0);
    say (who, av[0], " link existing-exit destination-room\n", (char *) 0);
    say (who, av[0], " player name [password]\n", (char *) 0);
    return (UERR_NONE);
  }

  say (who, "I don't understand what you want to ", av[0], "\n", (char *) 0);
  return (UERR_ARGCNT);
}