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 <stdlib.h>
#include <string.h>
#include "externs.h"
#include "db.h"
#include "attrib.h"

#define OSEE AF_OSEE
#define SDARK AF_DARK
#define WIZARD AF_WIZARD
#define UNIMP AF_UNIMP
#define NOMOD AF_NOMOD
#define DATE AF_DATE
#define INH AF_INHERIT
#define LOCK AF_LOCK
#define FUNC AF_FUNC
#define DBREF AF_DBREF
#define NOMEM AF_NOMEM
#define AHAVEN AF_HAVEN
#define APROG AF_PROG

/* Start new attribute declarations with numbers 1000 and higher. */

ATTR atr_list[] =
{
  {"Fail",                INH,                             1},
  {"PFail",               INH|APROG,                       2},
  {"Succ",                INH,                             3},
  {"PSucc",               INH|APROG,                       4},
  {"Password",            WIZARD|SDARK|NOMOD,              5},
  {"Desc",                INH|OSEE,                        6},
  {"PDesc",               INH|APROG,                       7},
  {"Sex",                 INH|OSEE,                        8},
  {"Drop",                INH,                             9},
  {"PDrop",               INH|APROG,                      10},
  {"Color",               INH|OSEE,                       11},
  {"Startup",             INH|WIZARD,                     12},
  {"LastDisc",            WIZARD|DATE|OSEE,               13},
  {"LastConn",            WIZARD|DATE|OSEE,               14},
  {"Enter",               INH,                            15},
  {"PEnter",              INH|APROG,                      16},
  {"Idle",                INH,                            17},
  {"Away",                INH,                            18},
  {"Alias",               OSEE,                           19},
  {"Efail",               INH,                            20},
  {"PEfail",              INH|APROG,                      21},
  {"Leave",               INH,                            22},
  {"PLeave",              INH|APROG,                      23},
  {"Quota",               SDARK|NOMOD|WIZARD|NOMEM,       24},
  {"TZ",                  INH,                            25},
  {"Email",               WIZARD,                         26},
  {"Move",                INH,                            27},
  {"PMove",               INH|APROG,                      28},
  {"Lock",                INH|LOCK,                       29},
  {"LEnter",              INH|LOCK,                       30},
  {"LUse",                INH|LOCK,                       31},
  {"Ufail",               INH,                            32},
  {"PUfail",              INH|APROG,                      33},
  {"Connect",             INH,                            34},
  {"PConnect",            INH|APROG,                      35},
  {"Disconnect",          INH,                            36},
  {"PDisconnect",         INH|APROG,                      37},
  {"WhoFlags",            INH,                            38},
  {"PPage",               INH|APROG,                      39},
  {"LHide",               INH|LOCK,                       40},
  {"LPage",               INH|LOCK,                       41},
  {"Notify",              INH,                            42},
  {"LLeave",              INH|LOCK,                       43},
  {"LFail",               INH,                            44},
  {"PLfail",              INH|APROG,                      45},
  {"Doing",               INH|OSEE,                       46},
  {"Defown",              INH|DBREF|WIZARD,               47},
  {"LastSite",            SDARK|WIZARD|NOMOD,             48},
  {"WhoIs",               INH|OSEE,                       49},
  {"PWhoIs",              INH|APROG,                      50},
  {"RName",               INH|WIZARD,                     51},
  {"Connects",            INH|OSEE|WIZARD|NOMOD,          52},
  {"Caption",             INH|OSEE,                       53},
  {"Parent",              INH,                            54},
  {"PParent",             INH|APROG,                      55},
  {"UnParent",            INH,                            56},
  {"PUnParent",           INH|APROG,                      57},
  {"LSee",                INH|LOCK,                       58},
  {"MOTD",                WIZARD|SDARK,                   59},
  {"Rainbow",             NOMOD|SDARK,                    60},
  {"WhoIdle",             INH,                            61},
  {"WhoColor",            WIZARD|SDARK,                   62},
  {"LastLoc",             NOMOD|SDARK,                    63},
  {"North",               WIZARD|DBREF,                   64},
  {"South",               WIZARD|DBREF,                   65},
  {"East",                WIZARD|DBREF,                   66},
  {"West",                WIZARD|DBREF,                   67},
  {"Northeast",           WIZARD|DBREF,                   68},
  {"Northwest",           WIZARD|DBREF,                   69},
  {"Southeast",           WIZARD|DBREF,                   70},
  {"Southwest",           WIZARD|DBREF,                   71},
  {"CQuota",              NOMOD|SDARK,                    72},
  {"Pennies",             WIZARD|SDARK,                   73},
  {"BadLogins",           WIZARD|SDARK|NOMOD,             74},
  {NULL,                  0L,                             -1}
};

