untermud/DOC/
untermud/DOC/U/
untermud/DOC/U/U-examples/
untermud/DOC/internals/
untermud/DOC/wizard/
untermud/MISC/
untermud/MISC/dbchk/
untermud/RWHO/
untermud/RWHO/rwhod/
/*
    Copyright (C)1991, Marcus J. Ranum. All rights reserved.
*/

/* configure all options BEFORE including system stuff. */
#include    "config.h"
#include    "mud.h"
#include    "sbuf.h"
#include    "vars.h"
#include    "look.h"

static void say_other ();
static void say_name ();
static int known (char *att);


/*
this is to enable/disable TinyMUD-style object IDs after looked at stuff
which means you do a lock evaluation every time you look at something. UGH!
*/
#ifdef  LOOK_OBJECT_IDS
#define DISPLAY_NAME(who,ob,showoid)    say_name(who,ob,showoid)
#else
#define DISPLAY_NAME(who,ob,junk)   say(who,ut_name(ob),"\n",(char *)0)
#endif



#define ISDARK(obj) (ut_flagged((obj),var_isdark))

/*
 * Setup macro for whether a player is a valid
 * player or not, given who is calling and the
 * look flags.  If ignoring unconnected players,
 * the check ensures that the player isn't the
 * current player, that the player isn't DARK,
 * and that either unconnected players are
 * to be shown or the player is connected.
 * Note that the DARK check uses the macro defined
 * above.
 *
 * If ignoring unconnected players, the check
 * just ensures that the player isn't DARK, using
 * the ISDARK macro.
 */
#ifdef CONNONLY
#define VALID_PLAYER(who,ply,flg) \
    (strcmp((who),(ply)) && \
    (!ISDARK((ply))) && \
    (((flg) & LOOK_UNCONN) || playerconn((ply))))
#else
#define VALID_PLAYER(who,ply,flg) \
    (strcmp((who),(ply)) && \
    (!ISDARK((ply))))
#endif



