/
teeny/db/
teeny/dbm/
teeny/docs/
teeny/includes/
teeny/misc/
teeny/news/
teeny/text/
/* dbutils.c */

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

#include <stdio.h>
#include <ctype.h>

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

/*
 * This is the only file in the mud directory that knows about the index. Use
 * EXTREME caution when modifing the routines in this file. 
 */

extern struct dsc **main_index;
extern int      total_objects;
extern int      actual_objects;

static void     find_object();

int 
controls(player, obj)
  int             player;
  int             obj;
{
  if (obj == -3)
    return 1;			/* everyone controls HOME */

  if (player < 0 || player > total_objects || main_index[player] == NULL)
  {
    warning("controls", "called with nonexistant player");
    return 0;
  }
  if (obj < 0 || obj > total_objects || main_index[obj] == NULL)
  {
    warning("controls", "called with nonexistant object");
    return 0;
  }
  if (WizP(main_index[player]))
    return 1;

  if (DSC_OWNER(main_index[obj]) == player)
    return 1;

  return 0;
}

static void 
find_object(player, name, type)
  int             player;
  char           *name;
  int             type;
{
  register int    i, j, len;
  register char  *str;
  extern char     cmdwork[];

  for (i = 0; i < total_objects; i++)
  {
    if (main_index[i] == NULL)
      continue;

    if (((type != -1) && ((DSC_FLAGS(main_index[i]) & TYPE_MASK) != type))
	|| (type == -1 && isexit(i)))

      continue;

    if (!controls(player, i))
      continue;
    str = DSC_NAME(main_index[i]);
    if (str == NULL)
    {
      fprintf(stderr, "find_object: obj (#%d) has NULL name.\n", i);
      continue;
    }
    if (PlayerP(main_index[i]))
    {
      if (name != (char *) 0)
	for (j = 0; name[j] && str[j] && DOWNCASE(name[j]) == DOWNCASE(str[j]); j++);
      if ((name == (char *) 0) || isspace(str[j]))
      {
	if ((len = stuff_name(player, i, cmdwork, BUFFSIZ - 3)) == -1)
	{
	  strcpy(cmdwork, "<spammed name>\r\n");
	} else
	{
	  cmdwork[len] = '\r';
	  cmdwork[len + 1] = '\n';
	  cmdwork[len + 2] = '\0';
	}
	notify_player(player, cmdwork);
      }
    } else
    {
      if ((name == (char *) 0) || strstr_CI(str, name))
      {
	if ((len = stuff_name(player, i, cmdwork, BUFFSIZ - 3)) == -1)
	{
	  strcpy(cmdwork, "<spammed name>\r\n");
	} else
	{
	  cmdwork[len] = '\r';
	  cmdwork[len + 1] = '\n';
	  cmdwork[len + 2] = '\0';
	}
	notify_player(player, cmdwork);
      }
    }

  }
  notify_player(player, "***End of list***\r\n");
}
voidfunc 
do_owned(player, argone, argtwo)
  int             player;
  char           *argone;
  char           *argtwo;
{
  int             len, matchfor, i, type;
  extern char     cmdwork[];

  if (!iswiz(player))
  {
    notify_player(player, "Only a Wizard may look at the owners list.\r\n");
    return;
  }
  if (!argone || !*argone)
  {
    notify_player(player, "I need a player name.\r\n");
    return;
  }
  if ((matchfor = resolve_player(player, argone, 1)) == -1)
  {
    notify_player(player, "I can't find that person.\r\n");
    return;
  }
  type = -1;
  if (argtwo && *argtwo)
  {
    parse_type(argtwo, &type);
    if(type == -1)
    {
      notify_player(player, "@owned <player> [=<type>] where type is {e,p,r,t}\r\n");
      return;
    }
  }

  for (i = 0; i < total_objects; i++)
  {
    if (main_index[i] == NULL)
      continue;
    if (DSC_OWNER(main_index[i]) != matchfor)
      continue;
    /* they own this object */
    if (type != -1)
    {
      if ((DSC_FLAGS(main_index[i]) & TYPE_MASK) != type)
	continue;
    }
    if ((len = stuff_name(player, i, cmdwork, BUFFSIZ - 3)) == -1)
    {
      strcpy(cmdwork, "<spammed name>\r\n");
    } else
    {
      cmdwork[len] = '\r';
      cmdwork[len + 1] = '\n';
      cmdwork[len + 2] = '\0';
    }
    notify_player(player, cmdwork);
  }
  notify_player(player, "***End of list***\r\n");
}
int 
chownall(oldowner, newowner)
  register int    oldowner;
  register int    newowner;
{
  int             i, count = 0;

  if (!exists_object(oldowner) || !exists_object(newowner))
  {
    warning("chownall", "called with nonexistant object as an argument");
    return 0;
  }
  for (i = 0; i < total_objects; i++)
  {
    if (main_index[i] == NULL)
      continue;
    if (DSC_OWNER(main_index[i]) == oldowner)
    {
      DSC_OWNER(main_index[i]) = newowner;
      count++;
    }
  }
  return count;
}
voidfunc 
do_find(player, argone, argtwo)
  int             player;
  char           *argone;
  char           *argtwo;
{
  int             type;

  if (!argone || !*argone)
    argone = (char *) 0;

  type = -1;
  if (argtwo && *argtwo)
  {
    parse_type(argtwo, &type);
    if(type == -1)
    {
      notify_player(player, "@find <string> [=<type>] where type is {e,p,r,t}\r\n");
      return;
    }
  }

  find_object(player, argone, type);
}

