TinyMAZE/
TinyMAZE/config/
TinyMAZE/doc/
TinyMAZE/run/msgs/
TinyMAZE/src/
TinyMAZE/src/db/
TinyMAZE/src/ident/
TinyMAZE/src/io/
TinyMAZE/src/prog/
TinyMAZE/src/softcode/
TinyMAZE/src/util/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "db.h"
#include "config.h"
#include "externs.h"
#include "powers.h"

static int num_builtin_exits(OBJ *loc)
{
  int ctr = 0;

  if(*atr_get(loc, "NORTH"))
    ctr++;
  if(*atr_get(loc, "SOUTH"))
    ctr++;
  if(*atr_get(loc, "EAST"))
    ctr++;
  if(*atr_get(loc, "WEST"))
    ctr++;
  if(*atr_get(loc, "NORTHEAST"))
    ctr++;
  if(*atr_get(loc, "NORTHWEST"))
    ctr++;
  if(*atr_get(loc, "SOUTHEAST"))
    ctr++;
  if(*atr_get(loc, "SOUTHWEST"))
    ctr++;

  return(ctr);
}

char *pseudo_exit_name(OBJ *loc, char *atrname)
{
  char buf[4096];
  OBJ *link;
  int i;
  struct
  {
    char *atrname;
    char *name;
  } exits[] =
  { {"NORTH", "North <N>"}, {"SOUTH", "South <S>"}, {"EAST", "East <E>"},
    {"WEST", "West <W>"}, {"NORTHEAST", "Northeast <NE>"},
    {"SOUTHEAST", "Southeast <SE>"}, {"SOUTHWEST", "Southwest <SW>"},
    {"NORTHWEST", "Northwest <NW>"}, {NULL, NULL}
  };

  for(i = 0;exits[i].atrname;++i)
    if(!string_compare(exits[i].atrname, atrname))
      break;

  if(!(exits[i].atrname))
    return("");

  if((link = match_dbref(atr_get(loc, atrname), TYPE_ROOM)))
  {
    if(my_is_color(atr_get(link, "COLOR")))
      sprintf(buf, "|%s|%s", atr_get(link, "COLOR"), exits[i].name);
    else
      sprintf(buf, "|n|%s", exits[i].name);
  }
  else
    sprintf(buf, "|n|%s", exits[i].name);

  return(stack_string_alloc(buf, 0));
}

static char *list_builtin_exits(OBJ *loc, int *ctr)
{
  char buf[4096], buf2[4096];

  *buf = '\0';

  if(*atr_get(loc, "NORTH"))
  {
    strcpy(buf2, pseudo_exit_name(loc, "NORTH"));

    if(!(*ctr)++)
      strcpy(buf, buf2);
    else
      sprintf(buf+strlen(buf), " %s", buf2);
  }
  if(*atr_get(loc, "SOUTH"))
  {
    strcpy(buf2, pseudo_exit_name(loc, "SOUTH"));

    if(!(*ctr)++)
      strcpy(buf, buf2);
    else
      sprintf(buf+strlen(buf), " %s", buf2);
  }
  if(*atr_get(loc, "EAST"))
  {
    strcpy(buf2, pseudo_exit_name(loc, "EAST"));

    if(!(*ctr)++)
      strcpy(buf, buf2);
    else
      sprintf(buf+strlen(buf), " %s", buf2);
  }
  if(*atr_get(loc, "WEST"))
  {
    strcpy(buf2, pseudo_exit_name(loc, "WEST"));

    if(!(*ctr)++)
      strcpy(buf, buf2);
    else
      sprintf(buf+strlen(buf), " %s", buf2);
  }
  if(*atr_get(loc, "NORTHEAST"))
  {
    strcpy(buf2, pseudo_exit_name(loc, "NORTHEAST"));

    if(!(*ctr)++)
      strcpy(buf, buf2);
    else
      sprintf(buf+strlen(buf), " %s", buf2);
  }
  if(*atr_get(loc, "NORTHWEST"))
  {
    strcpy(buf2, pseudo_exit_name(loc, "NORTHWEST"));

    if(!(*ctr)++)
      strcpy(buf, buf2);
    else
      sprintf(buf+strlen(buf), " %s", buf2);
  }
  if(*atr_get(loc, "SOUTHEAST"))
  {
    strcpy(buf2, pseudo_exit_name(loc, "SOUTHEAST"));

    if(!(*ctr)++)
      strcpy(buf, buf2);
    else
      sprintf(buf+strlen(buf), " %s", buf2);
  }
  if(*atr_get(loc, "SOUTHWEST"))
  {
    strcpy(buf2, pseudo_exit_name(loc, "SOUTHWEST"));

    if(!(*ctr)++)
      strcpy(buf, buf2);
    else
      sprintf(buf+strlen(buf), " %s", buf2);
  }

  return(stack_string_alloc(buf, 0));
}