/* look at something */
void lookat (char *who, char *thing, int flg)
{
  char nxtu[MAXOID];
  char *dp;

  /* flagged to print the thing's name */
  if (flg & LOOK_NAME) {
    DISPLAY_NAME (who, thing, (ut_flagged (who, var_wiz)
        || ut_isobjown (who, thing)
        || !bool_locked (who, thing, (char *) 0, var_link, 1)));
  }
  dp = ut_getatt (thing, 0, typ_str, var_desc, (char *) 0);
  if (dp == (char *) 0) {
    say (who, "You see nothing special.\n", (char *) 0);
  } else {
    say (who, dp, "\n", (char *) 0);
  }

#ifdef  TINYHACK
  /* This revolting little bit of cat vomit is for compatibility with */
  /* converted Tiny* style databases.  The code that is commented out */
  /* would be the "right thing" to do if you were really going to do  */
  /* this.  The working stuff is the minimum that needs to be done.   */

  if (ut_flagged (thing, var_isroom)) {
    int ac = 0;
    char *av[2];
    av[0] = av[1] = (char *) 0;

    if (bool_locked (who, thing, thing, var_lock, 0)) {
      (void) activate (ACTIV_PONLY, who, thing, thing, var_fail, ac, av);
      (void) activate (ACTIV_ECAST, who, thing, thing, var_ofail, ac, av);
    } else {
      (void) activate (ACTIV_PONLY, who, thing, thing, var_succ, ac, av);
      (void) activate (ACTIV_ECAST, who, thing, thing, var_osucc, ac, av);
    }
  }
#endif

  /* Don't show any lists if this thing is dark */

  if (ISDARK (thing))
    return;

  /* players? */
  dp = ut_getatt (thing, 0, typ_list, var_ply, (char *) 0);
  if ((flg & LOOK_PLAY) && dp != (char *) 0) {
    int numdisp = 0;
    char *savelst = dp;

    while ((dp = lstnext (dp, nxtu, sizeof (nxtu))) != (char *) 0)
      if (VALID_PLAYER (who, nxtu, flg))
        numdisp++;
    if (numdisp > 0) {
      say (who, "Players:\n", (char *) 0);
      dp = savelst;
      while ((dp = lstnext (dp, nxtu, sizeof (nxtu))) != (char *) 0)
        if (VALID_PLAYER (who, nxtu, flg))
          DISPLAY_NAME (who, nxtu, 0);
    }
  }
#ifdef  COMBAT
  dp = ut_getatt (thing, 0, typ_obj, var_weapon, (char *) 0);
  if (dp != (char *) 0 && !ISDARK (dp))
    say (who, "Wielding: ", ut_name (dp), "\n", (char *) 0);
#endif

  /* carrying or contents? */
  dp = ut_getatt (thing, 0, typ_list, var_cont, (char *) 0);
  if ((flg & (LOOK_CARRY | LOOK_CONT)) && dp != (char *) 0) {
    int numdisp = 0;
    char *savelst = dp;

    while ((dp = lstnext (dp, nxtu, sizeof (nxtu))) != (char *) 0)
      if (!ISDARK (nxtu))
        numdisp++;

    if (numdisp > 0) {
      if (flg & LOOK_CARRY)
        say (who, "Carrying:\n", (char *) 0);
      else
        say (who, "Contents:\n", (char *) 0);

      dp = savelst;
      while ((dp = lstnext (dp, nxtu, sizeof (nxtu))) != (char *) 0)
        if (!ISDARK (nxtu))
          DISPLAY_NAME (who, nxtu, 0);
    }
  }

  /* wearing */
  dp = ut_getatt (thing, 0, typ_list, var_wearing, (char *) 0);
  if ((flg & LOOK_CARRY) && dp != (char *) 0) {
    int numdisp = 0;
    char *savelst = dp;

    while ((dp = lstnext (dp, nxtu, sizeof (nxtu))) != (char *) 0)
      if (!ISDARK (nxtu))
        numdisp++;

    if (numdisp > 0) {
      say (who, "Wearing:\n", (char *) 0);
      dp = savelst;
      while ((dp = lstnext (dp, nxtu, sizeof (nxtu))) != (char *) 0)
        if (!ISDARK (nxtu))
          DISPLAY_NAME (who, nxtu, 0);
    }
  }
#ifdef  LIST_EXITS
  /* Listing of non dark exits added by Ed Hand  6/27/91  */
  dp = ut_getatt (thing, 0, typ_list, var_xit, (char *) 0);
  if ((flg & LOOK_NAME) && dp != (char *) 0) {
    int numdisp = 0;
    char *savelst = dp;

    while ((dp = lstnext (dp, nxtu, sizeof (nxtu))) != (char *) 0)
      if (!ISDARK (nxtu))
        numdisp++;

    if (numdisp > 0) {
      say (who, "Obvious Exits:\n", (char *) 0);
      dp = savelst;
      while ((dp = lstnext (dp, nxtu, sizeof (nxtu))) != (char *) 0)
        if (!ISDARK (nxtu))
          DISPLAY_NAME (who, nxtu, 0);
    }
  }
#endif /* LIST_EXITS */

  /* using? */
  dp = ut_getatt (thing, 0, typ_obj, var_using, (char *) 0);
  if ((flg & LOOK_USING) && dp != (char *) 0 && !ISDARK (dp))
    (void) say_attribute (who, thing, var_using, (char *) 0, 0);
}



static void say_name (char *who, char *ob, int showoid)
{
  if (showoid)
    say (who, ut_name (ob), "(", ob, ")\n", (char *) 0);
  else
    say (who, ut_name (ob), "\n", (char *) 0);
}


/*
  ob - name or OID of the object
  att -the attribute to look for
  title - optional title, overrides default
  showoid - show object ids?
 */