#undef OSEE
#undef SDARK
#undef WIZARD
#undef UNIMP
#undef NOMOD
#undef DATE
#undef INH
#undef LOCK
#undef FUNC
#undef DBREF
#undef NOMEM
#undef AHAVEN
#undef APROG

ATTR *find_attr(char *atrname)
{
  ATTR *a;

  for(a = &atr_list[0];a->name;a++)
    if(!string_compare(a->name, atrname))
      break;

  if(!a->name)
    return((ATTR *)NULL);

  return(a);
}

ATTR *find_attr_by_num(int atrnum)
{
  ATTR *a;

  for(a = &atr_list[0];a->name;a++)
    if(a->atrnum == atrnum)
      return(a);

  return((ATTR *)NULL);
}

ALIST *find_attr_on_obj(OBJ *thing, ATTR *attr)
{
  ALIST *ptr;

  for(ptr = thing->attrlist;ptr;ptr = ptr->next)
    if(ptr->attr == attr)
      break;

  return(ptr);
}

/* Clear an attribute in the list */
void atr_clr(OBJ *thing, char *atrname)
{
  ATTR *attr;

  if(!(attr = find_attr(atrname)))
  {
    log_error(tprintf("atr_clr(): Couldn't find attribute \"%s\"", atrname));
    return;
  }

  atr_clr_a(thing, attr);
}

void atr_clr_a(OBJ *thing, ATTR *attr)
{
  ALIST *ptr, *ptrprev = NULL;

  for(ptr = thing->attrlist;ptr;ptr = ptr->next)
  {
    if(ptr->attr == attr)
      break;
    ptrprev = ptr;
  }

  if(!ptr)
    return;

  if(!ptrprev)
    thing->attrlist = thing->attrlist->next;
  else
    ptrprev->next = ptr->next;

  stack_free(ptr->value);
  stack_free(ptr);
}

/* Add attribute to list */
void atr_add(OBJ *thing, char *atrname, char *val)
{
  ATTR *attr;

  if(!(attr = find_attr(atrname)))
  {
    log_error(tprintf("atr_add(): Couldn't find attribute \"%s\"", atrname));
    return;
  }

  atr_add_a(thing, attr, val);
}

void atr_add_a(OBJ *thing, ATTR *attr, char *val)
{
  ALIST *ptr, *newattr;
  extern int loading_db;
  extern OBJ *cmd_plyr;

/* Objects set NOMODIFY can't be modified. Period. */
/* The only exception is during the database load routine. */
  if(thing->flags & NOMODIFY && !loading_db)
  {
    if(cmd_plyr)
    {
      notify(cmd_plyr, tprintf("|+R|WARNING|+W|: %s |C|is set NOMODIFY!",
        unparse_object(cmd_plyr, thing)));
      notify(cmd_plyr,
        tprintf("|+R|WARNING|+W|: |C|Attribute '%s' left untouched.",
        attr->name));
      notify(cmd_plyr,
        "|+R|WARNING|+W|: |C|Ignore any messages regarding succession.");
    }
    return;
  }

/* Sanity check */
  if(!attr)
    return;

  if(!val)
    val = "";

  if(!(ptr = find_attr_on_obj(thing, attr))) /* Have to add a new one */
  {
    if(!*val)    /* Nevermind, we got lucky */
      return;

    newattr = (ALIST *)stack_alloc(sizeof(ALIST), 1, 0);
    newattr->attr = attr;
    newattr->value = NULL;       /* We'll set this in a sec */
    newattr->next = NULL;
    if(thing->attrlist)
    {
      for(ptr = thing->attrlist;ptr->next;ptr = ptr->next);
      ptr->next = newattr;
    }
    else
      thing->attrlist = newattr;
    ptr = newattr;
  }

  if(!*val)
  {
    atr_clr_a(thing, attr);
    return;
  }

  if(!ptr->value)
    ptr->value = stack_string_alloc(val, 1);
  else
    ptr->value = stack_string_realloc(ptr->value, val);
}