static void look_exits(OBJ *player, OBJ *loc, char *exit_name)
{
  OBJ *thing;
  char buff[4096];
  int ctr = 0;

  for(thing = loc->exits;thing;thing = thing->next_exit)
    if(can_see(player, thing, !is_dark(loc)))
      ctr++;
  ctr += num_builtin_exits(loc);
  if(!ctr)
  {
    notify(player, "|+W|No obvious exits");
    return;
  }

  notify(player, exit_name);

  ctr = 0;
  strcpy(buff, list_builtin_exits(loc, &ctr));

  for(thing = loc->exits;thing;thing = thing->next_exit)
    if(can_see(player, thing, !is_dark(loc)))
    {
      if(!ctr++)
        strcpy(buff, name(thing));
      else
        sprintf(buff+strlen(buff), " %s", name(thing));
    }

  if(*buff)
    notify(player, buff);
  else            /* Only get here if a room is set dark */
    notify(player, "|+W|No obvious exits");
}

static void look_contents(OBJ *player, OBJ *loc, char *contents_name)
{
  OBJ *thing;
  int can_see_loc;
  int contents = 0;
  char *clr = "n";
  char x_buf[256];
  DDATA *d;

/* Check to see if he can see the location */
  can_see_loc = !is_dark(loc);

/* Check to see if there is anything there */
  for(thing = loc->contents;thing;thing = thing->next_con)
    if(can_see(player, thing, can_see_loc))
      contents++;

  if(!contents)
    return;

  notify(player, contents_name);
  for(thing = loc->contents;thing;thing = thing->next_con)
  {
    if(!can_see(player, thing, can_see_loc))
      continue;

    strcpy(x_buf, "");
    if(my_is_color(atr_get(thing, "COLOR")))
      clr = atr_get(thing, "COLOR");
    else
      clr = "n";
    if((d = is_idle(thing)))
      strcat(x_buf, tprintf("|+W| (%s)",
        time_format(now-d->last_time, 1)));
    notify(player, tprintf("%s|%s| %s%s",
      unparse_object(player, thing), clr,
      atr_get(thing, "CAPTION"), x_buf));
  }
}

static void look_simple(OBJ *player, OBJ *thing)
{
  char *str;
  char *clr = "n";
  char x_buf[256];
  DDATA *d;

/* If it's not an exit or it's not set transparent */
  if(Typeof(thing) != TYPE_EXIT || !(thing->flags & OPAQUE))
  {
    strcpy(x_buf, "");

    if(my_is_color(atr_get(thing, "COLOR")))
      clr = atr_get(thing, "COLOR");
    else
      clr = "n";

    if(Typeof(thing) == TYPE_EXIT)
      notify(player, tprintf("%s|%s| %s", unparse_object(player, thing),
        clr, atr_get(thing, "CAPTION")));
    else
    {
      if((d = is_idle(thing)))
        strcat(x_buf, tprintf("|+W| (%s)",
          time_format(now-d->last_time, 1)));
      notify(player,tprintf("%s|%s| %s%s",
        unparse_object(player, thing),
        clr, atr_get(thing, "CAPTION"), x_buf));
    }

    if(Typeof(thing) == TYPE_PLAYER)
      str = "I'm descriptionless. Sorry.";
    else
      str = "What you see is beyond description.";

    did_it(player, thing, "DESC", str, "PLEAVE");
  }

  if(Typeof(thing) == TYPE_EXIT && thing->flags & OPAQUE)
  {
    if(thing->link)
    {
      notify(player,
        tprintf("You peer through to %s...", name(thing->link)));
      did_it(player, thing->link, "DESC",
        "You see nothing on the other side.", "PDESC");
      look_contents(player, thing->link, "|+W|Contents:");
    }
    else
      notify(player, "It's too dark to see anything.");
  }
}

