/
teeny/db/
teeny/dbm/
teeny/docs/
teeny/includes/
teeny/misc/
teeny/news/
teeny/text/
/* cmdutils.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"

/*
 * Utility functions for use by the command handlers in cmds.c, speech.c,
 * wiz.c and buildcmds.c 
 */

#ifdef OLD_RAND
long            rand();
#else
long            random();
#endif					/* OLD_RAND */

/*
 * A work buffer. Different from the one in cmds.c/buildcmds.c, though it
 * probably need not be. 
 */

char            work[BUFFSIZ + 64];

/*
 * Send an thing IN A CONTENTS LIST home. 
 */

void 
send_home(obj, loc)
  int             obj;
  int             loc;
{
  int             home, next;

  if (get_int_elt(obj, HOME, &home) == -1)
  {
    warning("send_home", "could not get home");
    return;
  }
  list_drop(obj, loc, 1);	/* Drop it from contents list here */

  if (!exists_object(home))
  {
    home = STARTING_LOC;	/* Fake it, eh? */
  }
  if (set_int_elt(obj, LOC, home) == -1)
  {
    warning("send_home", "could not set location");
    return;
  }
  if (get_int_elt(home, CONTENTS, &next) == -1)
  {
    warning("send_home", "could not get contents");
    return;
  }
  if (set_int_elt(obj, NEXT, next) == -1)
  {
    warning("send_home", "could not set next");
    return;
  }
  if (set_int_elt(home, CONTENTS, obj) == -1)
  {
    warning("send_home", "could not set contents");
    return;
  }
}

/*
 * Resolves a string into an object reference, if it can. The last parameter
 * is a flag. Returns -1 if no matching object, -2 if ambiguous. This routine
 * now *only* matches non-exits. If you want exits matched, call either
 * resolve_exit() or resolve_anything().  To match objects and exits
 * correctly, call resolve_object_or_exit().
 */
int 
resolve_object(player, name, splat_ok)
  int             player;
  char           *name;
  int             splat_ok;
{
  int             matched, location;
  int             match1, match2, match3;
  int             flags;

  if (*name == '#' && isdigit(name[1]))
  {
    name++;
    matched = atoi(name);
    if (exists_object(matched) && !isexit(matched))
    {
	return (matched);
    } else
    {
	return (-1);
    }
  }
  /* Check these first.  Don't want to confuse these. */
  if (get_int_elt(player, LOC, &location) == -1)
  {
    warning("resolve_object", "bad location");
    return (-1);
  }

  if (strcmp("here", name) == 0)
  {
     if(get_int_elt(player, LOC, &location) == -1){
       warning("resolve_object", "couldn't get player's location");
       return(-1); /* no match, hehe */
     }
    return (location);
  }
  if (strcmp("me", name) == 0)
  {
    return (player);
  }

  /* if match_here tells us "tie" then we return the info immediately. */

/*
  if((match1 = match_here(player, player, name, MAT_THINGS)) == -2)
    return (-2);
  if((match2 = match_here(player, location, name, MAT_THINGS)) == -2)
    return (-2);
  if((match3 = match_here(player, location, name, MAT_PLAYERS)) == -2)
    return (-2);
*/
  match1 = match_here(player, player, name, MAT_THINGS);
  match2 = match_here(player, location, name, MAT_THINGS);
  match3 = match_here(player, location, name, MAT_PLAYERS);

  if ((match1 == -1) && (match2 == -1) && (match3 == -1))
  {

    /*
     * OK. Last ditch. If this player's a wiz or we're splat_ok, try
     * *<playername>. 
     */

    if (*name == '*')
    {
      if (!splat_ok)
      {				/* If not a Wiz, bag out */
	if (get_int_elt(player, FLAGS, &flags) == -1)
	{
	  warning("resolve_object", "bad flags ref on player");
	  return (-1);
	}
	if (!(flags & WIZARD))
	{
	  return (-1);
	}
      }
      name++;
      return (match_player(name));
    }
    return (-1);
  }

  return (best_match(name, match1, match2, match3, -1));
}