#define COUNT_OBJ(x)    \
(((matchfor != -2)&&(DSC_OWNER(main_index[x])==matchfor)) || matchfor == -2)
#define STATS_FRMT      \
"%d object%s = %d room%s, %d exit%s, %d thing%s, %d player%s (%d garbage).\r\n"
voidfunc 
do_stats(player, arg)
  int             player;
  char           *arg;
{
  extern char     cmdwork[];
  int             matchfor;

  if (!arg || !*arg)
  {
    matchfor = -2;
  } else
  {
    if ((matchfor = resolve_player(player, arg, iswiz(player))) == -1)
    {
      notify_player(player, "I can't find that person.\r\n");
      return;
    }
    if ((matchfor != player) && !iswiz(player))
    {
      notify_player(player, "You can't stat other players!\r\n");
      return;
    }
    /* matchfor should now contain a valid player number */
  }

  if (!iswiz(player) && matchfor == -2)
  {
    sprintf(cmdwork, "The universe contains %d objects.\r\n", actual_objects);
    notify_player(player, cmdwork);
  } else
  {
    register int    i;
    register int    exits = 0;
    register int    rooms = 0;
    register int    players = 0;
    register int    things = 0;
    register int    total = 0;

    for (i = 0; i < total_objects; i++)
    {
      if (main_index[i] == NULL)
	continue;
      if (ExitP(main_index[i]))
      {
	if (COUNT_OBJ(i))
	{
	  total++;
	  exits++;
	}
	continue;
      }
      if (RoomP(main_index[i]))
      {
	if (COUNT_OBJ(i))
	{
	  rooms++;
	  total++;
	}
	continue;
      }
      if (PlayerP(main_index[i]))
      {
	if (COUNT_OBJ(i))
	{
	  total++;
	  players++;
	}
	continue;
      }
      if (ThingP(main_index[i]))
      {
	if (COUNT_OBJ(i))
	{
	  total++;
	  things++;
	}
	continue;
      }
    }

    sprintf(cmdwork, STATS_FRMT,
      total, (total == 1) ? "" : "s", rooms, (rooms == 1) ? "" : "s", exits,
	 (exits == 1) ? "" : "s", things, (things == 1) ? "" : "s", players,
	    (players == 1) ? "" : "s",
	    (matchfor == -2) ? total_objects - actual_objects : 0);
    notify_player(player, cmdwork);

    if (iswiz(player) && matchfor == -2)
    {
      extern int      cache_usage;
      extern int      cache_size;

      sprintf(cmdwork, "Cache usage: %d of %d.\r\n", cache_usage, cache_size);
      notify_player(player, cmdwork);
    }
  }
}

#undef COUNT_OBJ
#undef STATS_FRMT

/* fix up destinations/homes/dropto's that point at non existant objects */
void 
zap_destinations(oldobj)
  int             oldobj;
{
  register int    i;

  for (i = 0; i < total_objects; i++)
  {
    if ((main_index[i] == NULL) || (DSC_HOME(main_index[i]) != oldobj))
      continue;
    switch (DSC_FLAGS(main_index[i]) & TYPE_MASK)
    {
    case TYP_PLAYER:
      DSC_HOME(main_index[i]) = STARTING_LOC;
      break;
    case TYP_THING:
      DSC_HOME(main_index[i]) =	/* link to owners home */
	  DSC_HOME(main_index[DSC_OWNER(main_index[i])]);
      break;
    case TYP_ROOM:
      DSC_DROPTO(main_index[i]) = -1;	/* unlink */
      break;
    case TYP_EXIT:
      DSC_DESTINATION(main_index[i]) = -1;	/* unlink */
      break;
    default:			/* fuckit */
      fprintf(stderr, "warning: object #%d is unknown type.\n", i);
    }
  }
}

