musicmud-2.1.6/data/
musicmud-2.1.6/data/help/
musicmud-2.1.6/data/policy/
musicmud-2.1.6/data/wild/
musicmud-2.1.6/data/world/
musicmud-2.1.6/doc/
musicmud-2.1.6/src/ident/
musicmud-2.1.6/src/lua/
musicmud-2.1.6/src/lua/include/
musicmud-2.1.6/src/lua/src/lib/
musicmud-2.1.6/src/lua/src/lua/
musicmud-2.1.6/src/lua/src/luac/
/* 
 * MusicMUD Daemon, version 1.0
 * Copyright (C) 1998-2003 Abigail Brady, others
 * 
 * This program 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.
 * 
 * This program 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; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 * 
 */
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <sys/time.h>
#include <unistd.h>

#include <string>
#include <set>
#include <deque>

#include "vsprintf.h"
#include "musicmud.h"
#include "verbs.h"
#include "misc.h"
#include "MudObject.h"
#include "Interpret.h"
#include "log.h"
#include "flagnames.h"
#include "pflags.h"
#include "pflagnames.h"
#include "util.h"
#include "Mission.h"

#include "musicmud.h"
#include "misc.h"
#include "util.h"
#include "rooms.h"
#include "Player.h"
#include "events.h"
#include "trap.h"
#include "pflags.h"
#include "death.h"
#include "colour.h"
#include "musictok.h"

void MudObject::set_mission(Mission *m) {
  if (mission)
    mission->remove(this);
  mission = m;
  if (mission)
    mission->add(this);
}

static void convert(FILE *f, const char *string) {
    if (!strchr(string, '\\') && !strchr(string, '"'))
	fputs(string, f);
    else
	while (*string) {
	    if (*string == '\\') fputs("\\\\", f);
	    else if (*string == '"') fputs("\\\"", f);
	    else fputc(*string, f);
	    string++;
	}
}


Flag find_flag(const char *n) {
  if (strcasecmp(n, "Color")==0)
    return FL_COLOUR;
  for (Flag k=FL_FIRST;k<FL_MAX;k++) {
    if (strcasecmp(n, flag_names[k])==0) return k;
  }
  return FL_NONE;
}

PFlag find_priv(const char *n) {
  if (strncasecmp(n, "PFL_", 4)==0)
    n += 4;
  for (int k=0;k<PFL_MAX;k++) {
    if (strcasecmp(n, priv_names[k])==0) 
      return PFlag(k);
  }
  return PFL_NONE;
}


MudObject::MudObject(const char *_id): Object(_id), of(0), 
    zone(0), mission(0), next_time(now), wander_time(now),
  rant_time(now), follows(0), ilc(0), 
    reftime(now), children(new World<MudObject>()), owner(0), players_here(0)
    {
      l.exit = 0;
      l.s = 0;
};


void MudObject::ref() {
    reftime = now;
}

MudObject::~MudObject() {
    if (follows) {
      follow(0);
    }
    if (followers.getsize()) {
      MudObject *o;
      int i;
      foreach((&followers), o, i) {
	o->follow(0);
	i--;
      }
    }
    if (snooping.getsize()) {
      MudObject *o;
      int i;
      foreach((&snooping), o, i) {
	desnoop(o);
	i--;
      }
    }
    if (snoopers.getsize()) {
      MudObject *o;
      int i;
      foreach((&snoopers), o, i) {
	o->desnoop(this);
	i--;
      }
    }

    if (tracing.getsize()) {
      MudObject *o;
      int i;
      foreach((&tracing), o, i) {
	detrace(o);
	i--;
      }
    }
    if (tracers.getsize()) {
      MudObject *o;
      int i;
      foreach((&tracers), o, i) {
	o->detrace(this);
	i--;
      }
    }

    set_mission(0);
    MudObject *o;
    int i;
    foreach(children, o, i) {
        children->remove(*o);
	if (owner) {
	  owner->children->add(*o);
	  o->owner = owner;
	} else {
	  set_owner(o, "@musicmud");
	}
	i--;
    }
    delete children;
    if (owner) {
	owner->children->remove(*this);
    }
    if (zone) {
      set("zone", (const char *)0);
    }
    q_remove();
}