/*
 * Resolves a string into an object reference, if it can. The last parameter
 * is a flag. Returns -1 if no matching object, -2 if ambiguous. This routine
 * also matches exits, using rules that are similar to TinyMUD, but not
 * exactly the same.  TinyMUD would give all exact matches an equal
 * chance, but this gives only the best of each category an equal chance,
 * if the match is exact.
 */
int 
resolve_object_or_exit(player, name, splat_ok)
  int             player;
  char           *name;
  int             splat_ok;
{
  int             matched, location;
  int             match1, match2, match3, match4;
  int             flags;

  if (*name == '#' && isdigit(name[1]))
  {
    name++;
    matched = atoi(name);
    if (exists_object(matched))
    {
	return (matched);
    } else
    {
	return (-1);
    }
  }
  /* Check these first.  Don't want to confuse these. */
  if (get_int_elt(player, LOC, &location) == -1)
  {
    warning("resolve_object_or_exit", "bad location");
    return (-1);
  }

  if (strcmp("here", name) == 0)
  {
     if(get_int_elt(player, LOC, &location) == -1){
       warning("resolve_object_or_exit", "couldn't get player's location");
       return(-1); /* no match, hehe */
     }
    return (location);
  }
  if (strcmp("me", name) == 0)
  {
    return (player);
  }

  /* if match_here tells us "tie" then we return the info immediately. */

/*
  if((match1 = match_here(player, player, name, MAT_THINGS)) == -2)
    return (-2);
  if((match2 = match_here(player, location, name, MAT_THINGS)) == -2)
    return (-2);
  if((match3 = match_here(player, location, name, MAT_PLAYERS)) == -2)
    return (-2);
  if((match4 = resolve_exit(player, name)) == -2)
    return (-2);
*/
  match1 = match_here(player, player, name, MAT_THINGS);
  match2 = match_here(player, location, name, MAT_THINGS);
  match3 = match_here(player, location, name, MAT_PLAYERS);
  match4 = resolve_exit(player, name);

  if ((match1 == -1) && (match2 == -1) && (match3 == -1) && (match4 == -1))
  {

    /*
     * OK. Last ditch. If this player's a wiz or we're splat_ok, try
     * *<playername>. 
     */

    if (*name == '*')
    {
      if (!splat_ok)
      {				/* If not a Wiz, bag out */
	if (get_int_elt(player, FLAGS, &flags) == -1)
	{
	  warning("resolve_object_or_exit", "bad flags ref on player");
	  return (-1);
	}
	if (!(flags & WIZARD))
	{
	  return (-1);
	}
      }
      name++;
      return (match_player(name));
    }
    return (-1);
  }

  return (best_match(name, match1, match2, match3, match4));
} /* resolve_object_or_exit */

/*
 * This routine tries to match a player name every way possible. It should be
 * used more often. 
 */
int 
resolve_player(player, name, splat_ok)
  int             player;
  char           *name;
  int             splat_ok;
{
  int             matched, loc;

  if (get_int_elt(player, LOC, &loc) == -1)
  {
    warning("resolve_player", "bad loc ref on player");
    return -1;
  }
  matched = match_here(player, loc, name, MAT_PLAYERS);
  if (exists_object(matched) && isplayer(matched))
    return (matched);

  if (!strcmp(name, "me"))
    return (player);

  if (!splat_ok)
    return (-1);

  if (name[0] == '*')
    name++;
  if (name[0] == '#')
  {
    matched = atoi(name + 1);
    if (exists_object(matched) && isplayer(matched))
      return (matched);
    else
      return (-1);
  }
  return (match_player(name));
}

/*
 * This routine tries to match its argument to an exit, exact matches only.
 * #<objnum> is not allowed. Returns -1 on no match, -2 if ambiguous, or the
 * object number. 
 */