void look_room(OBJ *player, OBJ *loc)
{
  char buf[4096];
  char *clr = "n";

  if(my_is_color(atr_get(loc, "COLOR")))
    clr = atr_get(loc, "COLOR");

  sprintf(buf, "%s|%s| %s", unparse_object(player, loc),
    clr, atr_get(loc, "CAPTION"));

  notify(player, buf);

  if(Typeof(loc) == TYPE_ROOM)
  {
    if(!(player->flags & PLAYER_TERSE))
      did_it(player, loc, "DESC", NULL, "PDESC");

    if(could_doit(player, loc, "LOCK"))
      did_it(player, loc, "SUCC", NULL, "PSUCC");
    else
      did_it(player, loc, "FAIL", NULL, "PFAIL");
  }
  
  look_contents(player, loc, "|+W|Contents:");
  look_exits(player, loc, "|+W|Obvious exits:");
}

void do_look_around(OBJ *player)
{
  look_room(player, player->location);
}

void do_look_at(OBJ *player, char *arg1)
{
  OBJ *thing;
  
  if(!*arg1)
  {
    look_room(player, player->location);
    return;
  }

  thing = match_object(player, arg1, NOTYPE);
  if(!thing)
  {
    notify(player, no_match(arg1));
    return;
  }
	
  if(Typeof(thing) == TYPE_ROOM)
    look_room(player, thing);
  else
    look_simple(player, thing);
}

char *flag_description(OBJ *thing)
{
  char buf[4096];
  
  strcpy(buf, "|+B|Type:|n| ");
  switch(Typeof(thing))
  {
    case TYPE_ROOM:
      strcat(buf, "Room");
      break;
    case TYPE_EXIT:
      strcat(buf, "Exit");
      break;
    case TYPE_THING:
      strcat(buf, "Thing");
      break;
    case TYPE_PLAYER:
      strcat(buf, "Player");
      break;
  }
  
/* Print flags */
  strcat(buf, "      |+B|Flags:|n|");
  if(thing->flags & PUPPET)
    strcat(buf," puppet");
  if(thing->flags & DARK)
    strcat(buf," dark");
  if(thing->flags & HAVEN)
    strcat(buf," haven");
  if(thing->flags & VISIBLE)
    strcat(buf," visible");
  if(thing->flags & OPAQUE)
    strcat(buf, (Typeof(thing) == TYPE_EXIT)?" transparent":" opaque");
  if(thing->flags & INHERIT_POWERS)
    strcat(buf," inherit");
  if(thing->flags & QUIET)
    strcat(buf," quiet");
  if(is_connected_raw(thing))
    strcat(buf," connected");
  switch(Typeof(thing))
  {
    case TYPE_PLAYER:
      if(thing->flags & PLAYER_SLAVE)
        strcat(buf," slave");
      if(thing->flags & PLAYER_TERSE)
        strcat(buf," terse");
      if(thing->flags & PLAYER_ANSI)
        strcat(buf," ansi");
      if(thing->flags & PLAYER_MORTAL)
        strcat(buf," mortal");
      if(thing->flags & PLAYER_NO_WALLS)
        strcat(buf," no_walls");
      if(thing->flags & PLAYER_NO_COM)
        strcat(buf," no_com");
      if(thing->flags & PLAYER_NO_ANN)
        strcat(buf," no_ann");
      break;
    case TYPE_EXIT:
      if(thing->flags & EXIT_LIGHT)
        strcat(buf," light");
      break;
    case TYPE_THING:
      if(thing->flags & THING_LIGHT)
        strcat(buf," light");
      break;
    case TYPE_ROOM:
      if(thing->flags & ROOM_FLOATING)
        strcat(buf," floating");
      break;
  }

  return(stack_string_alloc(buf, 0));
}