void MudObject::reset() {
    if (get_flag(FL_DESTROYONRESET)) {
      set_flag(FL_SILENTQUIT, 1);
      if (children->getsize()) {
	MudObject *o;
	int i;
	foreach(children, o, i)
	  set_owner(o, owner);
      }
      set_owner(this, "@musicud");
      nuke_me = 1;
      return;
    }

    flags = resetflags;
    q_update();

    set_bflag(FL_TIMER, 0);
    {
      strit i = strs.begin();
      while (i != strs.end()) {
	if (i->first[0]=='!') {
	  unset(i->first.c_str());
	  i = strs.begin();
	}
	else
	  i++;
      }
    }
    {
      intit i = ints.begin();
      while (i != ints.end()) {
	if (i->first[0]=='!') {
	  unset(i->first.c_str());
	  i = ints.begin();
	} else
	  i++;
      }
    }
    if (!is_player(this)) {
	if (MudObject*s=get_object("start"))
	  if (s != owner) { 
	    set_owner(this, s);
	  }
	if (get_int("initstrength")!=-1) set(KEY_STRENGTH, get_int("initstrength"));
	else if (get_int("maxstrength")!=-1) set(KEY_STRENGTH, get_int("maxstrength"));
    }
    if (get("wornby.start")) set(KEY_WORNBY, get("wornby.start"));
    if (get("wield.start")) set(KEY_WIELD, get("wield.start"));
    if (get("killedby")) unset("killedby");

    if (const char *ss=get("siton.start")) {
      set(KEY_SITON, ss);
    }

    unset("_fighting");

    set(KEY_STATE, get_int("initstate", 0));

    if (get("$keycode.sofar")) set("$keycode.sofar", "");

    if (follows) {
      interpret("leave");
    }

    if (get_int("maxenergy")>0) 
      set("!energy", get_int("maxenergy"));

    set_flag(FL_DONE, 0);

    set("$flag", get("initflag"));
    
    if (MudObject *ac=get_object(KEY_ACCEPTER)) {
      ac->unset("mission");
    }
    unset(KEY_ACCEPTER);

    if (get_flag(FL_STARTPLAN) && get("plan"))
      {
	set("!plan", get("plan"));
	set("!when", 1);
	set("!what", "");
	set_flag(FL_TIMER, 1);
      }

    if (get_int("initdeck")==1) {
      for (int i=0;i<52;i++) {
	array_set("$card", i, i);
      }
      set("$card.count", 52);
    } else {
      unset("$card.count");
    }

    int c=array_size("shop");
    for(int i=0;i<c;i++) {
      if (int r=array_get_int("shop", i, "istock")) {
	if (r != -1) {
	  array_set("$stock", i, r);
	}
      }
    }

    if (MudObject*sub=get_object("fullof")) {
      array_set("$fill", 0, sub->id);
      array_set("$fillamt", 0, get_int("volume", 0));
      set("$fill.count", 1);
      set("$fillamt.count", 1);
    } else {
      unset("$fill.count");
      unset("$fillamt.count");
      unset("$fill.0");
      unset("$fillamt.0");
    }

    dotrap(E_ONRESET, this, this);
    /* ::: reset o1==object being reset. */
}

void MudObject::send_data() {
}

bool MudObject::spewfile(const char *, const char *, bool, const char *) {
  return 0;
}

MudObject *qui = 0;
const char *current_command;
Verb *quiverb;

bool MudObject::interpretf(const char *format, PRINT_PARMS) 
{
  string buffer = formatprint(this, format, GET_PARMS());
  bool b = interpret(buffer.c_str());
  return b;
}

void MudObject::holo_clone(const MudObject *whatof, const char *prefix) {
  clone(whatof);

  cstrit i = whatof->strs.begin();
  while (i != whatof->strs.end()) {

    if (strncmp(i->first.c_str(), "disc.", 5)==0) {
      i++; continue;       
    }

    if (i->first == "wornfrom") {
      i++; continue;
    }

    if (MudObject *o=planet->get(i->second.c_str()))
      if (!streq(o->get("zone"), "template")) {

      string nstr = "";

      const char * nval = i->second.c_str();
      if (nval[0]==':') {
	nstr = ":";
	nstr += prefix;
	nstr += "_";
	nstr += nval + 1;
      } else {
	nstr = prefix;
	nstr += "_";
	nstr += nval;
      }

      set(i->first, nstr);

    }

    i++;
  }
}