int 
resolve_exit(player, name)
  int             player;
  char           *name;
{
  int             matched, location;
  int             match1, match2;

  if (get_int_elt(player, LOC, &location) == -1)
  {
    warning("resolve_exit", "bad location ref on player");
    return (-1);
  }
  match1 = match_here(player, location, name, MAT_EXITS);
  match2 = match_here(player, player, name, MAT_EXITS);

  if (((match1 > -1) && (match2 > -1)) || match1 == -2 || match2 == -2)
    return (-2);
  if (match1 != -1)
  {
    matched = match1;
  } else
  if (match2 != -1)
  {
    matched = match2;
  } else
  {
    /* go ahead and *carefully* parse an object number */
    matched = -1;

    if (*name && (*name == '#') && *(name + 1) && isdigit(name[1]))
    {
      matched = atoi(name + 1);
      if (!exists_object(matched) || !isexit(matched))
	matched = -1;
    }
  }

  return (matched);
}

/*
 * This simply calls resolve_object() and then resolve_exit(). Use this if
 * you really, really don't give a damn about match order. 
 */
int 
resolve_anything(player, name, splat_ok)
  int             player;
  char           *name;
  int             splat_ok;
{
  int             matched, match1, match2;

  match1 = resolve_object(player, name, splat_ok);
  match2 = resolve_exit(player, name);

  if ((match1 == -2) || (match2 == -2))
  {
    matched = -2;
  } else
  if ((match1 != -1) && (match2 != -1))
  {
    matched = -2;
  } else
  if (match1 != -1)
  {
    matched = match1;
  } else
  if (match2 != -1)
  {
    matched = match2;
  } else
    matched = -1;

  return (matched);
}

/*
 * Drops an element from a list. You'd better be sure the element is actually
 * on the list. If code == 0, exits list, if code == 1, things list. 
 */
void 
list_drop(elt, place, code)
  int             elt;
  int             place;
  int             code;
{
  int             current, last, next;
  int             listcode;

  if (code == 1)
  {
    listcode = CONTENTS;
  } else
  {
    listcode = EXITS;
  }

  if (get_int_elt(place, listcode, &current) == -1)
  {
    warning("list_drop", "bad list reference.");
    return;
  }
  last = -1;
  while (current != elt && current != -1)
  {
    last = current;
    if (get_int_elt(current, NEXT, &current) == -1)
    {
      warning("list_drop", "bad ref inside list");
      return;
    }
  }

  /* Post Mortem. */

  /* grab the next thing on the list anyway. */

  if (get_int_elt(current, NEXT, &next) == -1)
  {
    warning("list_drop", "bad ref inside list");
    return;
  }
  if (last == -1)
  {				/* Was 1st thing on list */
    if (set_int_elt(place, listcode, next) == -1)
    {
      warning("list_drop", "bad list reference.");
      return;
    }
  } else
  {
    if (set_int_elt(last, NEXT, next) == -1)
    {
      warning("list_drop", "bad list reference.");
      return;
    }
  }
}

/*
 * Adds a thing to the top of the contents or exits list of the specified
 * place. 
 */

void 
list_add(thing, place, code)
  int             thing;
  int             place;
  int             code;
{
  int             list;
  int             listcode;

  if (code == 1)
  {
    listcode = CONTENTS;
  } else
  {
    listcode = EXITS;
  }

  if (get_int_elt(place, listcode, &list) == -1)
  {
    warning("list_add", "can't get contents");
    return;
  }
  if (set_int_elt(thing, NEXT, list) == -1)
  {
    warning("list_add", "bad can't set NEXT");
    return;
  }
  if (set_int_elt(place, listcode, thing) == -1)
  {
    warning("list_add", "can't set contents");
    return;
  }
}

/*
 * Crams the name of a thing into a buffer. If the player controls the thing,
 * or if the thing is link_ok, we show the number. 
 */

