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/
#include "musicmud.h"
#include "levels.h"
#include "msi.h"
#include "nations.h"
#include "Socket.h"
#include "verbs.h"
#include "State.h"
#include "emsg.h"

#include <algorithm>

#define MODULE "who"

class orderer {
public:
  bool operator()(const Player *a, const Player *b) const {
    if (level_of(a) > level_of(b)) return 1;
    if (level_of(a) < level_of(b)) return 0;
    if (strcmp(a->id, b->id)<0)                  return 1;
    return 0;
  }
};

std::vector<Player*> players_on(MudObject *who=0, bool onlyon=true) {
  std::vector<Player*> l;
  iforeach(i, *players) {
    if (who && (who!=i && !visible_to(who, i))) 
      continue;

    if (!onlyon || i->get_flag(FL_LOGGEDIN))
      l.push_back(i);
  }
  std::sort(l.begin(), l.end(), orderer());
  return l;
}

static char object_gender(const MudObject *o) {
  const char *gender = o->get("gender");
  if (gender) return toupper(*gender);
  else return 'N';
}

static const char *g_string(char a)
{
  if (a == 'M')
    return "^O";
  if (a == 'F')
    return "^F";
  if (a == 'N')
    return "N";
  if (a == 'P')
    return "P";
  if (a == 'A')
    return "A";
  return "?";
}

static std::string getname(const Player *who) {
  return who->get("name");
}

static std::string getlevel(const Player *who)
{
  return ssprintf("%i", level_of(who));
}

static std::string getprivs(const Player *who)
{
  return ssprintf("%i", privs_of(who));
}

static std::string getmission(const Player *who)
{
  MudObject *m = who->get_object("mission");
  if (!m)
    return "-";
  if (m->owner != (MudObject *)who)
    return "-";
  if (m->get_flag(FL_QUEST) && m->get("mname"))
    return m->get("mname");
  if (m->get_flag(FL_MISSION) && m->get_object("instance")) {
    MudObject *i = m->get_object("instance");
    return ssprintf("%s mini", i->get("mname"));
  }
  return "-";
}

static std::string getinvis(const Player *who) {
  return ssprintf("%i", invis(who));
}

static std::string getnation(const Player *who) 
{
  return prettynation(nation(who));
}

static std::string getgender(const Player *who) {
  return g_string(object_gender(who));
}

static std::string getrank(const Player *who) {
  return get_rank(who);
}

static std::string getlocation(const Player *who) {
  return get_zoneprop(who->owner, "planet", "Somewhere");
}

static std::string getlocid(const Player *who) {
  return who->owner->id;
}

static std::string getlocname(const Player *who) {
  return who->owner->get("name")?:"Unknown";
}

time_t idle_time(const Player *who) {
  return now - who->get_idle();
}

static string format_itime(time_t t) {
    char thing[256];
    time_t seconds = t % 60;
    time_t minutes = t / 60;
    time_t hours = minutes / 60;
    minutes = minutes % 60;
	sprintf(thing, "%03i:%02i:%02i", (int)hours, (int)minutes, (int)seconds);
    return thing;
}

static string time_idle(const Player *o) {
    return format_itime(now - o->get_idle());
}

static string get_state(Player *o) {
    string thing = "";
    if (o->get("away")) thing += " ^G[^gAway^G]";
    if (linkdead(o)) thing += " ^Y[^gLinkdead^Y]";
    if (idle_time(o)>=(60*60)) thing += " ^R[^rIdle^R]";
    else if (idle_time(o)>=(60*15)) thing += " ^Y[^yIdle^Y]";
    else if (idle_time(o)>=(60*2)) thing += " ^G[^gIdle^G]";
    if (o->get_flag(FL_CODING)) thing += " ^C[^BCoding^C]";
    if (o->get_int("remort")!=-1) thing += " ^r[^RRemort^r]";
    if (o->get_flag(FL_SLEEPING)) thing += " ^W[^mAsleep^W]";
    const char *state = o->get_state()->id;
    if (state) {
      if (strstr(state, "make")) thing += " ^R[^YBuilding^R]";
      if (strstr(state, "mail")) thing += " ^R[^YMailing^R]";
      if (strstr(state, "board")) thing += " ^R[^YPosting^R]";
    }
    if (const char *p=o->get("$piggy")) {
      thing += ssprintf(" ^g[^G%#s^g]", p);
    }
    return thing;
}

static std::string gettitle(const Player *who) {
  return ssprintf("%s%s", object_title(who), get_state(const_cast<Player*>(who)));
}

static std::string getidle(const Player *who) {
  if (who->p)
    return ssprintf("^m%s^n", time_idle(who).c_str());
  else
    return ssprintf("^y%s^n", time_idle(who).c_str());
}

