/
2.0.4beta/doc/
2.0.4beta/gnu/
2.0.4beta/sha/
/* display.c */

#include "config.h"

/*
 *		       This file is part of TeenyMUD II.
 *		 Copyright(C) 1993, 1994, 1995 by Jason Downs.
 *                           All rights reserved.
 * 
 * TeenyMUD II is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * TeenyMUD II is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program (see the file 'COPYING'); if not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA.
 *
 */

#include <stdio.h>
#include <sys/types.h>
#ifdef HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif			/* HAVE_STRING_H */
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif			/* HAVE_STDLIB_H */

#include "conf.h"
#include "teeny.h"
#include "flaglist.h"
#include "attrs.h"
#include "externs.h"

/* routines for formatting object-related data for human viewing. */

char *display_name(player, cause, thing)
    int player, cause, thing;
{
  static char buff[MEDBUFFSIZ];
  char *name, *ptr;
  int flags[FLAGS_LEN], type;
  register FlagList *flist;
  int control, visible;

  /* do a couple of sanity checks. */
  if(thing == -2) {
    strcpy(buff, "*HOME*");
    return(buff);
  } else if(!exists_object(thing)) {
    strcpy(buff, "*NOTHING*");
    return(buff);
  }

  if((get_str_elt(thing, NAME, &name) == -1)
     || (get_flags_elt(thing, FLAGS, flags) == -1)) {
    logfile(LOG_ERROR,
	    "display_name: couldn't get name or flags of object #%d\n", thing);
    strcpy(buff, "*BAD NAME*");
    return(buff);
  }

  for(ptr = buff; name && *name
      && ((ptr - buff) < (MEDBUFFSIZ-64)); *ptr++ = *name++);
  *ptr = '\0';

  type = (flags[0] & TYPE_MASK);
  control = controls(player, cause, thing);
  visible = 0;

  if(!control) {
    for (flist = GenFlags; flist->name; flist++) {
      if ((flags[flist->word] & flist->code)
	  && (flist->perm & PERM_VISIBLE))
        visible++;
    }
    switch (type) {
    case TYP_ROOM:
      for(flist = RoomFlags; flist->name; flist++) {
        if ((flags[flist->word] & flist->code)
	    && (flist->perm & PERM_VISIBLE))
	  visible++;
      }
      break;
    case TYP_PLAYER:
      for(flist = PlayerFlags; flist->name; flist++) {
        if ((flags[flist->word] & flist->code)
	    && (flist->perm & PERM_VISIBLE))
	  visible++;
      }
      break;
    case TYP_EXIT:
      for(flist = ExitFlags; flist->name; flist++) {
        if ((flags[flist->word] & flist->code)
	    && (flist->perm & PERM_VISIBLE))
	  visible++;
      }
      break;
    case TYP_THING:
      for(flist = ThingFlags; flist->name; flist++) {
        if ((flags[flist->word] & flist->code)
	    && (flist->perm & PERM_VISIBLE))
	  visible++;
      }
      break;
    }
  }

  if(control || visible) {
    sprintf(ptr, "(#%d%s%s)", thing,
    	    (type == TYP_PLAYER) ? "P" : (type == TYP_ROOM) ? "R" :
	    (type == TYP_EXIT) ? "E" : "", display_objflags(flags, control));
  }

  return(buff);
}

static int sort_flags(chr1, chr2)
    register char *chr1, *chr2;
{
  return(*chr1 - *chr2);
}