bool MudObject::interpret(const char *string) {
  std::string la;

  if (!string || !*string) return 0;
  
  while (*string==' ') string++;
  
  const char *oldcurrent_command = current_command;
  Verb *oldverb = quiverb;
  
  current_command = string;
  MudObject *oldwho = qui;
  qui = this;
  quiverb = 0;
  
  std::deque<std::string> what;
  
  std::string s = string;
  int argc = 0;
  int sofar = 0;
  Verb *verb = 0;
  while (1) {
    int sp = s.find(' ');
    if (sp == -1)
      break;
    
    if (sp || (verb && (verb->vflags & VFL_MAGICSPACE))) {
      what.push_back(s.substr(0, sp));
      argc++;
    }
    
    if (!verb && argc) {
      verb = get_verb(what[0].c_str());
    }
    
    sofar = sp+1;
    s = s.substr(sofar);
  }
  
  if (s.length() && ((s[0]!=' ') || verb && (verb->vflags & VFL_MAGICSPACE))) {
    what.push_back(s);
    argc++;
  }
  
  int success = 0;
  
  if (what.size()==0) {
    current_command = oldcurrent_command;
    qui = oldwho;
    quiverb = oldverb;
    return 0;
  }

  if (const char *al=get(ssprintf("alias.%s", what[0].c_str()).c_str())) {
    what.pop_front();
    std::deque<std::string> v;

    StrTok tok(al);
    while (const char *txt=tok.next(" ")) {
      if (streq(txt, "$*")) {
	std::deque<std::string>::iterator i = what.begin();
	while (i != what.end()) {
	  v.push_back(*i);
	  i++;
	}
	what = std::deque<std::string>();
	continue;
      }

      v.push_back(txt);
    }

    std::deque<std::string>::iterator i = what.begin();
    while (i != what.end()) {
      v.push_back(*i);
      i++;
    }

    what = v;

    argc = what.size();
    std::string s;
    for (int i=0;i<argc;i++) {
      if (i)
	s += " ";
      s += what[i];
    }
    printf("After aliasing, expands to: %s\2^n\n", s.c_str());
  }

    verb = get_verb(what[0].c_str());
    if (verb) 
      what[0] = verb->id;
    
    const char *argv[argc+1];
    
    for (int c=0;c<argc;c++) {
      argv[c] = what[c].c_str();
    }
    argv[argc] = 0;

    if (verb) {
      if (!owner && !(verb->vflags & VFL_OKNOOWNER)) {
	printf("You don't have an owner atm, so can't do that.\n");
	success = 1;
      } else if (verb->disabled) {
	printf("%#s is temporarily disabled.\n", verb->id);
	success = 1;
      } else if (verb->has_privs(this) || this->ilc) {
	quiverb = verb;
	verb->invoke(this, argc, argv);
	success = 1;
      } else if (verb->pflag == PFL_AWAKE) {
	printf("You toss and turn in your sleep.\n");
	oprintf(cansee, "%#M tosses and turns in %s sleep.\n", this, his_or_her(this));
	success = 1;
      } else if (!(verb->vflags & VFL_DENYEXISTS)) {
	printf("You can't do that : %s\n", argv[0]);
	success = 1;
      }
    } else {
      int i2;
      Interpreter *in;
      foreach(interpreters, in, i2) {
	int value = in->invoke(this, string, argc, argv);
	if (value == 0 || value == 1) {
	  success = 1;
	  break;
	}
      }
    }
  
  if (!success) {
    printf("What do you mean by \"%s\"?\n", argv[0]);
  }
  
  current_command = oldcurrent_command;
  qui = oldwho;
  quiverb = oldverb;
  return 0;
}

bool MudObject::cancel_printf() {
  return 1;
}

void MudObject::real_printf(const char *f, const PARMS &p, MudObject *target, int snoop) {
  if (!target)
    target = this;

  if (!snoop) {
    MudObject *o;
    int i;
    foreach((&snoopers), o, i) {
      string fm = "^R*^n";
      fm += f;
      o->real_printf(fm.c_str(), p, target, 1);
    }
  }

  if (of) {
    string temp = formatprint(target, f, p);
    fprintf(of, "%s", temp.c_str());
    return;
  }
}

void MudObject::printf(const char *fmt, PRINT_PARMS) {
  real_printf(fmt, GET_PARMS());
}

void MudObject::spec_printf(const char *fmt, PRINT_PARMS) {
  real_spec_printf(fmt, GET_PARMS());
}


void MudObject::real_spec_printf(const char *fmt, const PARMS &) {
}

void MudObject::aprintf(const char *fmt, PRINT_PARMS) {
  return real_aprintf(always, fmt, GET_PARMS(), this);
}


void MudObject::real_aprintf(const showto &f, const char * a, const PARMS &p, MudObject *target) {
  MudObject *o;
  int i;
  foreach(children, o, i) {
    o->real_aprintf(f, a, p, target);
  }
  if (f(this))
    real_printf(a, p, target);
}