int say_attribute (char *who, char *ob, char *att, char *title, int showoid)
{
  char tbuf[MAXOID];            /* buffer for the title */
  Obj *op;                      /* pointer to the object */
  char *atp;                    /* pointer to the attribute */
  char *atd;

  if ((op = cache_get (ob)) == (Obj *) 0)
    return (1);

  if ((atp = objattr (op, att, (int *) 0)) == (char *) 0)
    return (1);

  atd = attdata (atp);

  /* possibly generate a title */
  if (title == (char *) 0) {
    fndvnam (att, tbuf, sizeof (tbuf));
    title = tbuf;
  }

  /* here we have to use the stretchy-buffer version of listnext */
  if (attistype (atp, typ_list)) {      /* a list? */
    Sbuf sb;

    if (atd == (char *) 0 || *atd == '\0')
      return (1);
    say (who, title, ":\n", (char *) 0);

    sbuf_initstatic (&sb);
    while ((atd = lstnextsbuf (atd, &sb)) != (char *) 0)
      say_name (who, sbuf_buf (&sb), showoid);
    sbuf_freestatic (&sb);
  } else if (attistype (atp, typ_obj)) {        /* an object? */
    if (atd == (char *) 0 || *atd == '\0')
      return (1);
    say (who, title, ": ", (char *) 0);
    say_name (who, atd, showoid);
  } else if (attistype (atp, typ_flag)) {       /* a flag? */
    say (who, title, " ", (char *) 0);
  } else if (attistype (atp, typ_cmd)) {        /* a command? */
    if (atd == (char *) 0 || *atd == '\0')
      return (1);
    say (who, title, "(macro): ", atd, "\n", (char *) 0);
  } else if (attistype (atp, typ_u)) {  /* U-code? */
    if (atd == (char *) 0 || *atd == '\0')
      return (1);
    say (who, title, "(U-code): ", atd, "\n", (char *) 0);
  } else {
    if (atd == (char *) 0 || *atd == '\0')
      return (1);
    say (who, title, ": ", atd, "\n", (char *) 0);
  }
  return (0);
}




static void say_other (char *who, char *ob)
{
  char aname[MAXOID];
  Obj *op;                      /* pointer to the object */
  int a;

  if ((op = cache_get (ob)) == (Obj *) 0)
    return;

  for (a = 0; a < (int) op->ocnt; a++) {
    if (attname (op->oap[a], aname) == 0 && !known (aname))     /* an unknown! */
      (void) say_attribute (who, ob, aname, aname, 1);
  }
}




/* attributes in the order you want to to see them */
static char *flgs[] = {
  var_isroom, var_isplay, var_wiz, var_isdark,
  var_islocal,
#ifdef  COMBAT
  var_isdead, var_isweapon, var_isarmor,
#endif
  0
};



static char *atts[] = {
  var_nam, var_desc, var_text, var_owner,
  var_ply, var_cont, var_using, var_xit,
  var_lock, var_link, var_succ, var_osucc,
  var_fail, var_ofail, var_drop, var_odrop,
  var_loc, var_dest, var_home, var_dropto,
  var_newsart, var_subive, var_objive, var_posive,
#ifdef  COMBAT
  var_weapon,
#endif
  var_pass, 0
};



static int known (char *att)
{
  char **ap;

  for (ap = flgs; *ap != (char *) 0; ++ap)
    if (strcmp (att, *ap) == 0)
      return (2);
  for (ap = atts; *ap != (char *) 0; ++ap)
    if (strcmp (att, *ap) == 0)
      return (1);
  return (0);
}



int do_examine (char *who, char *aswho, char *ob)
{
  char **ap;

  if (ut_flagged (ob, var_isplay)) {
    say (who, "A player", (char *) 0);
  } else if (ut_flagged (ob, var_isroom)) {
    say (who, "A room", (char *) 0);
  } else
    if (lstlook (ut_getatt (ob, 0, typ_list, var_loc, var_xit, (char *) 0),
      ob)) {
    say (who, "An exit", (char *) 0);
  } else {
    say (who, "An object", (char *) 0);
  }
  say (who, " named: ", (char *) 0);
  say_name (who, ob, 1);

  if (!ut_flagged (aswho, var_wiz) && !ut_isobjown (aswho, ob)) {
    char *here, *there;

    here = ut_loc (aswho);
    there = ut_loc (ob);
    if (!strcmp (here, there) || !strcmp (here, ob) || !strcmp (there, aswho)) {
      (void) say_attribute (who, ob, var_desc, (char *) 0, 0);
      (void) say_attribute (who, ob, var_owner, (char *) 0, 1);
    }
    return (0);
  }

  say (who, "Flags: ", (char *) 0);
  for (ap = flgs; *ap != (char *) 0; ++ap)
    (void) say_attribute (who, ob, *ap, (char *) 0, 0);
  say (who, "\n", (char *) 0);

  for (ap = atts + 1; *ap != (char *) 0; ++ap)
    (void) say_attribute (who, ob, *ap, (char *) 0, 1);

  say_other (who, ob);
  return (0);
}