char *atr_get(OBJ *thing, char *atrname)
{
  ATTR *attr;

  if(!(attr = find_attr(atrname)))
  {
    log_error(tprintf("atr_get(): Couldn't find attribute \"%s\"", atrname));
    return("");
  }

  return(atr_get_a(thing, attr));
}

char *atr_get_a(OBJ *thing, ATTR *attr)
{
  ALIST *ptr;

  if((ptr = find_attr_on_obj(thing, attr)))
    return(ptr->value);

  return("");
}

void atr_free(OBJ *thing)
{
  ALIST *ptr, *ptrnext;

  for(ptr = thing->attrlist;ptr;ptr = ptrnext)
  {
    ptrnext = ptr->next;

    stack_free(ptr->value);
    stack_free(ptr);
  }

  thing->attrlist = NULL;
}

int parse_attrib(OBJ *player, char *str, OBJ **thing, ATTR **attr)
{
  char *s;
  char buf[4096];

  strcpy(buf, str);

  if(!(s = strchr(buf, '/')))
    return(0);
  *s++ = '\0';
  if(!(*thing = match_object(player, buf, NOTYPE)))
    return(0);
  if(!(*attr = find_attr(s)))
    return(0);
  if((*attr)->flags & AF_DARK && !can_see_atr(player, *thing, *attr))
    return(0);
  return(1);
}

char *unparse_atr_flags(unsigned long flags)
{
  char buf[4096];
  char *b = buf;

  if(flags & AF_WIZARD)
    *b++ = 'W';
  if(flags & AF_UNIMP)
    *b++ = 'U';
  if(flags & AF_OSEE)
    *b++ = 'O';
  if(flags & AF_INHERIT)
    *b++ = 'I';
  if(flags & AF_DARK)
    *b++ = 'D';
  if(flags & AF_DATE)
    *b++ = 'd';
  if(flags & AF_LOCK)
    *b++ = 'L';
  if(flags & AF_FUNC)
    *b++ = 'F';
  if(flags & AF_HAVEN)
    *b++ = 'H';
  *b = '\0';

  return(stack_string_alloc(buf, 0));
}

char *unparse_attr(ALIST *atr)
{
  char buf[4096] = "|+B|";

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

  return(stack_string_alloc(buf, 0));
}

void my_atr_add(OBJ *thing, char *atrname, long increase)
{
  int temp;

  temp = atol(atr_get(thing, atrname));
  atr_add(thing, atrname, tprintf("%ld", temp+increase));
}

void do_cpattr(OBJ *player, char *arg1, char *arg2)
{
  OBJ *source, *dest;
  ATTR *attr_source, *attr_dest;

  if(!(parse_attrib(player, arg1, &source, &attr_source)))
  {
    notify(player, "No match.");
    return;
  }

  if(!controls(player, source, POW_MODIFY))
  {
    notify(player, perm_denied());
    return;
  }

  if(!(parse_attrib(player, arg2, &dest, &attr_dest)))
  {
    notify(player, "No match.");
    return;
  }

  if(!controls(player, dest, POW_MODIFY))
  {
    notify(player, perm_denied());
    return;
  }

  atr_add_a(dest, attr_dest, atr_get_a(source, attr_source));

  notify(player, "Copied.");
}