void MudObject::lprintf(const showto &o, const char *fmt, PRINT_PARMS) {
  if (!owner) return;
  
  PARMS p = GET_PARMS();

  if (owner->get_flag(FL_LINKED)) {
    int i;
    MudObject *obj;
    foreach(owner->children, obj, i) {
      MudObject *dest = linkedlink(obj);
      if (dest && dest != owner) {
	dest->real_aprintf(o, fmt, p, 0);
      }
    }
  }
}

void MudObject::oprintf(const showto &f, const char *fmt, PRINT_PARMS) {
  if (!owner)
    return;

  PARMS p = GET_PARMS();

  MudObject *o;
  int i;  

  foreach(owner->children, o, i)
    if (o != this &&
	(!is_player(o) || o->get_flag(FL_LOGGEDIN)) && f(o))
      o->real_printf(fmt, p, 0);
}

void MudObject::oprintf(const char *fmt, PRINT_PARMS) {
  oprintf(always, fmt, PRINT_PASS_PARMS);
}

void MudObject::action_to(MudObject *from, const char *fmt, const char *t, MudObject *prop) {
  if (from && !filter(from)(this))
    return;
  string buffer = sprinta(this, fmt, this, from, t, 2, prop);
  if (buffer.length()==0)
    return;
  printf("%s\n", buffer.c_str());
}

void MudObject::action_from(MudObject *from, const char *fmt, const char *t, MudObject *second, MudObject *prop) {
  if (!is_player(this) && !is_mobile(this) && !snoopers.getsize()) return;
  if (from && !filter(from)(this))
    return;
  string buffer = sprinta(this, fmt, from, second ? second : this, t, 2, prop);
  if (buffer.length()==0)
    return;
  printf("%s\n", buffer.c_str());
}

MudObject *linkedlink(MudObject *ext) {
  if (!ext->owner->get_flag(FL_LINKED))
    return 0;
  if (MudObject *door=ext->get_object("door")) {
    if (state(door) && !door->get_flag(FL_TRANSPARENT))
      return 0;
  }
  MudObject *dest = ext->get_object("link");
  if (!dest)
    return 0;
  if (dest==ext->owner)
    return 0;
  if (dest->get_flag(FL_LINKED))
    return dest;
  return 0;
}

void MudObject::action(MudObject *avoid, const char *fmt, const char *t, MudObject *prop) {
  MudObject *o; int i;
  foreach(owner->children, o, i) {
    if (o!=avoid && o != this)
      o->action_from(this, fmt, t, avoid, prop);

    MudObject *ll = linkedlink(o);
    if (ll && ll != this->owner) {
      MudObject *m;
      int j;
      foreach(ll->children, m, j) if (m != avoid && m != this) {
	m->action_from(this, fmt, t, avoid, prop);
      }
    }
  }
}

void MudObject::action(const showto &s, MudObject *target, const char *fmt, const char *t, MudObject *prop) {
  MudObject *o; int i;
  foreach(owner->children, o, i) {
    if (o != target && o != this && s(o))
      o->action_from(this, fmt, t, target, prop);

    MudObject *ll = linkedlink(o);
    if (ll && ll != this->owner) {
      MudObject *m;
      int j;
      foreach(ll->children, m, j) if (m != target && m != this && s(o)) {
	m->action_from(this, fmt, t, target, prop);
      }
    }
  }
}

void MudObject::set(const char *key, const char *value) {
  if (streq(key, "id")) {
    bool plan = (planet->get(id)) == this;
    if (plan) planet->remove(this);    
    Object::set(key, value);
    if (plan) planet->add(this);
    return;
  }

    if (streq(key, "owner")) {
      MudObject *dest = planet->get(value);
      if (dest && is_in(dest, this)) {
	log(PFL_SEEINFO, 0, "debug", "attempt at moving %s into %s", id, dest->id);
	return;
      }

      if (!dest && this != mud)
	dest = mud;

	if (owner && owner->children) {
	  owner->children->remove(*this);
	  if (is_player(this))
	    owner->players_here--;
	}
	if (owner) owner->refcount--;
	owner = dest;
	if (owner) owner->refcount++;
	if (owner && owner->children) {
	  owner->children->add(*this);
	  if (is_player(this)) 
	    owner->players_here++;
	}
	return;
    }
    if (streq(key, "zone")) {
      if (zone && zone->children) zone->children->remove(*this);
      if (zone) zone->refcount--;
      if (zone && !zone->refcount) {
	zones->remove(*zone);
	delete zone;
      }
      if (value) {
        zone = zones->get(value);
        if (!zone) {
   	  zone = new MudObject(value);
	  zones->add(*zone);
        }
        if (zone) zone->refcount++;
        if (zone && zone->children) zone->children->add(*this);
      } else
	zone = 0; 
    }
    Object::set(key, value);
}