int 
stuff_name(player, thing, buff, siz)
  int             player;
  int             thing;
  char           *buff;
  int             siz;
{
  char           *name, *oldbuff;
  int             flags;

  if (!exists_object(thing))
  {
    name = "<nothing>";
    for (; *name && siz > 0; siz--)
    {
      *buff++ = *name++;
    }
    return (9);
  }
  oldbuff = buff;
  if (get_str_elt(thing, NAME, &name) == -1
      || get_int_elt(thing, FLAGS, &flags) == -1)
  {
    warning("stuff_name", "bad object name or flags ref");
    return (0);			/* Pretend it was a blank name. */
  }
  if (name == NULL)
    return (0);
  if ((TYPE_MASK & flags) == TYP_PLAYER)
  {
    while (!isspace(*name) && *name && siz)
    {
      *buff++ = *name++;
      siz--;
    }
    if (!isspace(*name) && *name)
    {
      return (-1);		/* Failed to fit */
    }
  } else
  {
    while (*name && siz)
    {
      *buff++ = *name++;
      siz--;
    }
    if (*name)
    {
      return (-1);		/* Failed to fit */
    }
  }

  /* Name fit OK. Do a number? */

  if (controls(player, thing) || islinkok(thing)
      || isjumpok(thing) || isabode(thing))
  {
    if (siz < 24)
    {
      return (-1);		/* Frob it. */
    }
    *buff++ = '(';
    *buff++ = '#';
    buff = ty_itoa(buff, thing);

    /* Flags */

    switch (flags & TYPE_MASK)
    {
    case TYP_PLAYER:
      *buff++ = 'P';
      break;
    case TYP_ROOM:
      *buff++ = 'R';
      break;
    case TYP_EXIT:
      *buff++ = 'E';
    }
    if (flags & WIZARD)
      *buff++ = 'W';
    if (flags & TEMPLE)
      *buff++ = 'T';
    if (flags & STICKY)
      *buff++ = 'S';
    if (flags & LINK_OK)
      *buff++ = 'L';
    if (flags & JUMP_OK)
      *buff++ = 'J';
    if (flags & ABODE)
      *buff++ = 'A';
    if (flags & HAVEN)
      *buff++ = 'H';
    if (flags & DARK)
      *buff++ = 'D';
    if (flags & BUILDER)
      *buff++ = 'B';
    *buff++ = ')';
  }
  return (buff - oldbuff);
}

/*
 * Given a non-empty matchlist of exits, this will try to get the player
 * through one of them. It takes an unlocked exit in preference to a locked
 * one. 
 */
void 
do_go_attempt(player, here, exlist)
  int             player;
  int             here;
  struct match   *exlist;
{
  struct match   *current, *locklist, *next;
  int             locked;
  int             total_locked, total_unlocked, total;
  int             theex, dest;
  char           *p, *q, *name;
  int             count;

  /* loop over the list once, to count it. This is clumsy. Cope. */

  current = exlist;
  for (count = 1; current->fwd != exlist && count < 1000; count++)
  {
    current = current->fwd;
  }

  current = exlist;
  locklist = NULL;
  total_locked = total_unlocked = 0;

  /* Loop over the list, putting locked exits on the locklist */

  do
  {

    next = current->fwd;	/* Guard this with your LIFE. */
    if (get_int_elt(current->obj, DESTINATION, &dest) == -1)
    {
      warning("do_go_attempt", "bed dest ref on exit");
      return;
    }
    /* Exits that are unlinked, or have dests that don't exist */
    /* are considered locked. home (-3) is OK.  */

    if (islocked(player, current->obj) || (dest != -3 && !exists_object(dest)))
    {
      total_locked++;
      /* Remove this match from exlist */

      if (current->fwd == current)
      {
	exlist = NULL;
      } else
      {
	if (exlist == current)
	{
	  exlist = next;
	}
	(current->back)->fwd = current->fwd;
	(current->fwd)->back = current->back;
      }
      /* Stuff it in to locklist */
      if (locklist == NULL)
      {
	locklist = current->back = current->fwd = current;
      } else
      {
	current->back = locklist->back;
	current->fwd = locklist;
	(locklist->back)->fwd = current;
	locklist->back = current;
      }
    } else
    {
      total_unlocked++;
    }
    current = next;
    count--;
  } while (count > 0);

  /* If there are no unlocked exits, then go with a locked one. */

