dbm/
misc/
old-docs/
/* buildcmds.c */

#include "copyright.h"
#include "config.h"

#include <stdio.h>
#ifdef STRING_H
#include <string.h>
#else
#include <strings.h>
#endif				/* STRING_H */
#include <ctype.h>
#if defined(ALLOCA_H) && !defined(NO_ALLOCA)
#include <alloca.h>
#endif

#include "teeny.h"
#include "case.h"
#include "strlist.h"

/*
 * Building/Creating commands
 */

/* Buffer from cmds.c */

extern char     cmdwork[];

voidfunc        do_create(player, argone)
  int             player;
  char           *argone;
{
  int             obj, next, home, here;

#ifdef RESTRICT_BUILDING
  if (!isbuilder(player) && !iswiz(player)) {
    notify_player(player, "That command is for authorized builders only.\r\n");
    return;
  }
#endif				/* RESTRICT_BUILDING */

  if (check_quota(player)) {
    notify_player(player, "Sorry, you're over your limit.\r\n");
    return;
  }
  if (!argone || !*argone) {
    notify_player(player, "You need to specify a name.\r\n");
    return;
  }
  if (!ok_name(argone)) {
    notify_player(player, "That's a silly name for an object!\r\n");
    return;
  }
  /* Go to it */

  obj = create_obj(TYP_THING);
  if (set_str_elt(obj, NAME, argone) == -1)
    goto createbomb;

  if (set_int_elt(obj, OWNER, player) == -1)
    goto createbomb;
  if (set_int_elt(obj, LOC, player) == -1)
    goto createbomb;
  if (get_int_elt(player, LOC, &here) == -1)
    goto createbomb;
  if (controls(player, here) || isabode(here)) {
    home = here;
  } else {
    if (get_int_elt(player, HOME, &home) == -1)
      goto createbomb;
  }
  if (set_int_elt(obj, HOME, home) == -1)
    goto createbomb;

  if (get_int_elt(player, CONTENTS, &next) == -1)
    goto createbomb;
  if (set_int_elt(player, CONTENTS, obj) == -1)
    goto createbomb;
  if (set_int_elt(obj, NEXT, next) == -1)
    goto createbomb;
  stamp(obj);

  /* Tell the player */

  sprintf(cmdwork, "Object %s created with number #%d.\r\n", argone, obj);
  notify_player(player, cmdwork);
  return;
createbomb:
  notify_bad(player);
  return;
}
voidfunc        do_dig(player, arg, argtwo)
  int             player;
  char           *arg;
  char           *argtwo;
{
  int             room, parent;

#ifdef RESTRICT_BUILDING
  if (!isbuilder(player) && !iswiz(player)) {
    notify_player(player, "That command is for authorized builders only.\r\n");
    return;
  }
#endif				/* RESTRICT_BUILDING */

  if (check_quota(player)) {
    notify_player(player, "Sorry, you're over your limit.\r\n");
    return;
  }
  if (!arg || !*arg) {
    notify_player(player, "You need to specify a name.\r\n");
    return;
  }
  if (!ok_name(arg)) {
    notify_player(player, "That's a silly name for a room!\r\n");
    return;
  }
  if (!argtwo || !*argtwo) {
    parent = ROOT_PARENT;
  } else {
    if (!strcasecmp(argtwo, "root"))
      parent = ROOT_PARENT;
    else {
      if (argtwo[0] != '#' || !argtwo[1] || !isdigit(argtwo[1])) {
	notify_player(player, "You must specify the parent by number.\r\n");
	return;
      }
      parent = atoi(argtwo + 1);
      if (!exists_object(parent)) {
	notify_player(player, "That parent does not exist.\r\n");
	return;
      }
      if (!isroom(parent)) {
	notify_player(player, "Illegal parent.\r\n");
	return;
      }
      if (!controls(player, parent) && parent != ROOT_PARENT &&
	  !isabode(parent)) {
	notify_player(player, "Permission denied.\r\n");
	return;
      }
      if (get_int_elt(parent, LOC, &room) == -1)
	goto digbomb;
      if (!legal_parent_check(parent, room)) {
	notify_player(player, "Illegal parent.\r\n");
	return;
      }
    }
  }

  room = create_obj(TYP_ROOM);
  if (set_int_elt(room, OWNER, player) == -1)
    goto digbomb;
  if (set_str_elt(room, NAME, arg) == -1)
    goto digbomb;
  if (set_int_elt(room, LOC, parent) == -1)
    goto digbomb;
  list_add(room, parent, ROOMS_LIST);

  stamp(room);

  /* Tell the player */

  sprintf(cmdwork, "Room %s created with number #%d.\r\n", arg, room);
  notify_player(player, cmdwork);
  return;
digbomb:
  notify_bad(player);
  return;
}
void            do_set_string(player, argone, argtwo, code)
  int             player;
  char           *argone;
  char           *argtwo;
  int             code;
{
  int             obj, flags;
  StringList     *strs;

  /* Find the thing to set the string ON */

  if (!argone || !*argone) {
    for (strs = Strings; strs->code && strs->code != code; strs++);
    if (!strs->code) {		/* shouldn't ever happen.. */
      notify_player(player, "Set what on what?\r\n");
      return;
    }
    (void) sprintf(cmdwork, "Set the %c%s string on what?\r\n",
		   DOWNCASE((strs->name)[0]), (strs->name) + 1);
    notify_player(player, cmdwork);
    return;
  }
  if ((obj = resolve_object(player, argone, 0)) == -1) {
    if ((obj = resolve_exit(player, argone)) == -1) {
      notify_player(player, "I don't see that here.\r\n");
      return;
    }
  }
  if (obj == -2) {
    notify_player(player, "I don't know which one you mean.\r\n");
    return;
  }
  if (!controls(player, obj)) {
    notify_player(player, "You can't do that!\r\n");
    return;
  }
  if (!isplayer(obj))
    stamp(obj);

  /* We *might* be setting a player name. Gotta be careful */

  if (code == NAME) {

    if (argtwo == NULL || *argtwo == 0) {
      notify_player(player, "You must specify a name.\r\n");
      return;
    }
    /* Check out the name */

    if (get_int_elt(obj, FLAGS, &flags) == -1) {
      warning("do_set_string", "cannot get flags");
      goto namebomb;
    }
    if ((flags & TYPE_MASK) == TYP_EXIT)
      if (!ok_exit_name(argtwo)) {
	notify_player(player, "Bad exit name.\r\n");
	return;
      } else if (!ok_name(argtwo)) {
	notify_player(player, "Bad name.\r\n");
	return;
      }
    if ((flags & TYPE_MASK) == TYP_PLAYER) {
      char           *name, *pword, *givenpwd;
      /* skip to pwd in given name */

      if (parse_name_pwd(argtwo, &name, &givenpwd) == -1) {
	notify_player(player, "Wrong password.\r\n");
	return;
      }
      if (!ok_player_name(name)) {
	notify_player(player, "You can't give a player that name.\r\n");
	return;
      }
      if (get_str_elt(obj, PASSWORD, &pword) == -1) {
	goto namebomb;
      }
      if (!pword || !*pword) {
	notify_player(player, "You can't change your name.\r\n");
	return;
      }
      if (!givenpwd || !*givenpwd) {
	notify_player(player, "Wrong password.\r\n");
	return;
      }
      if (strcmp(crypt(givenpwd, CRYPT_KEY), pword) != 0) {
	notify_player(player, "Wrong password.\r\n");
	return;
      }
      argtwo = name;
    }
  }
  if (set_str_elt(obj, code, argtwo) == -1)
    goto namebomb;

  switch (code) {
  case NAME:
    notify_player(player, "Name set.\r\n");
    break;
  case DESC:
  case IDESC:
    notify_player(player, "Description set.\r\n");
    break;
  default:
    notify_player(player, "Message set.\r\n");
  }

  return;

namebomb:
  notify_bad(player);
  return;
}

