dbm/
misc/
old-docs/
/* cmds.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>

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

/*
 * These routines, together with those in buildcmds.c, wiz.c and speech.c
 * actually implement the commands of TeenyMUD. Hrm. Actually WHO and QUIT
 * are caught in the network interface code.
 */

/*
 * Workspace for building strings. None of this sprintf() shit. A little
 * extra space so we can be non-anal about counting.
 */

char            cmdwork[LARGEBUFFSIZ];

void            do_home(player)
  int             player;
{
  int             here, home, list, next;
  char           *name;

  if (get_int_elt(player, HOME, &home) == -1)
    goto homebomb;
  if (!exists_object(home)) {
    notify_player(player, "Your home does not exist!\r\n");
    home = STARTING_LOC;
  }
  if (get_int_elt(player, LOC, &here) == -1)
    goto homebomb;

  /* Tell people here. */

  name = getname(player);

  if (!isdark(here) && !isdark(player)) {
    (void) sprintf(cmdwork, "%s goes home.\r\n%s has left.\r\n", name, name);
    notify_oall(player, cmdwork);
  }
  send_home(player, here);

  if (isroom(here))
    flush_room(here);

  if (!isdark(player) && !isdark(home)) {
    (void) sprintf(cmdwork, "%s has arrived.\r\n", name);
    notify_oall(player, cmdwork);
  }
  /* Send all the player's stuff home too */

  if (get_int_elt(player, CONTENTS, &list) == -1)
    goto homebomb;
  while (list != -1) {
    /* send_home() will change the NEXT element of list */

    if (get_int_elt(list, NEXT, &next) == -1)
      goto homebomb;
    if (isplayer(list))
      notify_player(player, "You feel a wrenching sensation...\r\n");
    send_home(list, player);
    if (isplayer(list)) {
      sprintf(cmdwork, "%s has arrived.\r\n", getname(list));
      notify_oall(list, cmdwork);
      do_look(list, (char *) NULL);
    }
    list = next;
  }
  /* Tell the player */

  notify_player(player, "There's no place like home...\r\n");
  notify_player(player, "There's no place like home...\r\n");
  notify_player(player, "There's no place like home...\r\n");
  notify_player(player, "You wake up back home, without your possessions.\r\n");

  do_look(player, (char *) NULL);
  return;

homebomb:

  notify_bad(player);
  return;
}

voidfunc        do_drop(player, arg)
  int             player;
  char           *arg;
{
  int             here, obj, flags, dest, hereflags;

  if (!arg || !*arg) {
    notify_player(player, "Drop what?\r\n");
    return;
  }
  if ((obj = match_here(player, player, arg, MAT_THINGS | MAT_PLAYERS)) == -1) {
    if ((obj = match_here(player, player, arg, MAT_EXITS)) == -1) {
      notify_player(player, "You don't have that!\r\n");
      return;
    }
  }
  if (obj == -2) {
    notify_player(player, "I can't tell which one you want to drop.\r\n");
    return;
  }
  if (get_int_elt(obj, FLAGS, &flags) == -1)
    goto dropbomb;
  if (get_int_elt(player, LOC, &here) == -1)
    goto dropbomb;

  switch (flags & TYPE_MASK) {
  case TYP_EXIT:
    sprintf(cmdwork, "You can't drop exits. Use \"@attach %s = here\", instead.\r\n", arg);
    notify_player(player, cmdwork);
    return;
  case TYP_THING:
    if ((flags & DARK) && !controls(player, here)) {
      notify_player(player, "You can't drop that here.\r\n");
      return;
    }
  case TYP_PLAYER:

    /* Figure out where it's supposed to go */

    if (get_int_elt(here, FLAGS, &hereflags) == -1)
      goto dropbomb;

    if (flags & STICKY) {

      /* If the object is STICKY, send the object to home if you can.     */

      if (get_int_elt(obj, HOME, &dest) == -1)
	goto dropbomb;

    } else if (!(hereflags & STICKY)) {

      /* If this place is !STICKY, see if there's a dropto */

      if (get_int_elt(here, DROPTO, &dest) == -1)
	goto dropbomb;

      if (dest == -1 || !isroom(here)) {	/* No dropto */
	dest = here;
      } else if (dest == -3) {	/* Dropto home */
	if (get_int_elt(obj, HOME, &dest) == -1)
	  goto dropbomb;
      }
    } else {
      dest = here;
    }
    list_drop(obj, player, CONTENTS_LIST);

    stamp(obj);

    if (isplayer(obj)) {
      (void) strcpy(cmdwork, getname(player));
      (void) strcat(cmdwork, " drops you.\r\n");
      notify_player(obj, cmdwork);
    }
    /* Tell the room */

    (void) strcpy(cmdwork, "dropped ");
    (void) strcat(cmdwork, getname(obj));

    act_object(player, obj, DROP, ODROP, -1, (char *) NULL, cmdwork);

    if (dest != here)
      act_object(obj, here, DROP, ODROP, -1, (char *) NULL, (char *) NULL);

    list_add(obj, dest, CONTENTS_LIST);

    break;
  default:
    notify_player(player, "You have no business carrying that!\r\n");
    return;
  }
  if (set_int_elt(obj, LOC, dest) == -1)
    goto dropbomb;
  if (isplayer(obj)) {
    (void) strcpy(cmdwork, getname(obj));
    (void) strcat(cmdwork, " has arrived.\r\n");
    notify_oall(obj, cmdwork);
    do_look(obj, (char *) NULL);
  }
  notify_player(player, "Dropped.\r\n");
  return;
dropbomb:
  notify_bad(player);
  return;
}