int 
recycleobj(obj)
  int             obj;
{
  int             loc;
  int             list, next;
  int             total = 0;

  if (!exists_object(obj))
    return 0;

  if (PlayerP(main_index[obj]))
    return 0;

  if (get_int_elt(obj, LOC, &loc) == -1)
    goto recbomb;
  if (RoomP(main_index[obj]))
  {
    /* Nuke the exits. Ownership? Who cares. */

    if (get_int_elt(obj, EXITS, &list) == -1)
      goto recbomb;
    while (list != -1)
    {
      next = DSC_NEXT(main_index[list]);
      destroy_obj(list);
      total++;
      list = next;
    }

    /* Try to send everything here home. Nuke what's left */
    /* I.E. Anything homed here will get nuked. BOOM!     */

    if (get_int_elt(obj, CONTENTS, &list) == -1)
      goto recbomb;
    while (list != -1)
    {
      next = DSC_NEXT(main_index[list]);

      /* If this is a player homed here, set home to zero */

      if (PlayerP(main_index[list]))
      {
	if (DSC_HOME(main_index[list]) == obj)
	{
	  DSC_HOME(main_index[list]) = STARTING_LOC;
	}
      }
      if (PlayerP(main_index[list]))
      {
	char           *name, *p;
	char            ch;

	name = DSC_NAME(main_index[list]);
	for (p = name; *p && *p != ' '; p++);
	ch = *p;
	*p = '\0';

	notify_player(list, "You feel a wrenching sensation...\r\n");
	send_home(list, obj);
	notify_oall(list, name);
	notify_oall(list, " has arrived.\r\n");

	*p = ch;

	do_look(list, (char *) NULL);
      } else
      {
	send_home(list, obj);
      }
      list = next;
    }
    if (get_int_elt(obj, CONTENTS, &list) == -1)
      goto recbomb;
    while (list != -1)
    {
      next = DSC_NEXT(main_index[list]);
      destroy_obj(list);
      total++;
      list = next;
    }

    /* nuke the room itself. */

    destroy_obj(obj);
    total++;

    /* Skip over the DB checking all exits, and unlinking the */
    /* ones that come here.                                   */

    zap_destinations(obj);
  } else
  if (ExitP(main_index[obj]))
  {
    list_drop(obj, loc, 0);
    destroy_obj(obj);
    total++;
  } else
  if (ThingP(main_index[obj]))
  {
    list_drop(obj, loc, 1);
    zap_destinations(obj);
    if (get_int_elt(obj, CONTENTS, &list) == -1)
      goto recbomb;
    while (list != -1)
    {
      /* send objects home */
      next = DSC_NEXT(main_index[list]);
      send_home(list, obj);
      list = next;
    }
    if (get_int_elt(obj, EXITS, &list) == -1)
      goto recbomb;
    while (list != -1)
    {
      /* nuke exits */
      next = DSC_NEXT(main_index[list]);
      destroy_obj(list);
      total++;
      list = next;
    }
    destroy_obj(obj);
    total++;
  } else
  {
    warning("recycleobj", "unknown object type");
    goto recbomb;
  }
  return total;

recbomb:

  return -1;
}

/* recycle everything owned by obj, *except* obj */
int 
purgepossessions(obj)
  int             obj;
{
  register int    i;
  int             ret, total = 0;

  if (!exists_object(obj))
  {
    warning("purgepossessions", "called with nonexistant object");
    return 0;
  }
  for (i = 0; i < total_objects; i++)
  {
    if (main_index[i] == NULL)
      continue;
    if ((i == obj) || (DSC_OWNER(main_index[i]) != obj))
      continue;
    /* nuke this, what ever it is */
    ret = recycleobj(i);
    if (ret > 0)
      total += ret;
  }
  return total;
}

/*
 * Matches a player. This is kind of expensive CPU wise. 
 */
int 
match_player(name)
  register char  *name;
{
  register int    i, j;
  register char  *player;

  for (i = 0; i < total_objects; i++)
  {
    if (main_index[i] == NULL || !PlayerP(main_index[i]))
      continue;
    player = DSC_NAME(main_index[i]);
    if (!player || !*player)
    {
      warning("match_player", "player with null name found");
      continue;
    }
    for (j = 0; name[j] && player[j] && (DOWNCASE(name[j]) ==
					 DOWNCASE(player[j])); j++);
    if ((player[j] == ' ') && (name[j] == '\0'))
      return (i);
  }
  return (-1);
}

int
autotoadcheck(player)
  int		player;
{
  char 	       *desc, *name, *p;
  register int  i;
  register int  total = 0;
  extern char     cmdwork[];

  /* Is player guest? */

  if (player == GUEST)
    return TRUE;

  /* Does the player have a desc? */

  if (get_str_elt(player, DESC, &desc) == -1)
  {
    warning("autotoadcheck", "bad desc elt");
    notify_bad(player);
    return TRUE;
  }
  if (desc != NULL)
    return TRUE;

  /* Does the player own any property? (@stat > 1) */

  for (i = 0; i < total_objects; i++)
  {
    if (main_index[i] == NULL)
      continue;
    if (DSC_OWNER(main_index[i]) == player)
      total++;
  } 

  if (total > 1)
    return TRUE;

  /* Player has failed both tests.  Toad the bastard. */

  if (get_str_elt(player, NAME, &name) == -1)
  {
    warning("autotoadcheck", "bad name elt");
    notify_bad(player);
    return TRUE;
  }
  if (name != NULL)
  {
    for (p = cmdwork; *name && !isspace(*name);)
    {
      *p++ = *name++;
    }
    *p = '\0';
  }
  notify_player(player,
      "Are you just here to litter the db, or what?  Man!\r\n");
  do_toad(GOD,cmdwork,NULL);
  if (recycleobj(player) < 1)
    warning("autotoadcheck", "couldn't recycle the toad");

  return FALSE;
} /* autotoadcheck */