static std::string gethits(const Player *who) {
  if (who->get_priv(PFL_IMMORTAL))
    return "^-^-^-";
  else
    return ssprintf("^r%i^n", strength_of(who));
}

static std::string getarmour(const Player *who) {
  return ssprintf("%3i", parmour(const_cast<Player*>(who)) + 
		  player_armour(const_cast<Player*>(who)));
}

static std::string get6(const Player *who) {
  if (!who->p)
    return "-";
  return who->p->socket->is6()?"6":"4";
}

static std::string getnaws(const Player *who) {
  if (!who->p)
    return "-";
  const Player *p = who;
  if (p->p->row && p->p->col)
    return ssprintf("%ix%i", p->p->row, p->p->col);
  return "?x?";
}

static std::string getmxp(const Player *who) {
  if (!who->p)
    return "-";
  const Player *p = who;
  //  return p->p->mxp?ssprintf("MXP (%i)"):"";
  if (p->p->mxp) 
    if (p->p->mxp_version.length())
      return ssprintf("MXP : %s", p->p->mxp_version);
    else
      return "MXP";
  return "";
}

static std::string getterm(const Player *who) {
  if (!who->p)
    return "-";
  string t = who->p->term;
  if (t.length())
    return t;
  return "-";
}

static std::string getmccp(const Player *who) {
#ifndef NOCOMPRESS
  if (!who->p)
#endif
    return "-";
#ifndef NOCOMPRESS
  const Player *p = who;
  if (p->p->compress && p->p->uncbytes) {
    int pcnt = (p->p->combytes * 100) / p->p->uncbytes;
    return ssprintf("%i: %2i%%", p->p->will_compress==2?"v2":"v1", pcnt);
  }
  return "";
#endif
}

static std::string getstate(const Player *who) {
  return who->get_state()->id;
}

struct mypair {
  string match;
  string place;
};

list<mypair> localities;
int loc_loaded = 0;

static const char *locality(const Player *who) {
    if(!who->p) return "";
    string hs = who->p->get_hostname();
    const char *h = hs.c_str();

    if (!loc_loaded) {
      FILE *f = xopen(VARDATA, "places", "r");
      loc_loaded = 1;
      if (f) {
	while (1) {
	  string s = getline(f);
	  if (feof(f))
	    break;
	  if (s.find(' ')==string::npos)
	    continue;
	  
	  mypair a = { 
	    s.substr(0, s.find(' ')),
	    s.substr(s.find(' ')+1) };
	  localities.push_back(a);
	}
	
	xclose(f);
      }
      
    }

    list<mypair>::iterator i = localities.begin();
    while (i != localities.end()) {
      if (wcmatch(i->match.c_str(), h)) {
	return i->place.c_str();
      }
      i++;
    }

    return "";
}

static string hostuser(const Player *p, int ip)
{
  string h;
  if(p->p)
	  h=ip?p->p->get_ip():p->p->get_hostname();
  else
	  h="(linkdead)";
  if (!p->get("_username"))
  {
    return h;
  }

  string out = p->get("_username");
  out += "@";
  out += h;
  return out;
}

static string gethost(const Player *p) 
{
  if (!p->p)
    return "-";
  return hostuser(p, 0);
}

static string getip(const Player *p) 
{
  if (!p->p)
    return "-";
  return hostuser(p, 1);
}

static string getworld(const Player *p) 
{
  if (!p->p)
    return "-";
  return locality(p);
}

static string getfd(const Player *p) 
{
  if (!p->p)
    return "-";
  return ssprintf("%i", p->p->socket->getfd());
}

static string getstance(const Player *p)
{
  if (MudObject *f=p->get_object("_fighting")) {
    return ssprintf("%|fighting %P", p, f);
  }
  if (MudObject *m=mount(const_cast<Player*>(p))) {
    return ssprintf("%|%s %P", p, m->get("riding_verb")?:"riding", m);
  }

  if (p->get_flag(FL_SLEEPING))
    return "sleeping";

  if (p->get_flag(FL_SITTING))
    return "sitting";

  if (p->get_flag(FL_SWIMMING))
    return "swimming";

  return "standing";
}

static string getclothes(const Player *who)
{
  NewWorld cl = clothes(const_cast<Player*>(who));
  return ssprintf("%w", cl);
}

static string getconnected(const Player *who)
{
  return format_itime(now - who->on_since);
}

static string gettimeon(const Player *p)
{
  long sadness = p->get_int("timeon", 0) + (now - p->time_since);
  return ssprintf("%3i %02i:%02i:%02i", 
		  (sadness / 3600) / 24,
		  (sadness / 3600) % 24,
		  (sadness / 60) % 60,
		  sadness % 60);
}

static string getaway(const Player *p)
{
  const char *a = p->get("away");
  if (a)
    if (streq(a, "."))
      return ssprintf("Away");
    else
      return ssprintf("Away : %s", a);

  return "";
}