voidfunc        do_examine(player, arg)
  int             player;
  char           *arg;
{
  int             obj, num, len, flags;
  int            *lock;
  char           *p, *msg;
  long            timestamp;
  StringList     *strs;
  extern char    *ctime();

  if (!arg || !*arg) {
    if (get_int_elt(player, LOC, &obj) == -1)
      goto exbomb;
  } else {
    if ((obj = resolve_anything(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 mean.\r\n");
      return;
    }
  }
  if (!exists_object(obj)) {
    notify_player(player, "No such object.\r\n");
    return;
  }
  if (!controls(player, obj)) {
    if (get_str_elt(obj, DESC, &p) == -1)
      goto exbomb;
    if (p && *p) {
      notify_player(player, p);
      notify_player(player, "\r\n");
    }
    /* Owner */
    if (get_int_elt(obj, OWNER, &num) == -1)
      goto exbomb;
    sprintf(cmdwork, "Owner: %s\r\n", getname(num));
    notify_player(player, cmdwork);
    return;
  }
  if (get_int_elt(obj, FLAGS, &flags) == -1)
    goto exbomb;

  /* OK. Get this things data, and print it out! */
  /* name */
  (void) sprintf(cmdwork, "%s\r\n", stuff_name(player, obj));
  notify_player(player, cmdwork);

  /* Owner */

  if (get_int_elt(obj, OWNER, &num) == -1)
    goto exbomb;
  sprintf(cmdwork, "Owner: %s", getname(num));
  notify_player(player, cmdwork);

  if (get_lock_elt(obj, LOCK, &lock) == -1)
    goto exbomb;
  notify_player(player, "  Key: ");
  if (bool_display(player, lock, cmdwork, BUFFSIZ - 2) == -1) {
    notify_player(player, "*BAD LOCK*");
  } else {
    notify_player(player, cmdwork);
  }

  if (isplayer(obj)) {
    if (get_int_elt(obj, QUOTA, &num) == -1)
      goto exbomb;
    sprintf(cmdwork, "  Quota: %d", num);
    notify_player(player, cmdwork);
  }
  notify_player(player, "\r\n");

#ifdef VERBOSE_FLAGS
  notify_player(player, display_flags(obj));
#endif

  if (get_int_elt(obj, TIMESTAMP, &num) == -1)
    goto exbomb;
  timestamp = (long) num;
  if (isplayer(obj))
    (void) strcpy(cmdwork, "Last: ");
  else
    (void) strcpy(cmdwork, "Timestamp: ");

  strcat(cmdwork, ctime(&timestamp));
  if (isplayer(obj)) {
    char           *q;

    q = cmdwork + (strlen(cmdwork) - 1);
    if (get_str_elt(obj, SITE, &p) == -1)
      goto exbomb;
    sprintf(q, " from %s\r\n", (p && *p) ? p : "???");
  } else
    fix_newline(cmdwork);
  notify_player(player, cmdwork);

  if (get_lock_elt(obj, ELOCK, &lock) == -1)
    goto exbomb;
  if ((len = bool_display(player, lock, cmdwork, BUFFSIZ - 2)) == -1) {
    (void) strcpy(cmdwork, "*BAD LOCK*");
  }
  if (len != 1) {
    (void) strcat(cmdwork, "\r\n");
    notify_player(player, "Enter Key: ");
    notify_player(player, cmdwork);
  }
  for (strs = Strings; strs->code; strs++) {
    if (!(strs->flag & STR_DARK)) {
      if (get_str_elt(obj, strs->code, &p) == -1)
	goto exbomb;
      if (p != NULL) {
	(void) sprintf(cmdwork, "%s: %s\r\n", strs->name, p);
	notify_player(player, cmdwork);
      }
    }
  }

  /* home NOTE: Home == DropTo == Dest, depending on object type */
  if (get_int_elt(obj, HOME, &num) == -1)
    goto exbomb;
  switch (flags & TYPE_MASK) {
  case TYP_ROOM:
    (void) strcpy(cmdwork, "Dropto: ");
    if (num == -3)
      msg = "*HOME*\r\n";
    else
      msg = "None.\r\n";
    break;
  case TYP_EXIT:
    (void) strcpy(cmdwork, "Destination: ");
    if (num == -3)
      msg = "*HOME*\r\n";
    else
      msg = "*UNLINKED*\r\n";
    break;
  case TYP_THING:
  case TYP_PLAYER:
    (void) strcpy(cmdwork, "Home: ");
    msg = "Does not exist!\r\n";
    break;
  }
  if (exists_object(num)) {
    (void) strcat(cmdwork, stuff_name(player, num));
    (void) strcat(cmdwork, "\r\n");
    notify_player(player, cmdwork);
  } else {
    (void) strcat(cmdwork, msg);
    notify_player(player, cmdwork);
  }
  /* location */

  if (get_int_elt(obj, LOC, &num) == -1)
    goto exbomb;
  if (exists_object(num)) {
    (void) sprintf(cmdwork, "%s: %s\r\n", ((flags & TYPE_MASK) == TYP_ROOM) ?
		   "Parent" : "Location", stuff_name(player, num));
  } else {
    (void) sprintf(cmdwork, "%s does not exist! Object number: %d\r\n",
	    ((flags & TYPE_MASK) == TYP_ROOM) ? "Parent" : "Location", num);
  }
  notify_player(player, cmdwork);

  if (!isexit(obj)) {
    /* contents list */
    if (get_int_elt(obj, CONTENTS, &num) == -1)
      goto exbomb;
    if (num != -1) {
      notify_player(player, (isroom(obj)) ? "Contents:\r\n" :
		    ((isplayer(obj)) ? "Carrying:\r\n" : "Containing:\r\n"));
      /* last arg == 1 == show dark objects. */
      notify_list(player, num, cmdwork, BUFFSIZ, 1);
    } else {
      notify_player(player, "No contents.\r\n");
    }
    /* exits list */
    if (get_int_elt(obj, EXITS, &num) == -1)
      goto exbomb;
    if (num != -1) {
      notify_player(player, "Exits:\r\n");
      /* last arg == 1 == show dark objects */
      notify_list(player, num, cmdwork, BUFFSIZ, 1);
    } else {
      notify_player(player, "No exits.\r\n");
    }
  }
  return;
exbomb:
  notify_bad(player);
  return;
}

voidfunc        do_take(player, arg)
  int             player;
  char           *arg;
{
  int             here, obj, flags;

  if (!arg || !*arg) {
    notify_player(player, "Take what?\r\n");
    return;
  }
  if (get_int_elt(player, LOC, &here) == -1)
    goto takebomb;
  if ((obj = match_here(player, here, arg, MAT_THINGS)) == -1) {
    if ((obj = match_here(player, here, arg, MAT_EXITS)) == -1) {
      if ((obj = match_here(player, here, arg, MAT_PLAYERS)) == -1) {
	notify_player(player, "I don't see that here.\r\n");
	return;
      }
    }
  }
  if (obj == -2) {
    notify_player(player, "I can't tell which one you mean.\r\n");
    return;
  }
  if (get_int_elt(obj, FLAGS, &flags) == -1)
    goto takebomb;

  switch (flags & TYPE_MASK) {
  case TYP_EXIT:
    sprintf(cmdwork, "You can't pick up exits. Use \"@attach %s = me\", instead.\r\n", arg);
    notify_player(player, cmdwork);
    return;
  case TYP_THING:
  case TYP_PLAYER:

    /* If it's unlocked, you can take it */

    if (islocked(player, obj, LOCK)) {
      act_object(player, obj, FAIL, OFAIL, -1, "You can't take that.",
		 (char *) NULL);
      stamp(obj);
      return;
    }
    /* Do the succ/osucc */

    (void) strcpy(cmdwork, "takes ");
    (void) strcat(cmdwork, getname(obj));
    (void) strcat(cmdwork, ".");
    act_object(player, obj, SUC, OSUC, -1, (char *) NULL, cmdwork);
    if (isplayer(obj)) {
      (void) strcpy(cmdwork, getname(player));
      (void) strcat(cmdwork, " picks you up.\r\n");
      notify_player(obj, cmdwork);
      (void) strcpy(cmdwork, getname(obj));
      (void) strcat(cmdwork, " has left.\r\n");
      notify_oall(obj, cmdwork);
    }
    /* Drop it from contents list here. */

    list_drop(obj, here, CONTENTS_LIST);

    /* Add to player contenst list */

    list_add(obj, player, CONTENTS_LIST);
    stamp(obj);
    break;
  default:
    notify_player(player, "You can't take that!\r\n");
    return;
  }
  if (set_int_elt(obj, LOC, player) == -1)
    goto takebomb;
  if (isplayer(obj)) {
    (void) sprintf(cmdwork, "%s has arrived.\r\n", getname(obj));
    notify_oall(obj, cmdwork);
    do_look(obj, (char *) NULL);
  }
  notify_player(player, "Taken.\r\n");
  return;
takebomb:
  notify_bad(player);
  return;
}

voidfunc        do_go(player, arg)
  int             player;
  char           *arg;
{
  struct match   *exlist;
  int             here, list, count;

  if (!arg || !*arg) {
    notify_player(player, "Go where?\r\n");
    return;
  }
  if (!strcasecmp(arg, "home")) {
    do_home(player);
    return;
  }
  if (get_int_elt(player, LOC, &here) == -1)
    goto gobomb;
  if (get_int_elt(here, EXITS, &list) == -1)
    goto gobomb;

  if ((exlist = match_exits(arg, list, &count, MAT_INTERNAL)) != NULL) {

    /* Ok. We have a list of exits. Cope with 'em. */

    do_go_attempt(player, here, exlist);
    return;
  } else {
    int             parent, contents;

    /* check EXTERNAL exits on player */
    if (get_int_elt(player, EXITS, &list) == -1)
      goto gobomb;
    if ((exlist = match_exits(arg, list, &count, MAT_EXTERNAL)) != NULL) {
      do_go_attempt(player, here, exlist);
      return;
    }
    /* check EXTERNAL exits on contents */
    if (get_int_elt(here, CONTENTS, &contents) == -1)
      goto gobomb;
    while (contents != -1) {
      if (!isplayer(contents)) {
	if (get_int_elt(contents, EXITS, &list) == -1)
	  goto gobomb;
	if ((exlist = match_exits(arg, list, &count, MAT_EXTERNAL)) != NULL) {
	  do_go_attempt(player, here, exlist);
	  return;
	}
      }
      if (get_int_elt(contents, NEXT, &contents) == -1)
	goto gobomb;
    }
    /* check parents */
    if (isroom(here)) {
      parent = here;
      do {
	if (get_int_elt(parent, LOC, &parent) == -1)
	  goto gobomb;
	if (get_int_elt(parent, EXITS, &list) == -1)
	  goto gobomb;
	if ((exlist = match_exits(arg, list, &count, MAT_INTERNAL)) != NULL) {
	  do_go_attempt(player, here, exlist);
	  return;
	}
      } while (parent != ROOT_PARENT);
    } else {
      if (get_int_elt(ROOT_PARENT, EXITS, &list) == -1)
	goto gobomb;
      if ((exlist = match_exits(arg, list, &count, MAT_INTERNAL)) != NULL) {
	do_go_attempt(player, here, exlist);
	return;
      }
    }
  }

  notify_player(player, "You can't go that way.\r\n");
  return;
gobomb:
  notify_bad(player);
  return;
}
voidfunc        do_gripe(player, gripe)
  int             player;
  char           *gripe;
{
  char           *name;

  if (gripe == NULL) {
    notify_player(player, "What do you wish to gripe about?\r\n");
    return;
  }
  name = getname(player);
  log_gripe("GRIPE: From %s(#%d), \"%s\"\n", name, player, gripe);

  if (!issticky(PLAYER_GOD)) {
    (void) sprintf(cmdwork, "GRIPE: From %s, \"%s\"\r\n", name, gripe);
    notify_player(PLAYER_GOD, cmdwork);
  }
  notify_player(player, "Your complaint has been duly noted.\r\n");
  return;
}

voidfunc        do_inventory(player)
  int             player;
{
  int             list, header;

  header = 0;
  if (get_int_elt(player, CONTENTS, &list) == -1)
    goto invbomb;

  if (list != -1) {
    notify_player(player, "You are carrying:\r\n");
    header = 1;
    notify_list(player, list, cmdwork, BUFFSIZ, 1);
  }
  if (get_int_elt(player, EXITS, &list) == -1)
    goto invbomb;

  if (list != -1) {
    if (!header) {
      notify_player(player, "You are carrying:\r\n");
      header = 1;
    }
    notify_list(player, list, cmdwork, BUFFSIZ, 1);
  }
  if (!header)
    notify_player(player, "You aren't carrying anything.\r\n");
  return;
invbomb:
  notify_bad(player);
  return;
}

voidfunc        do_kill(player, argone)
  int             player;
  char           *argone;
{
  int             here, victim;
  int             list, next;

  if (!argone || !*argone) {
    notify_player(player, "Who would you like to kill?\r\n");
    return;
  }
  if (ishaven(player)) {
    notify_player(player, "You may not kill anyone.\r\n");
    return;
  }
  /* Find who we are supposed to kill */

  if (get_int_elt(player, LOC, &here) == -1)
    goto killbomb;
  if (ishaven(here) && !iswiz(player)) {
    notify_player(player, "It's too peaceful here.\r\n");
    return;
  }
  if ((victim = match_here(player, here, argone, MAT_PLAYERS)) == -1) {
    notify_player(player, "I don't see that player here.\r\n");
    return;
  }
  if (victim == -2) {
    notify_player(player, "I can't tell which person you want to kill.\r\n");
    return;
  }
  /* Have a whack at it. */

  if (iswiz(victim) && !iswiz(player)) {
    /* Fail the kill */

    notify_player(player, "Your kill attempt failed.\r\n");
    (void) sprintf(cmdwork, "%s tried to kill you!\r\n", getname(player));
    notify_player(victim, cmdwork);
  } else {
    /* The kill succeeded! Do it! */

    (void) sprintf(cmdwork, "%s killed you!\r\n", getname(player));
    notify_player(victim, cmdwork);

    /* Tell everyone. */

    (void) strcpy(cmdwork, "killed ");
    (void) strcat(cmdwork, getname(victim));
    (void) strcat(cmdwork, "!");

    act_object(player, victim, KILL, OKILL, -1, (char *) 0, cmdwork);

    (void) sprintf(cmdwork, "%s has left.\r\n", getname(victim));
    notify_oall(victim, cmdwork);

    /* Send the victim home. */

    send_home(victim, here);
    (void) sprintf(cmdwork, "%s has arrived.\r\n", getname(victim));
    notify_oall(victim, cmdwork);

    flush_room(here);

    /* Send all the player's stuff home too */

    if (get_int_elt(victim, CONTENTS, &list) == -1)
      goto killbomb;
    while (list != -1) {

      /* send_home() will change the NEXT element of list */

      if (get_int_elt(list, NEXT, &next) == -1)
	goto killbomb;
      send_home(list, victim);
      list = next;
    }
    do_look(victim, (char *) NULL);

  }
  return;
killbomb:
  notify_bad(player);
  return;
}

voidfunc        do_look(player, arg)
  int             player;
  char           *arg;
{
  int             here, contents, exits;
  int             obj, loc;
  char           *str;

  if (arg && *arg) {
    /* Look at a thing. */

    if (get_int_elt(player, LOC, &here) == -1)
      goto lookbomb;
    if ((obj = resolve_object(player, arg, iswiz(player))) == -1) {
      if ((obj = resolve_exit(player, arg)) == -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 (obj == -3) {
      notify_player(player, "I don't see that here.\r\n");
      return;
    }
    if (obj == here) {
      goto dropthru;
    }
    if (get_int_elt(obj, LOC, &loc) == -1)
      goto lookbomb;
    if ((loc != here && loc != player && !iswiz(player)) || isroom(obj)) {
      notify_player(player, "That's much too far away to see.\r\n");
      return;
    }
    if (!isplayer(obj))
      stamp(obj);

    act_object(player, obj, DESC, ODESC, -1, "You see nothing special.",
	       (char *) NULL);

    if (get_int_elt(obj, CONTENTS, &contents) == -1)
      goto lookbomb;

    if (contents != -1) {
      notify_player(player, "Carrying:\r\n");

      /* last argument: 0 == No dark objs. */
      notify_list(player, contents, cmdwork, BUFFSIZ, 0);
    }
    return;
  }
dropthru:

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

  /* Grab and show the name */

  (void) sprintf(cmdwork, "%s\r\n", stuff_name(player, here));
  notify_player(player, cmdwork);

  /* The desc. */

  act_object(player, here, (isroom(here)) ? DESC : IDESC, ODESC, -1,
	     (char *) NULL, (char *) NULL);
  if (isroom(here)) {
    if (get_str_elt(here, IDESC, &str) == -1)
      goto lookbomb;
    if (str != NULL) {
      (void) sprintf(cmdwork, "%s\r\n", str);
      notify_player(player, cmdwork);
    }
  }
  /* Do the room succ/osucc thing */

  if (isroom(here)) {
    if (islocked(player, here, LOCK)) {
      act_object(player, here, FAIL, OFAIL, -1, (char *) NULL, (char *) NULL);
    } else {
      act_object(player, here, SUC, OSUC, -1, (char *) NULL, (char *) NULL);
    }
  }
  /* Finally spew out the contents list, if the room is unDARK */

  if (can_see_anything(player, here)) {
    if (get_int_elt(here, CONTENTS, &contents) == -1) {
      warning("do_look", "bad contents ref on room");
      notify_bad(player);
      return;
    }
    notify_player(player, "Contents:\r\n");
    /* last arg == 0 == no dark objects */
    notify_list(player, contents, cmdwork, BUFFSIZ, 0);
  }
  if (get_int_elt(here, EXITS, &exits) == -1) {
    warning("do_look", "bad exits ref on room");
    return;
  }
  notify_exits(player, exits);

  return;
lookbomb:
  notify_bad(player);
  return;
}

voidfunc        do_password(player, argone, argtwo)
  int             player;
  char           *argone, *argtwo;
{
  char           *pwd;

  if (!argone || !*argone) {
    notify_player(player,
		  "Usage: @password <oldpassword> = <newpassword>\r\n");
    return;
  }
  if (get_str_elt(player, PASSWORD, &pwd) == -1)
    goto passbomb;
  if (!pwd || !*pwd) {
    notify_player(player, "You have no password!\r\n");
    return;
  }
  if (strcmp(pwd, crypt(argone, CRYPT_KEY)) != 0) {
    notify_player(player, "Incorrect password.\r\n");
    return;
  }
  if (set_str_elt(player, PASSWORD, crypt(argtwo, CRYPT_KEY)) == -1)
    goto passbomb;
  notify_player(player, "Password changed.\r\n");
  return;
passbomb:
  notify_bad(player);
  return;
}

voidfunc        do_set(player, argone, argtwo)
  int             player;
  char           *argone, *argtwo;
{
  int             obj, unset, newflag, objflags;
  char           *msg;

  if (!argtwo || !*argtwo) {
    notify_player(player, "Set what?\r\n");
    return;
  }
  if ((obj = resolve_object(player, argone, 0)) == -1) {
    if ((obj = resolve_exit(player, argone)) == -1) {
      notify_player(player, "I can't find what you want to set.\r\n");
      return;
    }
  }
  if (obj == -2) {
    notify_player(player, "I can't tell which one you want to set.\r\n");
    return;
  }
  if (!exists_object(obj) || !controls(player, obj)) {
    notify_player(player, "You can't set anything on that!\r\n");
    return;
  }
  /* Okie. What's this doof want to set? */

  if (*argtwo == '!') {
    unset = 1;
    argtwo++;
  } else {
    unset = 0;
  }
  switch (UPCASE(argtwo[0])) {
  case 'G':
    switch (UPCASE(argtwo[1])) {
    case 'O':
      if (!isgod(player)) {
	notify_player(player, "Permission denied, doof.\r\n");
	return;
      }
      if (obj == PLAYER_GOD && unset) {
	notify_player(player, "That player is always God.\r\n");
	return;
      }
      newflag = GOD;
      break;
    case 'U':
      if (!iswiz(player)) {
	notify_player(player, "Permission denied, doof.\r\n");
	return;
      }
      newflag = GUEST;
      break;
    default:
      notify_player(player, "I don't understand the flag.\r\n");
      return;
    }
    break;
  case 'L':
    newflag = LINK_OK;
    break;
  case 'S':
    newflag = STICKY;
    break;
  case 'D':
    if (!iswiz(player)) {
      int             loc;

      if (isplayer(obj)) {
	notify_player(player, "Permission denied, doof.\r\n");
	return;
      }
      if (isthing(obj)) {
	if (get_int_elt(obj, LOC, &loc) == -1)
	  goto setbomb;
	if (!controls(player, loc)) {
	  notify_player(player, "You must pick it up, first.\r\n");
	  return;
	}
      }
    }
    newflag = DARK;
    break;
  case 'W':
    if (!isgod(player)) {
      notify_player(player, "Permission denied, doof.\r\n");
      return;
    }
    newflag = WIZARD;
    break;
  case 'R':
    if (!iswiz(player)) {
      notify_player(player, "Permission denied, doof.\r\n");
      return;
    }
    if (!isplayer(obj)) {
      notify_player(player, "You can't set that on that.\r\n");
      return;
    }
    newflag = ROBOT;
    break;
  case 'J':
    newflag = JUMP_OK;
    break;
  case 'A':
    switch (UPCASE(argtwo[1])) {
    case 'B':
      if (isexit(obj)) {
	notify_player(player, "You can't set that flag on an exit.\r\n");
	return;
      }
      newflag = ABODE;
      break;
    case 'C':
      if (!isexit(obj)) {
	notify_player(player, "You can't set that flag on that.\r\n");
	return;
      }
      newflag = ACTION;
      break;
    default:
      notify_player(player, "I don't understand that flag.\r\n");
      return;
    }
    break;
  case 'O':
    if (!isexit(obj)) {
      notify_player(player, "You can only set that flag on an exit.\r\n");
      return;
    }
    newflag = ABODE;
    break;
  case 'H':
    if ((!iswiz(player) && isroom(obj)) || iswiz(player))
      newflag = HAVEN;
    else {
      notify_player(player, "Permission denied, doof.\r\n");
      return;
    }
    break;
#if defined(RESTRICT_BUILDING) || defined(BUILDING_OK)
  case 'B':
    if ((!iswiz(player) && isroom(obj)) || iswiz(player))
      newflag = BUILDER;
    else {
      notify_player(player, "Permission denied, doof.\r\n");
      return;
    }
    break;
#endif
  case 'E':
    switch (UPCASE(argtwo[1])) {
    case 'N':
      if (isexit(obj)) {
	notify_player(player, "You can't set that flag on an exit.\r\n");
	return;
      }
      newflag = ENTER_OK;
      break;
    case 'X':
      if (!isexit(obj)) {
	notify_player(player, "You can only set that flag on an exit.\r\n");
	return;
      }
      newflag = EXTERNAL;
      break;
    default:
      notify_player(player, "I don't understand that flag.\r\n");
      return;
    }
    break;
  case 'M':
    if (!isplayer(obj)) {
      notify_player(player, "You can only set gender on a player.\r\n");
      return;
    }
    if (isfemale(obj) || isneuter(obj)) {
      notify_player(player, (player == obj) ?
		    "You already have a gender. Unset it, first.\r\n" :
		    "They already have a gender. Unset it, first.\r\n");
      return;
    }
    newflag = GENDER_MALE;
    break;
  case 'F':
    if (!isplayer(obj)) {
      notify_player(player, "You can only set gender on a player.\r\n");
      return;
    }
    if (ismale(obj) || isneuter(obj)) {
      notify_player(player, (player == obj) ?
		    "You already have a gender. Unset it, first.\r\n" :
		    "They already have a gender. Unset it, first.\r\n");
      return;
    }
    newflag = GENDER_FEMALE;
    break;
  case 'N':
    if (!isplayer(obj)) {
      notify_player(player, "You can only set gender on a player.\r\n");
      return;
    }
    if (ismale(obj) || isfemale(obj)) {
      notify_player(player, (player == obj) ?
		    "You already have a gender. Unset it, first.\r\n" :
		    "They already have a gender. Unset it, first.\r\n");
      return;
    }
    newflag = GENDER_NEUTER;
    break;
  default:
    notify_player(player, "I don't understand that flag.\r\n");
    return;
  }

  /* Set the flags */

  if (!isplayer(obj))
    stamp(obj);

  if (get_int_elt(obj, FLAGS, &objflags) == -1)
    goto setbomb;

  if (unset) {
    objflags &= ~newflag;
    msg = "Flag unset.\r\n";
  } else {
    objflags |= newflag;
    msg = "Flag set.\r\n";
  }
  if (set_int_elt(obj, FLAGS, objflags) == -1)
    goto setbomb;
  notify_player(player, msg);

  return;
setbomb:
  notify_bad(player);
  return;
}
voidfunc        do_recycle(player, arg)
  int             player;
  char           *arg;
{
  int             obj, loc;

#ifdef RESTRICT_BUILDING
  if (!isbuilder(player) && !iswiz(player)) {
    notify_player(player, "Only authorized builders may recycle things.\r\n");
    return;
  }
#endif
  if (!arg || !*arg) {
    notify_player(player, "Recycle what?\r\n");
    return;
  }
  if (get_int_elt(player, LOC, &loc) == -1) {
    warning("do_recycle", "bad loc ref on player");
    return;
  }
  if ((obj = match_here(player, player, arg, MAT_THINGS | MAT_EXITS)) == -1) {
    if ((obj = match_here(player, loc, arg, MAT_THINGS | MAT_EXITS)) == -1) {
      if (!strcmp(arg, "here")) {
	obj = loc;
      } else {
	if (*arg == '#' && *(arg + 1) && exists_object(atoi(arg + 1))) {
	  obj = atoi(arg + 1);
	} else {
	  notify_player(player, "I can't find what you want to recycle.\r\n");
	  return;
	}
      }
    }
  }
  if (obj == -2) {
    notify_player(player, "I can't tell which one you want to recycle.\r\n");
    return;
  }
  if (!controls(player, obj)) {
    notify_player(player, "You don't own that!\r\n");
    return;
  }
  if (obj == 0) {
    notify_player(player, "You may not recycle object Zero.\r\n");
    return;
  }
#if STARTING_LOC != 0
  if (obj == STARTING_LOC) {
    notify_player(player, "You may not recycle that.\r\n");
    return;
  }
#endif
#if ROOT_PARENT != 0
  if (obj == ROOT_PARENT) {
    notify_player(player, "You may not recycle that.\r\n");
    return;
  }
#endif

  if (isplayer(obj)) {
    notify_player(player, "You can't recycle players.\r\n");
    return;
  }
  if (recycleobj(obj) > 0) {
    notify_player(player, "Thank you for recycling.\r\n");
  } else {
    notify_bad(player);
  }
}
voidfunc        do_version(player)
  int             player;
{
  extern char    *gdbm_version;

  (void) sprintf(cmdwork, "The code running is %s.\r\n%s\r\n", version,
		 gdbm_version);
  notify_player(player, cmdwork);
}