void MudObject::save_difference(FILE *f, const MudObject *ofwhat) const
{
  {
    cstrit i = strs.begin();
    while (i != strs.end()) {
      if (i->first[0] != '!' && !(streq(i->second.c_str(), ofwhat->get(i->first.c_str())))) {
	fprintf(f, "string %s \"", i->first.c_str());
	convert(f, i->second.c_str());
	fprintf(f, "\"\n"); 
      }
      i++;
    }  
  }

  {
    cintit i = ints.begin();
    while (i != ints.end()) {
      if (i->first[0] != '!' && (i->second != ofwhat->get_int(i->first.c_str()))) {
	fprintf(f, "int %s %i\n", i->first.c_str(), i->second);
      }
      i++;
    }  
  }
  
}

const char *MudObject::get(const char *key) const {
    if (strcmp(key, "owner")==0) 
	if (owner) 
	    return owner->id;
    else
	return 0;
    else return Object::get(key);
}

MudObject *find_questob(const char *name) 
{
  int l = strlen(name);
  if (l < 2)
    return 0;
  extern set<MudObject*> s_quests;
  for (set<MudObject*>::iterator i=s_quests.begin();i!=s_quests.end();i++) {
    MudObject *q = *i;
    if (q->get("mname") && strncasecmp(q->get("mname"), name, l)==0)
      return q;
  }
  return NULL;
}


class autofree {
  void *v;
public:
  autofree(void *v) : v(v) { }
  ~autofree() { free(v); }
};

void priv_load(bitset<512> &s, const char *str, char *buffer) {
  if (strncmp(buffer, str, strlen(str))==0) {
    char *a = strtok(buffer+strlen(str), " ");
    while (a) {
      PFlag i = find_priv(a);
      if (i!=PFL_NONE)
	s[i] = 1;
      a = strtok(0, " ");
    }
  }
}

void priv_save(const bitset<512> &s, const char *str, FILE *f)
{
  bool j = false;
  for (int p=2;p<PFL_MAX;p++) {
    if (s[p]) {
      if (!j) {
	fprintf(f, str);
	j = true;
      }
      fprintf(f, " %s", priv_names[p]);
    }
  }
  if (j) fprintf(f, "\n");
}

void MudObject::load(const char *buf) {
  
  char *buffer = strdup(buf);
  autofree af(buffer);

    if (*buffer=='\t') buffer++;
    
    if (strncmp(buffer, "string ", 7)==0) {
	char *pname = buffer + 7;
	char *pvalue = strchr(buffer, '"');
	if (!pvalue) {
	    log(PFL_SEEINFO, 0, "zoneload", "error in zone file");
	  return;
	}
	
	*pvalue = 0;
	pvalue++;
	pvalue[strlen(pvalue)-1]=0;
	if (strchr(pname, ' '))
	    *strchr(pname, ' ')=0;

	if (strncmp(pname, "eq.", 3)==0) return;
	if (strncmp(pname, "q.", 2)==0) return;

	if (streq(pname, "wield")) 
	  pname = "$wield";

	if (*pname != '_') {
	  if (streq(pname, "owner") && !this->owner) 
	    set("!owner", pvalue);
	  else
	    this->set(pname, pvalue);
	}
    }
    if (strncmp(buffer, "int ", 4)==0) {
	char *pname = buffer + 4;

	char *pvalue = strchr(pname, ' ');
	*pvalue = 0;
	pvalue++;

	if (strncmp(pname, "eq.", 3)==0) return;
	if (strncmp(pname, "q.", 2)==0) return;
	if (strncmp(pname, "quest_id", 8)==0) return;
	
	if (streq(pname, "state"))
	  this->set(KEY_STATE, atoi(pvalue));
	else if (streq(pname, "initstate")) {
	  int v = atoi(pvalue);
	  if (v != -1)
	    this->set(pname, v);
	}
	else if (*pname != '_' && (strcmp(pname, "noreset")!=0)) {
	  if (streq(pname, "rantcount"))
	    pname = "rant.count";

	  if (streq(pname, "balance"))
	    pname = "$balance";

	  if (streq(pname, "cash"))
	    pname = "$cash";

	  if (streq(pname, "armor"))
	    pname = "armour";

	    this->set(pname, atoi(pvalue));
	}
    }

    if (strncmp(buffer, "flags ", 6)==0) {
	char *a = strtok(buffer+6, " ");
	while (a) {
		Flag j = find_flag(a);
		if (j!=-1) {
		    set_flag(j, 1);
		    set_rflag(j, 1);
		}
	    a = strtok(0, " ");
	}
    }

    if (strncmp(buffer, "privs ", 6)==0) {
	char *a = strtok(buffer+6, " ");
	while (a) {
          if (!is_player(this)) {
            PFlag pf = find_priv(a);
            if (pf != PFL_NONE)
              granted[pf] = 1;
          }
	  a = strtok(0, " ");
	}
    }

    if (is_player(this) && strncmp(buffer, "quest ", 6)==0) {
	char *a = strtok(buffer+6, " ");
	while (a) {
	    quest_set(this, a);
	    a = strtok(0, " ");
	}
    }

    priv_load(withheld, "withheld ", buffer);
    priv_load(granted, "granted ", buffer);
    priv_load(abeyed, "abeyance ", buffer);

    return;
}