struct col {
  char code;
  string name;
  std::string (*fn)(const Player*);
  PFlag priv;
  int wid;
  string post;
  string pre;
  bool right;
  int pad;
};

col possibles[] = {
  { 'n', "Name",          getname },
  { 'r', "Rank",          getrank },
  { 'e', "Rank",          getlevel,   PFL_SEESTATS },
  { 'E', "Rank",          getprivs,   PFL_SEESTATS },
  { 'v', "Inv",           getinvis,   PFL_SEESTATS },
  { 'N', "Nation",        getnation },
  { 't', "Title",         gettitle },
  { 'l', "Location",      getlocation },
  { 'L', "Location",      getlocid,   PFL_SEESTATS },
  { 'R', "Location Name", getlocname, PFL_SEESTATS },
  { 'i', "Idle Time",     getidle },
  { 'g', "Sex",           getgender },
  { 'q', "Mission",       getmission, PFL_SEESTATS },
  { 'h', "HP",            gethits,    PFL_SEESTATS },
  { 'a', "Arm",           getarmour,  PFL_SEESTATS },
  { '6', "IPv",           get6,       PFL_SEESTATS },
  { 'z', "MCCP",          getmccp,    PFL_SEESTATS },
  { 'X', "MXP",           getmxp,     PFL_SEESTATS },
  { 's', "Stance",        getstance,  PFL_SEESTATS },
  { 'S', "State",         getstate,   PFL_SEESTATS },
  { 'W', "NAWS",          getnaws,    PFL_SEESTATS },
  { 'T', "Terminal",      getterm,    PFL_SEESTATS },
  { 'I', "IP Address",    getip,      PFL_HOSTS },
  { 'H', "Hostname",      gethost,    PFL_HOSTS },
  { 'w', "Locality",      getworld,   PFL_HOSTS },
  { 'f', "FD",            getfd,      PFL_HOSTS },
  { 'c', "Clothes",       getclothes, PFL_SEESTATS },
  { 'm', "Time On",       gettimeon,  PFL_SEESTATS },
  { 'M', "Connected",     getconnected, PFL_SEESTATS },
  { 'A', "Away?",   getaway, },
  { 0 }
};
 
col find_column(char code, MudObject *who) {
  for (size_t i = 0;possibles[i].code;i++) {
    if (possibles[i].code==code) {
      if (possibles[i].priv!=PFL_NONE &&
	  !who->get_priv(possibles[i].priv))
	throw emsg(ssprintf("You can't see column '%c'.", code));
      return possibles[i];
    }
  }
  throw emsg(ssprintf("Couldn't find a column for '%c'.", code));
}

string strrep(int n, string s)
{
  string q;
  if (n > 1000)
    n = 1000;
  if (n < 0)
    n = 0;
  while (n--)
    q += s;
  return q;
}

static void multiwho(MudObject *who, const char *name, const char *code)
{
  bool onlyon = true;
  if (*code=='*') {
    code++; 
    if (who->get_priv(PFL_HOSTS))
      onlyon = false;
  }

  std::vector<Player*> p = players_on(who, onlyon);

  if (p.size()==0) {
    who->printf("There is noone visible on.\n");
    return;
  }

  std::vector<col> cols;

  while (*code) {
    col c = find_column(*code, who);
    c.pre = "";
    c.post = "";
    while (1) {
      if (code[1]=='-') {
	c.right = 1;
	code++;
      } else if (code[1]=='[' && code[2] && code[3]) {
	c.pre = ssprintf("^%c[^%c", code[2], code[3]);
	c.post = ssprintf("^%c]^n", code[2]);
	code+=3;
      } else if (code[1]=='{' && code[2]) {
	c.pre = ssprintf("^%c", code[2]);
	c.post = "^n";
	code+=2;
      } else if (code[1]=='<') {
	code+=2;
	c.name = "";
	while (*code && *code!='>') {
	  c.name += *code;
	  code++;
	}
      } else
	break;
    }
    cols.push_back(c);
    code++;
  }
  
  iforeach(i, p) {
    iforeach(cit, cols) {
      string s = (cit->fn)(*i);
      s += cit->post;
      s += cit->pre;

      cit->wid >?= colour_strlen(s.c_str(), who);
    }
  }

  iforeach(cit, cols) {
    int len = colour_strlen(cit->name.c_str(), who);
    
    if ((len < cit->wid) && colour_strlen(cit->pre.c_str(), who)) {
      cit->pad = 1;
    }

    cit->wid >?= len;
  }

  Header h(who, name);

  // titles

  who->printf("^w");
  size_t f = 0;
  iforeach(cit, cols) {
    if (f) {
	who->printf(" ");
    }
    f++;
    if (f == cols.size()) {
      who->printf("%*s%s", cit->pad, "", cit->name);
    } else {
      who->printf("%*s%-*s", cit->pad, "", cit->wid-cit->pad, cit->name);
    }
  }
  who->printf("\n");

  // the ---+--- line

  who->printf("^B");
  int wid = columns(who)-1;
  f = 0;
  iforeach(cit, cols) {
    if (f) {
      who->printf("^+");
      wid--;
    }
    f = 1;
    int l = cit->wid;
    if (wid<l) 
      l = wid;
    who->printf("%s", strrep(l, "^-"));
    wid -= l;
  }
  who->printf("%s^n\n", strrep(wid, "^-"));

  // bodies

  iforeach(i, p) {
    f = 0;
    iforeach(cit, cols) {
      if (f) {
	who->printf(" ");
      }
      f++;

      string txt = (cit->fn)(*i);

      int colwidth = cit->wid - 
	(colour_strlen(cit->pre.c_str(), who) + colour_strlen(cit->post.c_str(), who));

      if (cit->right) {
	// we have to right align this
	who->printf("%s%*s%s", cit->pre, colwidth, txt, cit->post);
      } else {
	if (f==cols.size() && colour_strlen(cit->post.c_str(), who)==0) {
	  // left align but don't pad, since we are last column and there's no terminator
	  who->printf("%s^Z%s%s", cit->pre, txt, cit->post);
	} else {
	  // business as normal
	  who->printf("%s%-*s%s", cit->pre, colwidth, txt, cit->post);
	}
      }
    }

    who->printf("\n");
  }
}