  if (exlist == NULL)
  {
    exlist = locklist;
    total = total_locked;
    locked = 1;
  } else
  {
    free_match_list(locklist);
    total = total_unlocked;
    locked = 0;
  }
  /* Now choose an exit from exlist */
  current = exlist;
  while (total)
  {
#ifndef OLD_RAND
    if (random() & 0x0010L)	/* Break with 50% probability */
#else
    if (rand() & 0x0010L)	/* Break with 50% probability */
#endif 					/* OLD_RAND */
      break;
    current = current->fwd;
    total--;
  }

  /* Actually, current points one too far ahead. */

  theex = (current->back)->obj;
  free_match_list(exlist);

  /* Now do the exit */

  if (locked)
  {
    fail_object(player, theex, "You can't go that way.");
    return;
  }
  /* Grab the destination */

  if (get_int_elt(theex, DESTINATION, &dest) == -1)
  {
    warning("do_go_attempt", "bad dest ref");
    return;
  }
  /* dest will be an existing object, or -3, otherwise 'locked' */

  if (dest == -3)
  {				/* home */
    if (get_int_elt(player, HOME, &dest) == -1)
    {
      warning("do_go_attempt", "bad home ref on player");
      return;
    }
    if (!exists_object(dest))
    {
      notify_player(player, "Your home does not exist!\r\n");
      dest = STARTING_LOC;
    }
  }
  if (!isdark(player) && !isdark(here))
    succeed_object(player, theex, (char *) NULL);
  else
  {
    char           *succ;

    if (get_str_elt(theex, SUC, &succ) == -1)
    {
      warning("do_go_attempt", "bad exit success reference");
      return;
    }
    if (succ != NULL)
    {
      notify_player(player, succ);
      notify_player(player, "\r\n");
    }
  }

  /* Tell people here that the player has left */

#ifdef TIMESTAMPS
  stamp(theex);
#endif				/* TIMESTAMPS */

  if (get_str_elt(player, NAME, &name) == -1)
  {
    warning("do_go_attempt", "bad player name reference");
    return;
  }
  p = work;
  q = name;
  for (count = 0; !isspace(*q) && *q && count < BUFFSIZ - 32; count++)
  {
    *p++ = *q++;
  }
  if (!isdark(player) && !isdark(here))
  {
    strcpy(p, " has left.\r\n");
    notify_oall(player, work);
  }
#ifdef DROP_FIELDS
  {
    char           *drop;

    if (get_str_elt(theex, DROP, &drop) == -1)
    {
      warning("do_go_attempt", "bad drop ref on exit");
      notify_bad(player);
      return;
    }
    if (drop != NULL)
    {
      notify_player(player, drop);
      notify_player(player, "\r\n");
    }
  }
#endif				/* DROP_FIELDS */

  /* Get the player out of here. */

  list_drop(player, here, 1);	/* From the things list */

  /* stuff player in at destination. */

  list_add(player, dest, 1);	/* Into contents list */
  if (set_int_elt(player, LOC, dest) == -1)
  {
    warning("do_go_attempt", "could not set player location");
    return;
  }
#ifdef DROP_FIELDS
  if (!isdark(player) && !isdark(here))
  {
    char           *odrop;

    if (get_str_elt(theex, ODROP, &odrop) == -1)
    {
      warning("do_go_attempt", "bad odrop ref on exit");
      notify_bad(player);
    } else
    if (odrop != NULL)
    {
      char           *sub, *r;

      sub = pronoun_sub(player, odrop);
      r = p;
      *r++ = ' ';
      for (; sub && *sub && (r - work) < BUFFSIZ - 3; *r++ = *sub++);
      *r++ = '\r';
      *r++ = '\n';
      *r = '\0';
      notify_oall(player, work);
    }
  }
#endif				/* DROP_FIELDS */

  /* Tell folks the player has arrived. p is still correct, really. */

  if (!isdark(player) && !isdark(dest))
  {
    strcpy(p, " has arrived.\r\n");
    notify_oall(player, work);
  }
  do_look(player, (char *) NULL);

  flush_room(here);
}