void MudObject::setf(const char*key, const char *format, PRINT_PARMS) {
  set(key, formatprint(this, format, GET_PARMS()));
}

MudObject *MudObject::get_object(const char *a) const {
  if (!a) return 0;
  const char *v = get(a);
  if (!v) return 0;
  return planet->get(v);
}

int MudObject::array_size(const char *aname) const
{
  string n = aname;
  n += ".count";
  return get_int(n.c_str(), 0);
}

const char *MudObject::array_get(const char *aname, int index)  const
{
  char n[1024];
  sprintf(n, "%s.%i", aname, index);
  return get(n);
}


MudObject *MudObject::array_get_object(const char *aname, int index) const
{
  char n[1024];
  sprintf(n, "%s.%i", aname, index);
  return get_object(n);
}

const char *MudObject::array_get(const char *aname, int index, const char *prop) const
{
  char n[1024];
  sprintf(n, "%s.%i.%s", aname, index, prop);
  return get(n);
}

MudObject *MudObject::array_get_object(const char *aname, int index, const char *prop) const
{
  char n[1024];
  sprintf(n, "%s.%i.%s", aname, index, prop);
  return get_object(n);
}

int MudObject::array_get_int(const char *aname, int index, int def)  const
{
  char n[1024];
  sprintf(n, "%s.%i", aname, index);
  return get_int(n, def);
}

int MudObject::array_get_int(const char *aname, int index, const char *prop, int def)  const
{
  char n[1024];
  sprintf(n, "%s.%i.%s", aname, index, prop);
  return get_int(n, def);
}

void MudObject::array_set(const char *aname, int index, MudObject *what) 
{
  char n[1024];
  sprintf(n, "%s.%i", aname, index);
  int size = array_size(aname);
  if ((index+1)>size) {
    size = index + 1;
  }
  if (what) {
    set(n, what->id);
    sprintf(n, "%s.count", aname);
    set(n, size);
  } else {
    unset(n);
  }
}

void MudObject::array_unset(const char *aname, int index, const char *prop) 
{
  char n[1024];
  sprintf(n, "%s.%i.%s", aname, index, prop);
  unset(n);
}

void MudObject::array_unset(const char *aname, int index) 
{
  char n[1024];
  sprintf(n, "%s.%i", aname, index);
  unset(n);
}

void MudObject::array_set(const char *aname, int index, const char *prop, int val) 
{
  char n[1024];
  sprintf(n, "%s.%i.%s", aname, index, prop);
  set(n, val);
}

void MudObject::array_set(const char *aname, int index, const char *prop, const char *val) 
{
  char n[1024];
  sprintf(n, "%s.%i.%s", aname, index, prop);
  set(n, val);
}

void MudObject::array_set(const char *aname, int index, int what) 
{
  char n[1024];
  sprintf(n, "%s.%i", aname, index);
  int size = array_size(aname);
  if ((index+1)>size) {
    size = index + 1;
  }

  set(n, what);
  sprintf(n, "%s.count", aname);
  set(n, size);
}


void MudObject::array_set(const char *aname, int index, const char *what) 
{
  char n[1024];
  sprintf(n, "%s.%i", aname, index);
  int size = array_size(aname);
  if ((index+1)>size) {
    size = index + 1;
  }

  set(n, what);
  sprintf(n, "%s.count", aname);
  set(n, size);
}

