muse1.7b4/
muse1.7b4/config/
muse1.7b4/doc/
muse1.7b4/run/
muse1.7b4/run/db/
muse1.7b4/src/
muse1.7b4/src/db/
muse1.7b4/src/files/
muse1.7b4/src/io/
muse1.7b4/src/prog/
muse1.7b4/src/util/
/* topology.c - check to make sure rooms and exits are the way they
   should be. */
/* $Id: warnings.c,v 1.2 1993/08/22 18:09:34 nils Exp $ */

#include <stdio.h>

#include "db.h"
#include "config.h"
#include "externs.h"

static dbref current_object = NOTHING;

static int lock_type(i,str)	/* 0== unlocked. 1== locked, 2== sometimes */
     dbref i;
     char *str;
{
  if (!*str)
    return 0;
  if (!strcmp(str,tprintf("#%d&!#%d",db[i].owner,db[i].owner)))
    return 1;
  if (!strcmp(str,tprintf("#%d",db[i].owner)))
    return 1;
  if (!strcmp(str,tprintf("#%d",db[i].location)))
    return 1;
  return 2;			/* too complicated. need both messages. */
}

static void complain P((dbref, char *, char *));
static void complain (i, name, desc)
     dbref i;
     char *name, *desc;
{
  char buf[1024];
  char *x=buf, *y;

  strcpy(buf,atr_get(i,A_WINHIBIT));
  while ((y=parse_up(&x,' ')))
    if (!string_compare(y,name) || !string_compare(y,"all"))
      return;			/* user doesn't want to hear about
				 * it for this object. */
  sprintf(buf, "Warning '%s' for %s: %s",name,unparse_object(db[i].owner,i),
	  desc);
  notify(db[i].owner, buf);
}
 
static void ct_roomdesc P((dbref));
static void ct_roomdesc(i)
     dbref i;
{
  if ((Typeof(i) == TYPE_ROOM) && !*atr_get(i,A_DESC))
    complain(i,"roomdesc","room has no description");
}

static void ct_onewayexit P((dbref));
static void ct_onewayexit(i)
     dbref i;
{
  dbref j;
  if ((Typeof(i) != TYPE_EXIT) || (db[i].link == NOTHING) || (Typeof(db[i].link) != TYPE_ROOM) || db[i].link == db[i].location)
    return;
  for (j=db[db[i].link].exits; j!=NOTHING; j = db[j].next)
    if (db[j].link == db[i].location)
      return;
  complain(i,"onewayexit","exit has no return exit");
}

static void ct_doubleexit P((dbref));
static void ct_doubleexit(i)
     dbref i;
{
  dbref j;
  int count=0;
  if ((Typeof(i) != TYPE_EXIT) || (db[i].link == NOTHING) || (Typeof(db[i].link) != TYPE_ROOM) || db[i].location == db[i].link)
    return;
  for (j=db[db[i].link].exits; j!=NOTHING; j = db[j].next)
    if (db[j].link == db[i].location)
      count++;
  if (count>1)
    complain(i,"doubleexit","exit has multiple return exits");
}

static void ct_exitmsgs P((dbref));
static void ct_exitmsgs(i)
     dbref i;
{
  int lt;
  if ((Typeof(i) != TYPE_EXIT) || (db[i].flags&DARK))
    return;
  lt = lock_type(i,atr_get(i,A_LOCK));
  if ((lt != 1) && (!*atr_get(i,A_OSUCC) ||
		    !*atr_get(i,A_ODROP) ||
		    !*atr_get(i,A_SUCC)))
    complain(i,"exitmsgs","exit is missing one or more of osucc, odrop, succ");
  if ((lt != 0) && (!*atr_get(i,A_OFAIL) ||
		    !*atr_get(i,A_FAIL)))
    complain(i,"exitmsgs","exit is missing one or more of fail, ofail");
}

static void ct_exitdesc P((dbref));
static void ct_exitdesc(i)
     dbref i;
{
  if ((Typeof(i) != TYPE_EXIT) || (db[i].flags&DARK))
    return;
  if (!*atr_get(i,A_DESC))
    complain(i,"exitdesc","exit is missing description");
}

static void ct_playdesc P((dbref));
static void ct_playdesc(i)
     dbref i;
{
  if (Typeof(i) != TYPE_PLAYER)
    return;
  if (!*atr_get(i,A_DESC))
    complain(i,"playdesc","player is missing description");
}