void 
flush_room(room)
  int             room;
{
  int             flags, dest, list;

  /* Check for sticky droptos */

  if (get_int_elt(room, FLAGS, &flags) == -1)
  {
    warning("flush_room", "bad flags ref on room");
    return;
  }
  if (flags & STICKY)
  {

    /* Check for a dropto to get activated. */

    if (get_int_elt(room, DROPTO, &dest) == -1)
    {
      warning("flush_room", "bad dropto reference");
      return;
    }
    /* If no dropto, or it's to somewhere that doesn't exist.. */

    if (dest == -1 || (dest != -3 && !exists_object(dest)))
    {
      return;
    }
    /* OK. See if there are any players here. */

    if (get_int_elt(room, CONTENTS, &list) == -1)
    {
      warning("flush_room", "bad contents list ref");
      return;
    }
    while (list != -1)
    {
      if (get_int_elt(list, FLAGS, &flags) == -1)
      {
	warning("flush_room", "bad flags ref in contents list");
	return;
      }
      if ((TYPE_MASK & flags) == TYP_PLAYER)
      {
	return;
      }
      if (get_int_elt(list, NEXT, &list) == -1)
      {
	warning("flush_room", "bad NEXT ref in contents list");
	return;
      }
    }

    /* No players left, toss everything here down the dropto */

    if (get_int_elt(room, CONTENTS, &list) == -1)
    {
      warning("flush_room", "bad contents list ref");
      return;
    }
    while (list != -1)
    {
      int             sendto, next;

      if (get_int_elt(list, NEXT, &next) == -1)
      {
	warning("flush_room", "bad NEXT ref in contents list");
	return;
      }
      if (get_int_elt(list, FLAGS, &flags) == -1)
      {
	warning("flush_room", "bad flags ref in contents list");
	return;
      }
      if ((TYPE_MASK & flags) == TYP_THING)
      {
	list_drop(list, room, 1);
	if ((dest == -3) || (flags & STICKY))
	{
	  /* send it home */
	  if (get_int_elt(list, HOME, &sendto) == -1)
	  {
	    warning("flush_room", "bad home ref in dropto");
	    sendto = STARTING_LOC;
	  }
	  if (!exists_object(sendto))
	  {
	    sendto = 0;
	  }
	} else
	{
	  sendto = dest;
	}
	list_add(list, sendto, 1);
	if (set_int_elt(list, LOC, sendto) == -1)
	{
	  warning("flush_room", "could not set LOC on dropto");
	  return;
	}
      }
      list = next;
    }
  }
}

void 
fail_object(player, thing, def)
  int             player;
  int             thing;
  char           *def;		/* Default fail string. */
{
  char           *str, *ostr, *name, *p, *sub;
  char            buffer[BUFFSIZ];

  /* Just grab the fail/ofail and do 'em */

  if (get_str_elt(thing, FAIL, &str) == -1)
  {
    warning("fail_object", "bad fail reference");
    return;
  }
  if (str == NULL)
    str = def;
  if (str != NULL)
  {
    notify_player(player, str);
    notify_player(player, "\r\n");
  }
  if (get_str_elt(thing, OFAIL, &ostr) == -1)
  {
    warning("fail_object", "bad ofail reference");
    return;
  }
  if (ostr != NULL)
  {
    sub = pronoun_sub(player, ostr);
    if (get_str_elt(player, NAME, &name) == -1)
    {
      warning("fail_object", "bad player name ref");
      return;
    }
    for (p = buffer; name && *name && *name != ' '; *p++ = *name++);
    *p++ = ' ';
    for (; sub && *sub && (p - buffer) < BUFFSIZ - 3; *p++ = *sub++);
    *p++ = '\r';
    *p++ = '\n';
    *p = '\0';
    notify_oall(player, buffer);
  }
}
void 
succeed_object(player, thing, def)
  int             player;
  int             thing;
  char           *def;		/* Default success string. */
{
  char           *str, *ostr, *name, *p, *sub;
  char            buffer[BUFFSIZ];

  /* Grab the succ and osucc and do 'em */

  if (get_str_elt(thing, SUC, &str) == -1)
  {
    warning("succeed_object", "bad success reference");
    return;
  }
  if (str == NULL)
    str = def;
  if (str != NULL)
  {
    notify_player(player, str);
    notify_player(player, "\r\n");
  }
  if (get_str_elt(thing, OSUC, &ostr) == -1)
  {
    warning("succeed_object", "bad osuccess reference");
    return;
  }
  if (ostr != NULL)
  {
    sub = pronoun_sub(player, ostr);
    if (get_str_elt(player, NAME, &name) == -1)
    {
      warning("succeed_object", "bad player name ref");
      return;
    }
    for (p = buffer; name && *name && *name != ' '; *p++ = *name++);
    *p++ = ' ';
    for (; sub && *sub && (p - buffer) < BUFFSIZ - 3; *p++ = *sub++);
    *p++ = '\r';
    *p++ = '\n';
    *p = '\0';
    notify_oall(player, buffer);
  }
}