void MudObject::save(FILE *f, bool include_var) const {
    if (get_flag(FL_DESTROYONRESET)) return;
    if (get_flag(FL_NOSAVE)) return;
    if (id[0] == '@') return;    

    fprintf(f, "mudobject \"%s\" {\n", id);
    
    bool j = false;
    for (Flag p=FL_FIRST;p<FL_MAX;p++) {
      	if (p == FL_TIMER || p == FL_OBSERVED)
		continue;

	if (is_player(this)?get_flag(p):get_rflag(p)) {
	    if (!j) {
		fprintf(f, "flags");
		j = true;
	    }
	    fprintf(f, " %s", flag_names[p]);
	}
    }
    if (j) fprintf(f, "\n");

    priv_save(withheld, "withheld", f);
    priv_save(abeyed, "abeyed", f);

    if (is_player(this))
      priv_save(granted, "granted", f);
    else
      priv_save(granted, "privs", f);

    j = false;
    for (std::set<string>::iterator q=quests.begin();q!=quests.end();q++) {
      if (!j) {
	fprintf(f, "quest");
	j = 1;
      }
      fprintf(f, " %s", q->c_str());
    }
    if (j) fprintf(f, "\n");

    if (owner)
           if (const char *s = get("start"))
    	  fprintf(f, "string owner \"%s\"\n", s);
            else
    	  fprintf(f, "string owner \"%s\"\n", owner->id);
    

  {
    cstrit i = strs.begin();
    while (i != strs.end()) {
      if (i->first[0] != '!' && (include_var || i->first[0] != '$')) {
	if (!strchr(i->first.c_str(), '"')) {
	  fprintf(f, "string %s \"", i->first.c_str());
	  convert(f, i->second.c_str());
	  fprintf(f, "\"\n"); 
	}
      }
      i++;
    }  
  }

  {
    cintit i = ints.begin();
    while (i != ints.end()) {
      if (i->first[0] != '!' && (include_var || i->first[0] != '$')) {
	if (!strchr(i->first.c_str(), '"')) {
	  fprintf(f, "int %s %i\n", i->first.c_str(), i->second);
	}
      }
      i++;
    }  
  }
    
    fprintf(f, "}\n");
}


void MudObject::set(const char *a, int b) {
  Object::set(a, b);
}


void MudObject::clone(const MudObject *whatof) {
  flags = whatof->flags;
  resetflags = whatof->resetflags;
  withheld = whatof->withheld;
  granted = whatof->granted;

  ints = whatof->ints;
  strs = whatof->strs;
  cstrit i = strs.begin();
  while (i != strs.end()) {
    if (strncmp(i->first.c_str(), "lua.", 4)==0) {
      unset(i->first.c_str());
      i = strs.begin();
    }
    else
      i++;
  }
}

void MudObject::save_var(FILE *f) const
{
  if (get_flag(FL_DESTROYONRESET)) return;
  if (get_flag(FL_NOSAVE)) return;

  int y = 0;

  cstrit i = strs.begin();
  while (i != strs.end()) {
    if (i->first[0] == '$') {
      if (strchr(i->first.c_str(), '"'))
	continue;

      if (!y)
	  fprintf(f, "vardata \"%s\" {\n", id);
      y++;

      fprintf(f, "string %s \"", i->first.c_str());
      convert(f, i->second.c_str());
      fprintf(f, "\"\n"); 

      
    }
    i++;
  }

  {
    cintit i = ints.begin();
    while (i != ints.end()) {
      if (i->first[0] == '$')  {
	
	if (strchr(i->first.c_str(), '"'))
	  continue;

	if (!y)
	  fprintf(f, "vardata \"%s\" {\n", id);
	y++;


	fprintf(f, "int %s %i\n", i->first.c_str(), i->second);
      }
      i++;
    }  
  }

  if (y) {
    fprintf(f, "}\n");
  }
}

set<MudObject*> s_quests;

void MudObject::q_update() {
  if (get_flag(FL_QUEST))
    s_quests.insert(this);
  else
    s_quests.erase(this);
}

void MudObject::q_remove() {
  if (get_flag(FL_QUEST))
    s_quests.erase(this);
}

void MudObject::set_flag(Flag what, bool value) {
  flags[what] = value;
  q_update();
}

bool MudObject::get_flag(Flag which) const {
  return flags[which];
}

void MudObject::set_rflag(Flag what, bool value) {
  resetflags[what] = value;
}

bool MudObject::get_rflag(Flag which) const {
  return resetflags[which];
}