voidfunc        do_open(player, argone, argtwo)
  int             player;
  char           *argone;
  char           *argtwo;
{
  int             here, exit, list, dest, flags;
  int             source;
  char           *p;

#ifdef RESTRICT_BUILDING
  if (!isbuilder(player) && !iswiz(player)) {
    notify_player(player, "That command is for authorized builders only.\r\n");
    return;
  }
#endif				/* RESTRICT_BUILDING */

  if (check_quota(player)) {
    notify_player(player, "Sorry, you're over your limit.\r\n");
    return;
  }
  if (!argone || !*argone) {
    notify_player(player, "You must specify a name.\r\n");
    return;
  }
  if (!ok_exit_name(argone) && !isgod(player)) {
    notify_player(player, "That's a silly name for an exit!\r\n");
    return;
  }
  /* parse for a source object */
  for (p = argone; *p && *p != '/'; p++);
  if (*p == '/') {		/* found one */
    *p++ = 0;			/* terminate argone */
    if (*p) {
      if ((source = resolve_object(player, p, iswiz(player))) == -1) {
	notify_player(player, "I can't find that source.\r\n");
	return;
      }
      if (source == -2) {
	notify_player(player, "I can't tell which source you mean.\r\n");
	return;
      }
      if (!exists_object(source) || !controls(player, source) || isexit(source)) {
	notify_player(player, "You can't open an exit on that!\r\n");
	return;
      }
    } else {
      notify_player(player, "You need to specify a source.\r\n");
      return;
    }
  } else {
    if (get_int_elt(player, LOC, &source) == -1)
      goto openbomb;
#ifndef BUILDING_OK
    if (!controls(player, source)) {
#else
    if (!controls(player, source) && !isbuildok(source)) {
#endif
      notify_player(player, "You can't open an exit here!\r\n");
      return;
    }
  }

  exit = create_obj(TYP_EXIT);
  if (set_str_elt(exit, NAME, argone) == -1)
    goto openbomb;
  if (set_int_elt(exit, OWNER, player) == -1)
    goto openbomb;
  if (set_int_elt(exit, LOC, source) == -1)
    goto openbomb;
  if (get_int_elt(source, EXITS, &list) == -1)
    goto openbomb;
  if (set_int_elt(exit, NEXT, list) == -1)
    goto openbomb;
  if (set_int_elt(source, EXITS, exit) == -1)
    goto openbomb;

  stamp(exit);
  /* Tell the player about this exit */

  sprintf(cmdwork, "Exit %s opened with number #%d.\r\n", argone, exit);
  notify_player(player, cmdwork);

  if (get_int_elt(player, LOC, &here) == -1)
    goto openbomb;

  if (argtwo != NULL) {		/* Try to link this */
    if (strcasecmp(argtwo, "home") == 0) {
      dest = -3;
    } else {
      if ((dest = resolve_object(player, argtwo, iswiz(player))) == -1) {
	notify_player(player, "I can't find that destination.\r\n");
	return;
      }
      if (dest == -2) {
	notify_player(player, "I can't tell which destination you mean.\r\n");
	return;
      }
    }
    notify_player(player, "Trying to link...\r\n");

    /* Can we link there? */

    if (dest != -3 && !exists_object(dest)) {
      notify_player(player, "Bad destination.\r\n");
      return;
    }
    if (dest != -3 && get_int_elt(dest, FLAGS, &flags) == -1) {
      notify_player(player, "Can't find destination.\r\n");
      return;
    }
    if (dest != -3 && (TYPE_MASK & flags) == TYP_EXIT) {
      notify_player(player, "You can't link an exit to that!\r\n");
      return;
    }
    if (!controls(player, dest) && !(flags & LINK_OK)) {
      notify_player(player, "Can't link to destination.\r\n");
      return;
    }
    /* OK. We can link there. */

    if (set_int_elt(exit, DESTINATION, dest) == -1)
      goto openbomb;
    notify_player(player, "Linked.\r\n");
  }
  return;

openbomb:
  notify_bad(player);
  return;
}
voidfunc        do_link(player, argone, argtwo)
  int             player;
  char           *argone;
  char           *argtwo;
{
  int             dest, flags, thing, here;
  int             code, foo, exowner;
  char           *msg;

  if (!argone || !*argone || !argtwo || !*argtwo) {
    notify_player(player, "Link what to where?\r\n");
    return;
  }
  if (get_int_elt(player, LOC, &here) == -1)
    goto linkbomb;

  /* Find the destination, thing to link to */

  if (!strcasecmp(argtwo, "home"))
    dest = -3;
  else {
    if ((dest = resolve_object(player, argtwo, iswiz(player))) == -1) {
      notify_player(player, "I can't find that destination.\r\n");
      return;
    }
    if (dest == -2) {
      notify_player(player, "I can't tell which destination you mean.\r\n");
      return;
    }
  }

  /* Can we link there? */

  if (dest != -3 && !exists_object(dest)) {
    notify_player(player, "Bad destination.\r\n");
    return;
  }
  if (dest != -3 && get_int_elt(dest, FLAGS, &flags) == -1) {
    notify_player(player, "Can't find destination.\r\n");
    return;
  }
  if (dest != -3 && (flags & TYPE_MASK) == TYP_EXIT) {
    notify_player(player, "You can't link anything to that!\r\n");
    return;
  }
  /* OK. Try to get the thing to link */

  if ((thing = resolve_exit(player, argone)) == -1) {
    if ((thing = resolve_object(player, argone, 0)) == -1) {
      notify_player(player, "I don't see that here.\r\n");
      return;
    }
  }
  if (thing == -2) {
    notify_player(player, "I can't tell which one you want to link.\r\n");
    return;
  }
  if (get_int_elt(thing, FLAGS, &flags) == -1)
    goto linkbomb;

  switch (flags & TYPE_MASK) {
  case TYP_PLAYER:
  case TYP_THING:
    if (!controls(player, dest) && !isabode(dest)) {
      notify_player(player, "You can't link that there!\r\n");
      return;
    }
    break;
  case TYP_ROOM:
  case TYP_EXIT:
    if (!controls(player, dest) && !islinkok(dest)) {
      notify_player(player, "You can't link that there!\r\n");
      return;
    }
  }
  /* What sort of thing is it? */

  switch (flags & TYPE_MASK) {
  case TYP_PLAYER:
  case TYP_THING:
    if (dest == -3) {
      notify_player(player, "Paradox in link of object.\r\n");
      return;
    }
    msg = "Home set.\r\n";
    code = HOME;
    break;
  case TYP_ROOM:
    msg = "Dropto set.\r\n";
    code = DROPTO;
    break;
  case TYP_EXIT:
    msg = "Linked.\r\n";
    code = DESTINATION;
    /* Check that the exit is unlinked */

    if (get_int_elt(thing, DESTINATION, &foo) == -1)
      goto linkbomb;

    if (foo != -1) {
      notify_player(player, "That exit is linked.\r\n");
      return;
    } else {
      if (get_int_elt(thing, OWNER, &exowner) == -1)
	goto linkbomb;
      if (exowner != player) {

#ifdef RESTRICT_BUILDING
	if (!isbuilder(player) && !iswiz(player)) {
	  notify_player(player, "Only authorized builders may do that.\r\n");
	  return;
	}
#endif				/* RESTRICT_BUILDING */
	if (check_quota(player)) {
	  notify_player(player, "Sorry, you're over your limit.\r\n");
	  return;
	}
      }
    }
    if (set_int_elt(thing, OWNER, player) == -1)
      goto linkbomb;
    notify_player(player, "Trying to link...\r\n");
    break;
  default:
    notify_player(player, "I don't understand that.\r\n");
    warning("do_link", "bad type field detected");
    return;
  }

  if (!controls(player, thing)) {
    notify_player(player, "You don't own that!\r\n");
    return;
  }
  /* Link it up. */

  if (set_int_elt(thing, code, dest) == -1)
    goto linkbomb;
  notify_player(player, msg);
  return;

linkbomb:

  notify_bad(player);
  return;
}

voidfunc        do_unlink(player, arg)
  int             player;
  char           *arg;
{
  int             obj, flags, code;
  char           *msg;

  if (!arg || !*arg) {
    notify_player(player, "Unlink what?\r\n");
    return;
  }
  if ((obj = resolve_exit(player, arg)) == -1) {
    if ((obj = resolve_object(player, arg, 0)) == -1) {
      notify_player(player, "I can't find that.\r\n");
      return;
    }
  }
  if (obj == -2) {
    notify_player(player, "I can't tell which one you want to unlink.\r\n");
    return;
  }
  if (!controls(player, obj)) {
    notify_player(player, "You can't unlink that!\r\n");
    return;
  }
  /* Unlink it. */

  if (get_int_elt(obj, FLAGS, &flags) == -1)
    goto unlinkbomb;
  switch (flags & TYPE_MASK) {
  case TYP_PLAYER:
  case TYP_THING:
    notify_player(player, "Can't unset an object's home!\r\n");
    return;
  case TYP_EXIT:
    code = DESTINATION;
    msg = "Exit unlinked.\r\n";
    break;
  case TYP_ROOM:
    code = DROPTO;
    msg = "Dropto unset.\r\n";
    break;
  default:
    notify_player(player, "I don't understand that.\r\n");
    return;
  }

  if (set_int_elt(obj, code, -1) == -1)
    goto unlinkbomb;
  notify_player(player, msg);
  return;

unlinkbomb:

  notify_bad(player);
  return;
}

/*
 * the next two routines provide @edit service. yay. the code be based on
 * code found deep within TinyMUSH, with me own argument parser.
 */
static int      parse_attrib(player, s, thing, atr)
  int             player;
  char           *s;
  int            *thing;
  int            *atr;
{
  char            buff[1024];
  StringList     *strs;

  strcpy(buff, s);
  /* get name up to / */
  for (s = buff; *s && (*s != '/'); s++);
  if (!*s)
    return (0);
  *s++ = 0;
  if ((*thing = resolve_anything(player, buff, iswiz(player))) == -1)
    return (0);
  if (*thing == -2)
    return (-2);
  if (!exists_object(*thing) || !controls(player, *thing))
    return (0);
  /* rest is attrib name */

  for (strs = Strings; strs->code; strs++) {
    if (stringprefix(s, strs->name)) {
      *atr = strs->code;
      break;
    }
  }

  if (!strs->code)
    return (0);
  if (((*atr == NAME) && isplayer(*thing)) || *atr == SITE || *atr == PASSWORD)
    return (-1);

  return (1);
}

voidfunc        do_copy(player, first, second)
  int             player;
  char           *first, *second;
{
  int             ret, source, dest, satr, datr;
  char           *p, *buf = NULL, *msg;

  if (!first || !*first || !second || !*second) {
    notify_player(player, "Copy what to what?\r\n");
    return;
  }
  if ((ret = parse_attrib(player, first, &source, &satr)) == 0) {
    notify_player(player, "No match.\r\n");
    return;
  }
  if (ret == -2) {
    notify_player(player, "I can't tell which source object you mean.\r\n");
    return;
  }
  if (ret != 1) {
    notify_player(player, "Permission denied.\r\n");
    return;
  }
  if ((ret = parse_attrib(player, second, &dest, &datr)) == 0) {
    notify_player(player, "No match.\r\n");
    return;
  }
  if (ret == -2) {
    notify_player(player, "I can't tell which destination object you mean.\r\n");
    return;
  }
  if (ret != 1) {
    notify_player(player, "Permission denied.\r\n");
    return;
  }
  if (get_str_elt(source, satr, &p) == -1) {
    notify_bad(player);
    return;
  }
  if (!p || !*p) {
    notify_player(player, "Nothing to do.\r\n");
    return;
  }
#ifdef NO_ALLOCA
  buf = (char *) ty_malloc(strlen(p) + 1, "do_copy");
#else
  buf = (char *) alloca(strlen(p) + 1);
#endif
  (void) strcpy(buf, p);
  if (set_str_elt(dest, datr, buf) == -1) {
    notify_bad(player);
#ifdef NO_ALLOCA
    ty_free(buf);
#endif
    return;
  }
#ifdef NO_ALLOCA
  ty_free(buf);
#endif

  stamp(dest);

  switch (datr) {
  case NAME:
    msg = "Name set.\r\n";
    break;
  case DESC:
  case IDESC:
    msg = "Description set.\r\n";
    break;
  default:
    msg = "Message set.\r\n";
  }
  notify_player(player, msg);
}

voidfunc        do_edit(player, it, args)
  int             player;
  char           *it;
  char           *args;
{
  int             thing;
  int             atr, d, len;
  char           *r, *s, *val;
  char            dest[1024], arg1[BUFFSIZ], arg2[BUFFSIZ];

  if (!it || !*it) {
    notify_player(player, "Edit what?\r\n");
    return;
  }
  d = parse_attrib(player, it, &thing, &atr);
  if (d == 0) {
    notify_player(player, "No match.\r\n");
    return;
  } else if (d == -2) {
    notify_player(player, "I can't tell which one you want to edit.\r\n");
    return;
  } else if (d != 1) {
    notify_player(player,
		  "Permission denied.  You can't change that attribute on that object.\r\n");
    return;
  }
  /* parse arguments */
  if (!args || !*args) {
    notify_player(player, "Nothing to do.\r\n");
    return;
  }
  d = 0;
  /* make arg1 */
  /* eat this pointer game, xibo  ;-) */
  while (d < (BUFFSIZ - 32) && args[0] != 0) {
    if (args[0] != ',' && args[0] != '\\') {
      arg1[d] = *args++;
      d++;
    } else {
      if (args[0] == '\\' && args[1] != ',') {
	arg1[d] = *args++;
	d++;
      } else {
	if (args[0] == '\\' && args[1] == ',') {
	  arg1[d] = args[1];
	  args += 2;
	  d++;
	} else {
	  arg1[d] = 0;
	  d++;
	  args++;
	  break;
	}
      }
    }
  }
  arg1[d] = 0;
  /* make arg2 */
  d = 0;
  while (d < (BUFFSIZ - 32) && args[d] != 0) {
    arg2[d] = args[d];
    d++;
  }
  arg2[d] = 0;

  if (arg1[0] == 0) {
    notify_player(player, "Nothing to do.\r\n");
    return;
  }
  val = arg1;
  r = (arg2[0]) ? arg2 : (char *) "";

  /* replace all occurances of val with r */
  if (get_str_elt(thing, atr, &s) == -1) {
    warning("do_edit", "bad object ref");
    notify_bad(player);
    return;
  }
  if (!s || !*s) {
    notify_player(player, "Nothing to do.\r\n");
    return;
  }
  len = strlen(val);
  for (d = 0; (d < 1000) && *s;)
    if (strncmp(val, s, len) == 0) {
      if ((d + strlen(r)) < 1000) {
	strcpy(dest + d, r);
	d += strlen(r);
	s += len;
      } else
	dest[d++] = *s++;
    } else
      dest[d++] = *s++;
  dest[d++] = 0;

  dest[BUFFSIZ - 1] = '\0';
  if (set_str_elt(thing, atr, dest) == -1) {
    warning("do_edit", "failed to store revised string");
    notify_bad(player);
    return;
  }
  switch (atr) {
  case DESC:
  case IDESC:
    notify_player(player, "Description set.\r\n");
    break;
  case NAME:
    notify_player(player, "Name set.\r\n");
    break;
  default:
    notify_player(player, "Message set.\r\n");
  }
  if (!isplayer(thing)) {
    stamp(thing);
  }
}