/*
 * Spits a file in the cwd to the player. 
 */
void 
spit_file(player, name)
  int             player;
  char           *name;
{
  FILE           *in;
  char            filebuff[130];
  int             i;

  if ((in = fopen(name, "r")) == NULL)
  {
    notify_player(player, "Sorry, ");
    notify_player(player, name);
    notify_player(player,
	  " is broken. Your wizards are no doubt toiling over it now.\r\n");
    return;
  }
  /* Grab thing outta the file and shove 'em */

  while (fgets(filebuff, 128, in) != NULL)
  {
    /* Replace the \n\0 with a \r\n\0, if present. */
    i = strlen(filebuff);
    if(filebuff[i-1] == '\n')
    {
      filebuff[i-1] = '\r';
      filebuff[i] = '\n';
      filebuff[i+1] = '\0';
    }
    notify_player(player, filebuff);
  }

  (void) fclose(in);
}

/*
 * Returns 1 if the player can see anything, 0 otherwise. 
 */
int 
can_see_anything(player, location)
  int             player;
  int             location;
{
  int             list, contents;

  if (location == -1)
  {
    /* get their location */
    if (get_int_elt(player, LOC, &location) == -1)
    {
      warning("can_see_anything", "bad player loc ref");
      notify_bad(player);
      return 0;
    }
  }
  if (get_int_elt(location, CONTENTS, &contents) == -1)
  {
    warning("can_see_anything", "bad location contents ref");
    notify_bad(player);
    return 0;
  }
  if (contents == player)
  {
    int             foo;

    if (get_int_elt(player, NEXT, &foo) == -1)
    {
      warning("can_see_anything", "bad player next ref");
      notify_bad(player);
      return 0;
    }
    if (foo == -1)
      return 0;
  }
  /* still here... hmm... loop through list. */
  list = contents;
  while (list != -1)
  {
    if (can_see(player, list))
      return 1;
    if (get_int_elt(list, NEXT, &list) == -1)
    {
      warning("can_see_anything", "bad next ref in contents list");
      notify_bad(player);
      return 0;
    }
  }
  /* they cannot see a damn thing! */
  return 0;
}

/*
 * Returns a 1 if player can see that specific object, 0 otherwise. 
 */
int 
can_see(player, obj)
  int             player;
  int             obj;
{
  int             loc, owner;

  if (player == obj)
    return 0;
#ifdef DARK_SLEEP
  if (isplayer(obj) && !isalive(obj))
    return 0;
#endif				/* DARK_SLEEP */
  if (isroom(obj))
    return 0;			/* wee... */
  if (get_int_elt(obj, LOC, &loc) == -1)
  {
    warning("can_see", "couldn't get object's location");
    return (0);
  }
  if (get_int_elt(obj, OWNER, &owner) == -1)
  {
    warning("can_see", "couldn't get object's owner");
    return (0);
  }
  /* this is so a wizz won't see so much junk a dark room. */
  if (isdark(loc) && (owner != player))
    return 0;
  if (!isdark(obj))
    return 1;
  if (isdark(obj) && controls(player, obj))
    return 1;

  return 0;
}