char *display_objflags(flags, showall)
    int *flags, showall;
{
  static char buff[FLAGS_MAX+1];
  register char *ptr = buff;
  register FlagList *flist;

  for (flist = GenFlags; flist->name; flist++) {
    if (flags[flist->word] & flist->code) {
      if(showall || (flist->perm & PERM_VISIBLE))
        *ptr++ = flist->chr;
    }
  }
  switch(flags[0] & TYPE_MASK) {
  case TYP_ROOM:
    for(flist = RoomFlags; flist->name; flist++) {
      if(flags[flist->word] & flist->code) {
	if(showall || (flist->perm & PERM_VISIBLE))
	  *ptr++ = flist->chr;
      }
    }
    break;
  case TYP_PLAYER:
    for(flist = PlayerFlags; flist->name; flist++) {
      if(flags[flist->word] & flist->code) {
	if(showall || (flist->perm & PERM_VISIBLE))
	  *ptr++ = flist->chr;
      }
    }
    break;
  case TYP_EXIT:
    for(flist = ExitFlags; flist->name; flist++) {
      if(flags[flist->word] & flist->code) {
	if(showall || (flist->perm & PERM_VISIBLE))
	  *ptr++ = flist->chr;
      }
    }
    break;
  case TYP_THING:
    for(flist = ThingFlags; flist->name; flist++) {
      if(flags[flist->word] & flist->code) {
	if(showall || (flist->perm & PERM_VISIBLE))
	  *ptr++ = flist->chr;
      }
    }
    break;
  }
  *ptr = '\0';

  /* make it look pretty */
  qsort(buff, (ptr - buff), sizeof(char), sort_flags);

  return(buff);
}

char *display_attrflags(aflags)
    int aflags;
{
  static char buff[A_FLAGS_MAX+1];
  register char *ptr;
  AFlagList *Aflags;

  for (ptr = buff, Aflags = AFlags; Aflags->name; Aflags++) {
    if (aflags & Aflags->code) 
      *ptr++ = Aflags->chr;
  }
  *ptr = '\0';
  return (buff);
}

/*
 * Format, sort, and display the long list of object flags.
 *
 * XXX: Too much of this is hard coded.
 */

struct sortbuf {
  char *name;	/* Long flag name */
  char chr;	/* Short flag name. */
};

static int sort_withbuf(s1, s2)
    register struct sortbuf *s1, *s2;
{
  return(s1->chr - s2->chr);
}

void display_flags(player, cause, obj)
    int player, cause, obj;
{
  char buffer[MEDBUFFSIZ];
  struct sortbuf bufptr[FLAGS_MAX];
  int flags[FLAGS_LEN], pindex = 0, bindex;
  register FlagList *flist;

  if (get_flags_elt(obj, FLAGS, flags) == -1) {
    notify_player(player, cause, player, "<Spammed flags>", 0);
  } else {
    strcpy(buffer, "Type: ");
    switch (flags[0] & TYPE_MASK) {
    case TYP_ROOM:
      strcat(buffer, "Room");
      break;
    case TYP_EXIT:
      strcat(buffer, "Exit");
      break;
    case TYP_PLAYER:
      strcat(buffer, "Player");
      break;
    case TYP_THING:
      strcat(buffer, "Thing");
      break;
    default:
      strcat(buffer, "*UNKNOWN TYPE*");
    }

    /*
     * We now assign pointers, so that we can sort them ala the short
     * flags display.
     */
    for (flist = GenFlags; flist->name; flist++) {
      if (flags[flist->word] & flist->code) {
	bufptr[pindex].chr = flist->chr;
	bufptr[pindex++].name = flist->name;
      }
    }
    switch(Typeof(obj)) {
    case TYP_ROOM:
      for(flist = RoomFlags; flist->name; flist++) {
	if(flags[flist->word] & flist->code) {
	  bufptr[pindex].chr = flist->chr;
	  bufptr[pindex++].name = flist->name;
	}
      }
      break;
    case TYP_PLAYER:
      for(flist = PlayerFlags; flist->name; flist++) {
	if(flags[flist->word] & flist->code) {
	  bufptr[pindex].chr = flist->chr;
	  bufptr[pindex++].name = flist->name;
	}
      }
      break;
    case TYP_THING:
      for(flist = ThingFlags; flist->name; flist++) {
	if(flags[flist->word] & flist->code) {
	  bufptr[pindex].chr = flist->chr;
	  bufptr[pindex++].name = flist->name;
	}
      }
      break;
    case TYP_EXIT:
      for(flist = ExitFlags; flist->name; flist++) {
	if(flags[flist->word] & flist->code) {
	  bufptr[pindex].chr = flist->chr;
	  bufptr[pindex++].name = flist->name;
	}
      }
      break;
    }

    if(pindex > 0) {		/* Found some flags... */
      strcat(buffer, "  Flags: ");

      /* Sort bufptr. */
      qsort(bufptr, (pindex - 1), sizeof(struct sortbuf), sort_withbuf);

      /* ..And now finish building the message. */
      for(bindex = 0; bindex < pindex; bindex++) {
        /* Space check. */
        if((strlen(buffer) + strlen(bufptr[bindex].name)) >= sizeof(buffer) - 3)
          break;

        strcat(buffer, bufptr[bindex].name);
        strcat(buffer, " ");
      }

      if (buffer[strlen(buffer) - 1] == ' ')
        buffer[strlen(buffer) - 1] = '\0';
    }
    
    /* Tell them about it. */
    notify_player(player, cause, player, buffer, 0);
  }
}