void look_atr(OBJ *player, OBJ *thing, ATTR *attr)
{
  char buf[4096];
  OBJ *o;
  char *value;

  value = atr_get_a(thing, attr);

  sprintf(buf, "|+B|%s%s|+C|[|+W|%s|+C|]|+B|:|n| ", attr->name,
    (attr->flags&AF_FUNC)?"()":"", unparse_atr_flags(attr->flags));

  if(attr->flags & AF_DATE)
    notify(player, tprintf("%s%s", buf,
      mktm(atol(value), "D", player)));
  else if(attr->flags & AF_LOCK)
    notify(player, tprintf("%s%s", buf,
      unprocess_lock(player, value)));
  else if(attr->flags & AF_DBREF)
  {
    if(!*value || !(o = find_object(atoi((value)+1))))
      notify(player, tprintf("%s%s", buf, value));
    else
      notify(player, tprintf("%s%s", buf,
        unparse_object(player, o)));
  }
  else
    notify(player, tprintf("%s%s", buf, value));
}

static void look_atrs(OBJ *player, OBJ *thing)
{
  ALIST *atr;

  for(atr = thing->attrlist;atr;atr = atr->next)
    if(can_see_atr(player, thing, atr->attr))
      look_atr(player, thing, atr->attr);
}

static int check_builtin_attrs(OBJ *player, char *arg)
{
  char *attr_name;
  OBJ *victim;

  if(!(attr_name = strchr(arg, '/')))
    return(0);

  *attr_name++ = '\0';

  if(!(victim = match_object(player, arg, NOTYPE)))
    return(0);

  if(!string_compare(attr_name, "name"))
    notify(player, tprintf("|+B|Name: %s", name(victim)));
  else if(!string_compare(attr_name, "flags"))
    notify(player, tprintf("|+B|Flags: |n|%s", unparse_flags(victim)));
  else if(!string_compare(attr_name, "location"))
    notify(player, tprintf("|+B|Location: %s",
      unparse_object(player, victim->location)));
  else if(!string_compare(attr_name, "link"))
    notify(player, tprintf("|+B|Link: %s",
      unparse_object(player, victim->link)));
  else if(!string_compare(attr_name, "owner"))
    notify(player, tprintf("|+B|Owner: %s",
      unparse_object(player, victim->owner)));
  else if(!string_compare(attr_name, "creator"))
    notify(player, tprintf("|+B|Creator: %s",
      unparse_object(player, victim->creator)));
  else if(!string_compare(attr_name, "modified"))
  {
    if(!victim->mod_time)
      notify(player, "|+B|Modified: |n|NEVER");
    else
      notify(player, tprintf("|+B|Modified: |n|%s",
        mktm(victim->mod_time, "D", player)));
  }
  else if(!string_compare(attr_name, "created"))
  {
    if(!victim->create_time)
      notify(player, "|+B|Created: |n|NEVER");
    else
      notify(player, tprintf("|+B|Created: |n|%s",
        mktm(victim->create_time, "D", player)));
  }
  else
    return(0);

  return(1);
}