static void ct_thngdesc P((dbref));
static void ct_thngdesc(i)
     dbref i;
{
  if ((Typeof(i) != TYPE_THING) || (db[i].location == db[i].owner))
    return;
  if (!*atr_get(i,A_DESC))
    complain(i,"thngdesc","thing is missing description");
}

static void ct_thngmsgs P((dbref));
static void ct_thngmsgs(i)
     dbref i;
{
  int lt;
  if ((Typeof(i) != TYPE_THING) || (db[i].location == db[i].owner))
    return;
  lt = lock_type(i,atr_get(i,A_LOCK));
  if ((lt != 1) && (!*atr_get(i,A_OSUCC) ||
		    !*atr_get(i,A_ODROP) ||
		    !*atr_get(i,A_SUCC) ||
		    !*atr_get(i,A_DROP)))
    complain(i,"thngmsgs","thing is missing one or more of osucc,odrop,succ,drop");
  if ((lt != 0) && (!*atr_get(i,A_OFAIL) ||
		    !*atr_get(i,A_FAIL)))
    complain(i,"thngmsgs","thing is missing one or more of ofail,fail");
}

static void ct_exitnames P((dbref));
static void ct_exitnames(i)
     dbref i;
{
  /* soon to be written */
}

static void ct_nolinked P((dbref));
static void ct_nolinked(i)
     dbref i;
{
  if ((Typeof(i) == TYPE_EXIT) && (db[i].link == NOTHING))
    complain(i,"nolinked","exit is unlinked; anyone can steal it");
}

/* now the groups */

/*static void ct_none P((dbref));
static void ct_none(i)
     dbref i;
{
  * do absoultely nothing *
}*/

static void ct_serious P((dbref));
static void ct_serious(i)
     dbref i;
{
  /* only display serious warnings */
  ct_roomdesc(i);
  ct_nolinked(i);
}

static void ct_normal P((dbref));
static void ct_normal(i)
     dbref i;
{
  ct_playdesc(i);
  ct_roomdesc(i);
  ct_onewayexit(i);
  ct_doubleexit(i);
  ct_exitnames(i);
  ct_nolinked(i);
}

static void ct_extra P((dbref));
static void ct_extra(i)
     dbref i;
{
  ct_roomdesc(i);
  ct_onewayexit(i);
  ct_doubleexit(i);
  ct_playdesc(i);
  ct_exitmsgs(i);
  ct_thngdesc(i);
  ct_thngmsgs(i);
  ct_exitnames(i);
  ct_nolinked(i);
}

static void ct_all P((dbref));
static void ct_all(i)
     dbref i;
{
  ct_extra(i);
  ct_exitdesc(i);
}

struct tcheck_s {
  char *name;
  void (*func) P((dbref));
} tchecks[] = {
  /* group checks */
/*  {"none", ct_none},*/
  {"serious", ct_serious},
  {"normal", ct_normal},
  {"extra", ct_extra},
  {"all", ct_all},

  /* now the individual checks */
  {"roomdesc", ct_roomdesc},
  {"onewayexit", ct_onewayexit},
  {"doubleexit", ct_doubleexit},
  {"exitmsgs", ct_exitmsgs},
  {"exitdesc", ct_exitdesc},
  {"thngdesc", ct_thngdesc},
  {"playdesc", ct_thngdesc},
  {"thngmsgs", ct_thngmsgs},
  {"exitnames", ct_exitnames},
  {"nolinked", ct_nolinked},
  {NULL, NULL}
};

void check_topology_on(i)
     dbref i;
{
  char buf[1024];
  char *x=buf, *y;
  
  strcpy(buf,(*atr_get(db[i].owner,A_WARNINGS))?atr_get(db[i].owner,A_WARNINGS):"normal");
  while ((y=parse_up(&x, ' '))) {
    int j;
    for (j=0; tchecks[j].name; j++)
      if (!string_compare(tchecks[j].name, y)) {
	(*tchecks[j].func)(i);
        break;
      }
    if (!tchecks[j].name && Typeof(i)==TYPE_PLAYER)
      notify(i,tprintf("Unknown warning: %s",y));
  }
}

void run_topology()
{
  int ndone;
  for (ndone=0; ndone<WARNING_CHUNK; ndone++) {
    current_object++;
    if (current_object >= db_top)
      current_object = (dbref) 0;
    if (!(db[current_object].flags & GOING) && db[db[current_object].owner].flags&PLAYER_CONNECT) {
      check_topology_on(current_object);
      ndone += WARNING_BONUS;
    }
  }
}