void display_attributes(player, cause, obj, match)
    int player, cause, obj;
    char *match;
{
  struct attr *atptr;
  struct asearch srch;
  char buf[MEDBUFFSIZ*2];

  for (atptr = attr_first(obj, &srch); atptr != (struct attr *)NULL;
       atptr = attr_next(obj, &srch)) {
    if (!can_see_attr(player, cause, obj, atptr->flags))
      continue;
    if ((match != (char *)NULL) && (match[0] != '\0')
        && !quick_wild_prefix(match, atptr->name))
      continue;
    if (atptr->flags != (DEFATTR_FLGS)) {
      sprintf(buf, "%s(%s): ", atptr->name, display_attrflags(atptr->flags));
      switch(atptr->type) {
      case ATTR_STRING:
        strcat(buf, (atptr->dat).str);
	break;
      case ATTR_LOCK:
        strcat(buf, unparse_boolexp(player, cause, (atptr->dat).lock));
	break;
      }
    } else {
      strcpy(buf, atptr->name);
      strcat(buf, ": ");
      switch(atptr->type) {
      case ATTR_STRING:
        strcat(buf, (atptr->dat).str);
	break;
      case ATTR_LOCK:
        strcat(buf, unparse_boolexp(player, cause, (atptr->dat).lock));
	break;
      }
    }
    notify_player(player, cause, player, buf, 0);
  }
}

void display_attributes_parent(player, cause, obj, match)
    int player, cause, obj;
    char *match;
{
  int parent, depth;
  struct attr *atptr;
  struct asearch srch;
  char buf[MEDBUFFSIZ*2];

  depth = 0;
  parent = obj;
  do {
    for (atptr = attr_first(parent, &srch); atptr != (struct attr *)NULL;
         atptr = attr_next(parent, &srch)) {
      if ((atptr->flags & A_PRIVATE) && (parent != obj))
	continue;
      if ((atptr->flags & A_PICKY) && (Typeof(parent) != Typeof(obj)))
        continue;
      if (isPICKY(parent) && (Typeof(parent) != Typeof(obj)))
        continue;
      if (!can_see_attr(player, cause, obj, atptr->flags))
	continue;
      if ((match != (char *)NULL) && (match[0] != '\0')
          && !quick_wild_prefix(match, atptr->name))
	continue;
      if (attr_source(obj, atptr->name) != parent)
	continue;

      if (atptr->flags != (DEFATTR_FLGS)) {
	sprintf(buf, "%s(%s): ", atptr->name, display_attrflags(atptr->flags));
	switch(atptr->type) {
	case ATTR_STRING:
	  strcat(buf, (atptr->dat).str);
	  break;
	case ATTR_LOCK:
	  strcat(buf, unparse_boolexp(player, cause, (atptr->dat).lock));
	  break;
	}
      } else {
        strcpy(buf, atptr->name);
	strcat(buf, ": ");
	switch(atptr->type) {
	case ATTR_STRING:
	  strcat(buf, (atptr->dat).str);
	  break;
	case ATTR_LOCK:
	  strcat(buf, unparse_boolexp(player, cause, (atptr->dat).lock));
	  break;
	}
      }
      notify_player(player, cause, player, buf, 0);
    }

    if (get_int_elt(parent, PARENT, &parent) == -1)
      break;
    depth++;
  } while ((parent != -1) && (depth <= mudconf.parent_depth));
}