struct {
    int level;
    PFlag priv;
} priv_things[] = {
	{ 1,           PFL_MAIL        },
	{ 1,           PFL_BECOME      },
	{ 1,           PFL_EMOTE },
	{ 4,           PFL_BOARD       }, 
	{ 7,           PFL_ABERCHAT    }, 
	{ 7,           PFL_TITLE       },

        { LEV_COMMANDER ,  PFL_GOTO        },
	{ LEV_COMMANDER ,  PFL_WHERE       },
        { LEV_COMMANDER ,  PFL_REMORT      },
	{ LEV_COMMANDER, PFL_SEEBUGS     },

        { LEV_CAPTAIN   ,  PFL_INVIS       },
        { LEV_CAPTAIN   ,  PFL_NOHASSLE    },
        { LEV_CAPTAIN   ,  PFL_SEESTATS    },
        { LEV_CAPTAIN   ,  PFL_SETIN       },

	{ LEV_CAPTAIN,  PFL_BOOT        },
	{ LEV_CAPTAIN,  PFL_ECHO        },
	{ LEV_CAPTAIN,  PFL_HEAL        },
	{ LEV_CAPTAIN,  PFL_IMMORTAL    },
	{ LEV_CAPTAIN,  PFL_MAKE        },
	{ LEV_CAPTAIN,  PFL_RESET       },
	{ LEV_CAPTAIN,  PFL_SEEINFO     },
	{ LEV_CAPTAIN,  PFL_START       },
	{ LEV_CAPTAIN,  PFL_STATUS      },
	{ LEV_CAPTAIN,  PFL_ROOM        },
	
	{ LEV_CAPTAIN, PFL_ACTIONS     },
	{ LEV_CAPTAIN, PFL_DETAIL      },
	{ LEV_CAPTAIN, PFL_ZAP         },
	{ LEV_CAPTAIN, PFL_BEAM        },
	{ LEV_CAPTAIN, PFL_ERASEOTHERS },
	{ LEV_CAPTAIN, PFL_MAKEFILE    },
	{ LEV_CAPTAIN, PFL_MAKEINFO    },
	{ LEV_CAPTAIN, PFL_MAKEHELP    },
	{ LEV_CAPTAIN, PFL_ERASEFILE   },
	{ LEV_CAPTAIN, PFL_ERASEINFO   },
	{ LEV_CAPTAIN, PFL_ERASEHELP   },
	{ LEV_CAPTAIN, PFL_ZONES       },
        { LEV_CAPTAIN, PFL_TRACE       },
	{ LEV_CAPTAIN, PFL_CLONE       },
	{ LEV_CAPTAIN, PFL_SEELUASPAM },

	{ LEV_COMMODORE, PFL_BAN         },  
	{ LEV_COMMODORE, PFL_FORCE       },
	{ LEV_COMMODORE, PFL_REMORTANYWHERE },

	{ LEV_ADMIRAL,   PFL_CANAKICK    },
	{ LEV_ADMIRAL,   PFL_CHQUEST     },
	{ LEV_COMMODORE, PFL_FROB        },
	{ LEV_CAPTAIN,   PFL_HOSTS       },
	{ LEV_CAPTAIN,   PFL_EDITALL	},
        { LEV_COMMANDER, PFL_MINIMISSIONS },
		
	{ LEV_COMMODORE, PFL_SHUTDOWN    },
	{ LEV_COMMODORE, PFL_CODER       },
	
	{ LEV_ADMIRAL,     PFL_MAKEPOLICY  },
	{ LEV_ADMIRAL,     PFL_ERASEPOLICY },
	{ LEV_COMMODORE,     PFL_SNOOP       },
	
	{ LEV_ADMIRAL,     PFL_GOD         },  

	{ 0, PFL_NONE },
};

bool MudObject::get_dpriv(PFlag which) const {
  for (int i=0;priv_things[i].level;i++)
    if (priv_things[i].priv == which)
      return privs_of(this)>=priv_things[i].level;

  return 0;
}

void MudObject::set_apriv(PFlag which, int i) {
  abeyed[which] = i;
}

void MudObject::set_gpriv(PFlag which, int i) {
  granted[which] = i;
}

void MudObject::set_wpriv(PFlag which, int i) {
  withheld[which] = i;
}

bool MudObject::get_wpriv(PFlag which) const {
  return withheld[which];
}

bool MudObject::get_apriv(PFlag which) const {
  return abeyed[which];
}

bool MudObject::get_gpriv(PFlag which) const {
  return granted[which];
}

bool MudObject::get_priv(PFlag which) const {
  if (withheld[which] || abeyed[which])
    return 0;

  if (granted[which] && (get_int("remort")==-1 || which==PFL_REMORTANYWHERE))
    return 1;
  
  // look up our level then return it
  for (int i=0;priv_things[i].level;i++) {
    if (priv_things[i].priv == which)
      return privs_of(this)>=priv_things[i].level;
  }

  return get_dpriv(which);
}

void MudObject::file_divert(FILE *f) {
  of = f;
}

void MudObject::file_undivert() {
  of = 0;
}

void MudObject::push_data() {
}