void do_examine(OBJ *player, char *arg)
{
  ATTR *attr;
  OBJ *thing;
  OBJ *what;
  int pos = 0;
  char buf[4096];
  int objects;

  if(!*arg)
    thing = player->location;
  else
  {
    if(strchr(arg, '/'))
    {
      if(!parse_attrib(player, arg, &thing, &attr))
      {
        if(!check_builtin_attrs(player, arg))
          notify(player, "No match.");
        return;
      }

      if(!can_see_atr(player, thing, attr))
      {
        notify(player, perm_denied());
        return;
      }

      look_atr(player, thing, attr);
      return;
    }

    thing = match_object(player, arg, NOTYPE);
    if(!thing)
    {
      notify(player, no_match(arg));
      return;
    }
  }
  
  if((!controls(player, thing, POW_EXAMINE) &&
    !(thing->flags & VISIBLE)))
  {
    strcpy(buf, unparse_object(player, thing));
    notify(player, tprintf("%s is owned by %s",
      buf, unparse_object(player, thing->owner)));

    return;
  }

  notify(player, unparse_object(player, thing));

  if(*Desc(thing) && can_see_atr(player, thing, find_attr("Desc")))
    notify(player, Desc(thing));
  
  if(Typeof(thing) == TYPE_PLAYER)
  {
    strcpy(buf, " |+B|Quota-Left:|n| ");
    if(power(thing, POW_NOQUOTA))
      strcat(buf, "INFINITE");
    else
    {
      objects = owns_stuff(thing);
      if(atoi(atr_get(thing, "QUOTA"))-objects <= 0)
        strcat(buf, "NONE");
      else
        sprintf(buf, "%d", atoi(atr_get(thing, "QUOTA"))-objects);
    }
  }

  notify(player,
    tprintf("|+B|Owner:|n| %s |+B|%s:|n| %ld",
    name(thing->owner), config.currency_plural, Pennies(thing)));
  notify(player, flag_description(thing));
  notify(player, tprintf("|+B|Created:|n| %s by %s",
    mktm(thing->create_time, "D", player),
    unparse_object(player, thing->creator)));
  notify(player, tprintf("|+B|Modified:|n| %s",
    (thing->mod_time > 0)?mktm(thing->mod_time, "D", player):"never"));

  look_atrs(player, thing);

  look_contents(player, thing, "|+W|Contents:");
  
  switch(Typeof(thing))
  {
    case TYPE_ROOM:
      for(what = exit_list;what;what = what->next)
        if(what->link && what->link == thing)
        {
          if(!pos)
          {
            notify(player, "|+W|Entrances:");
            pos = 1;
          }
          notify(player, unparse_object(player, what));
        }

      if(!pos)
        notify(player, "No entrances.");

      if(thing->exits)
      {
        notify(player, "|+W|Exits:");
        for(what = thing->exits;what;what = what->next_exit)
          notify(player, unparse_object(player, what));
      }
      else
        notify(player, "No exits.");
      break;

    case TYPE_THING:
    case TYPE_PLAYER:
      notify(player, tprintf( "|+B|Home:|n| %s",
        unparse_object(player, thing->link)));
      if(controls(player, thing->location, POW_EXAMINE) ||
        controls(player, thing, POW_EXAMINE))
      {
        notify(player, tprintf( "|+B|Location:|n| %s",
          unparse_object(player, thing->location)));
      }
      break;

    case TYPE_EXIT:
      notify(player, tprintf("|+B|Source:|n| %s",
        unparse_object(player, thing->location)));
      if(thing->link)
        notify(player, tprintf("|+B|Destination:|n| %s",
        unparse_object(player, thing->link)));
      break;
  }
}

void do_find(OBJ *player, char *arg)
{
  OBJ *o;
  int ctr = 0;
  
  if(!*arg)
  {
    notify(player, "Find what?");
    return;
  }

  for(o = player_list;o;o = o->next)
    if(string_match(o->name, arg))
      if(controls(player, o->owner, POW_EXAMINE))
      {
        notify(player, unparse_object(player, o));
        ctr++;
      }
  for(o = thing_list;o;o = o->next)
    if(string_match(o->name, arg))
      if(controls(player, o->owner, POW_EXAMINE))
      {
        notify(player, unparse_object(player, o));
        ctr++;
      }

  for(o = room_list;o;o = o->next)
    if(string_match(o->name, arg))
      if(controls(player, o->owner, POW_EXAMINE))
      {
        notify(player, unparse_object(player, o));
        ctr++;
      }

  if(ctr)
    notify(player,
      tprintf("|+C|%d |+B|match%s found.",
      ctr, check_plural(ctr, "", "es")));
  else
    notify(player, "No matches were found.");
}

void do_whereis(OBJ *player, char *arg)
{
  OBJ *thing;
  
  if(!*arg)
  {
    notify(player, "Where is who?");
    return;
  }

  thing = match_object(player, arg, NOTYPE);
  if(!thing)
  {
    if(!(thing = match_player(NULL, arg)))
    {
      notify(player, no_match(arg));
      return;
    }
  }
  
  if(thing->owner == player)
  {
    notify(player, tprintf("%s is at %s.",
      unparse_object(player, thing),
      unparse_object(player, thing->location)));
    return;
  }

  if(Typeof(thing) == TYPE_PLAYER && thing->flags & DARK)
  {
    notify(player, tprintf("%s wishes to have some privacy.",
      name(thing)));

    if(!controls(player, thing, POW_EXAMINE))
    {
      notify(thing,
        tprintf("%s tried to locate you and failed.",
          unparse_object(thing, player)));
      return;
    }

    notify(player,
        tprintf("Too bad! You use your powers to find %s anyway...",
        name(thing)));
  }

  notify(player, tprintf("%s is at %s.",
    unparse_object(player, thing),
    unparse_object(player, thing->location)));
  notify(thing, tprintf("%s has just located your position.",
    unparse_object(thing, player)));
}