static bool verb_multiwho(MudObject *who, int argc, const char **argv) { 
  if (!argv[1]) {
    throw emsg("multiwho <code> [title]");
  }
  multiwho(who, argv[2]?:"Multiwho", argv[1]);
  return true;
}

static const char *onoff(MudObject *viewer, bool isoff, MudObject *p, PFlag pflag)
{
  if (pflag != PFL_NONE && !viewer->get_priv(pflag))
    return "";

  if (pflag != PFL_NONE && !p->get_priv(pflag))
    return "^L ^-^-^-^-^-^-^- ";
 
  if (isoff)
    return "^R   off   ";

  return "^G   on    ";
}

static const char *cnoff(const char *what, MudObject *p, PFlag pflag)
{
  if (pflag != PFL_NONE && !p->get_priv(pflag))
    return "";

  return what;
}

static bool verb_acommstats(MudObject *o, int argc, const char **argv) {

  Header h(o, "ACommstats", 1);
    
    std::vector<Player*> p = players_on(o);
    
    size_t maxnamelen = 0;
    iforeach(i, p) {
      Player *obj = *i;
      maxnamelen >?= colour_strlen(obj->get("name"), o);
    }

    o->printf(" %*s %s%s%s%s%s\n", maxnamelen, "",
	      cnoff("aberchat ",  o, PFL_ABERCHAT),
	      cnoff("  achat  ",  o, PFL_ABERCHAT),
	      cnoff("  atell  ",  o, PFL_ABERCHAT),
	      cnoff("  acode  ",  o, PFL_CODER),
	      cnoff("  agod   ",  o, PFL_GOD));
    
    iforeach(i, p) {
      Player *obj = *i;
      o->printf(" %-*M %s%s%s%s%s%s^n\n",
		maxnamelen,
		obj, 
		obj==o?"&-b":"",
		onoff(o, obj->get_flag(FL_NOABERCHAT),  obj, PFL_ABERCHAT),
		onoff(o, obj->get_flag(FL_NOACHAT),     obj, PFL_ABERCHAT),
		onoff(o, obj->get_flag(FL_NOATELL),     obj, PFL_ABERCHAT),
		onoff(o, obj->get_flag(FL_NOACODE),     obj, PFL_CODER),
		onoff(o, obj->get_flag(FL_NOAGOD),      obj, PFL_GOD)
		);
    }
    
    return true;
}

static bool verb_wwwho(MudObject *o, int argc, const char **argv) {
  FILE *f = xopen("tmp", "wwwho-tmp2", "w+");
  if (!f)
    return 1;
  
  std::vector<Player*> p = players_on();

  iforeach(i, p) {
    Player *obj = *i;
    if (!invis(obj)) {
      string title = lose_colour(object_title(obj).c_str());
      fprintf(f, "%s;%s;%s\n", get_long_rank(obj), bwname(obj),
	      title.c_str());
    }
  }

  xclose(f);
  chmod("tmp/wwwho-tmp2", 0664); 
  rename("tmp/wwwho-tmp2", "tmp/wwwho-tmp");
  
  return true;
}

#include "verbmodule.h"

void startup() {

  AUTO_VERB(multiwho, 6, 0, PFL_NONE); 

  AUTO_VERB(acommstats, 5, 0, PFL_ABERCHAT);

  AUTO_VERB(wwwho, 5, 0, PFL_NONE);


}