void do_laston(OBJ *player, char *arg)
{
  char *attr;
  OBJ *thing;
  time_t tim1, tim2;
  char *p;

/* Show a list of players */
  if(!*arg)
  {
    FILE *fp;
    const char *filename = "laston.db";
    char buf[256];
    char part1[256];
    char host[256];
    int num_lines = 0, ctr = 0;
    int color = 0;
    char *clr_str;

    if((fp = fopen(filename, "r")) == NULL)
    {
      notify(player, "You must specify a valid player's name.");
      log_error(tprintf("Missing \"%s\" file for +laston!", filename));
      return;
    }

    while(!feof(fp))
    {
      fgets(buf, sizeof(buf), fp);
      num_lines++;
    }

    fclose(fp);

    if((fp = fopen(filename, "r")) == NULL)
    {
      notify(player, "You must specify a valid player's name.");
      log_error(tprintf("Missing \"%s\" file for +laston!", filename));
      return;
    }

    while(++ctr < num_lines-15)
      fgets(buf, sizeof(buf), fp);

    notify(player, tprintf("|+B|.%s.", my_string("-", 77)));
    notify(player, tprintf("|+B|||+B|%s|+B||",
      my_center("Last Players Connected", 77)));
    notify(player, tprintf("|+B||%s|", my_string("-", 77)));
    notify(player,
      tprintf("|+B|||+W|%s|+B|||+W|          TIME            |+B|||+W|%s|+B||",
      my_center("NAME", 21), my_center("HOST", 28)));
    notify(player, tprintf("|+B||%s|--------------------------|%s|",
      my_string("-", 21), my_string("-", 28)));

    while(!feof(fp))
    {
      if(color)
      {
        color = 0;
        clr_str = "|C|";
      }
      else
      {
        color = 1;
        clr_str = "|+C|";
      }

      buf[0] = '\0';

      fgets(buf, 22, fp);
      if(strlen(buf) < 15)
        break;
      buf[strlen(buf)-1] = '\0';
      p = &buf[strlen(buf)-1];
      while(p != buf && *p == ' ')
        p--;
      *(p+1) = '\0';
      strcpy(part1, buf);
      fgets(buf, sizeof(buf), fp);
      buf[strlen(buf)-1] = '\0';
      p = &buf[strlen(buf)-1];
      while(p != buf && *p != ' ')
        p--;
      strcpy(host, p+1);
      *p = '\0';

      if(!power(player, POW_HOST))
        strcpy(host, "???");

      notify(player, 
        tprintf("|+B|| %s%s|+B|| %s%s |+B|| %s%s|+B||",
        clr_str, my_ljust(part1, 20), clr_str, buf, clr_str,
        my_ljust(host, 27)));
    }
    notify(player, tprintf("|+B|`%s'", my_string("-", 77)));
    fclose(fp);
    return;
  } 
  
  if(!(thing = match_player(NULL, arg)))
  {
    notify(player, no_match(arg));
    return;
  }
  
  if(!could_doit(player, thing, "LHIDE") &&
    !controls(player, thing, POW_EXAMINE) && player != thing)
  {
    notify(player, tprintf("%s is hidden from you.", name(thing)));
    return;
  }

  attr = atr_get(thing, "LASTCONN");
  tim1 = atol(attr);
  if(!tim1)
  {
    notify(player, tprintf("%s has never logged on.", name(thing)));
    return;
  }
  notify(player,
    tprintf("%s |+B|was last logged on|+W|: |+C|%s",
    name(thing), mktm(tim1, "D", player)));

  attr = atr_get(thing, "LASTDISC");
  tim2 = atol(attr);
  notify(player,
    tprintf("%s |+B|last logged off at|+W|: |+C|%s",
    name(thing), mktm(tim2, "D", player)));

  attr = atr_get(thing, "LASTSITE");
  if(strlen(attr) && power(player, POW_HOST))
    notify(player,
      tprintf("%s |+B|last connected from|+W|: |+C|%s",
      name(thing), attr));

  if(tim2 < tim1)
    if(is_connected(player, thing))
      notify(player, tprintf("%s is currently connected.", name(thing)));
}