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 "verbs.h"
#include "misc.h"
#include "actions.h"
#include "levels.h"
#include "colour.h"
#include "flagnames.h"
#include "trap.h"

#include <algorithm>

#define MODULE "chat"

class ofunc {
public:
  virtual bool operator()(const Player*a, const Player *b) const = 0;
};

class orderer : public ofunc {
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;
  }
};

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

    if (i->get_flag(FL_LOGGEDIN))
      l.push_back(i);
  }
  T o;
  std::sort(l.begin(), l.end(), o);
  return l;
}

std::vector<Player*> players_on(MudObject *who=0) {
  return players_on<orderer>(who);
}

class Toggler : public Verb {
  Flag flag;
  const char *line;
public:
  Toggler(const char *cmd, int minlen, int pr, PFlag pfl, Flag flag, const char *line) : 
    Verb(cmd, minlen, pr, pfl), flag(flag), line(line) {
    set("module", "chat");
    verbs->add(this);
  }

  bool invoke(MudObject *who, int argc, const char **argv)
  {
    who->printf("Turning %s %s.\n", line, who->get_flag(flag)?"on":"off");
    who->set_bflag(flag, !who->get_flag(flag));
    return true;
  }

  ~Toggler() {
    verbs->remove(this);
  }
};

class Channel;

list<Channel*> channels;

static bool verb_commstats(MudObject *o, int argc, const char **argv);

string ltrim(const string &s)
{
  const char *t = s.c_str();
  while (*t) {
    if (!isspace(*t))
      return t;
    t++;
  }
  return "";
}

class Channel : public Verb {
  PFlag priv;

  string channel, defcol, colprop;
  
  string prestr, poststr;

  Flag ignorer;

  Toggler toggler;

  string obj;

  friend bool verb_commstats(MudObject *o, int argc, const char **argv);
  friend void docleanup();
public:
  Channel(const char *cmd, Flag ignorer, int minlen, int pr, PFlag pfl, const char *defcol,
	  const char *colprop, const char *channel, const char *prestr, const char *poststr, string obj) :
    Verb(cmd, minlen, pr, pfl, VFL_MAGICSPACE), 
    priv(pfl),
    channel(channel?:cmd), 
    defcol(defcol?:""),
    colprop(colprop?:""),
    prestr(prestr?:""),
    poststr(poststr?:""),
    ignorer(ignorer),
    toggler(((string)"no"+cmd).c_str(), minlen+2, pr, pfl, ignorer, cmd),
    obj(obj)
  {
    verbs->add(this);
    set("module", "chat");
    channels.push_back(this);
  }

  const char *checker(MudObject *user, MudObject *seer) {
    MudObject *o = planet->get(obj);
    if (!o)
      return 0;
    o->unset("!reason");

    dotrap(E_ONTRYCOMMLINE, o, o, user, seer);
    if (const char *r=o->get("!reason"))
      return r;
    return 0;
  }

  bool invoke(MudObject *who, int argc, const char **argv) 
  {
    if (const char *s=checker(who, NULL)) {
      who->printf("%s\n", s);
      return true;
    }

    string txt = the_rest(argc, argv, 1);
    
    if (!txt.length()) {
      who->printf("Say what?\n");
      return true;
    }

    if (txt[0]==':') {
      string remainder = ltrim(txt.substr(1));
      if (remainder.length()==0) {
	who->printf("Emote what?\n");
	return true;
      }
    }

    if (txt.substr(0, 2)=="::") {
      string remainder = ltrim(txt.substr(2));
      if (remainder.length()==0) {
	who->printf("Possessive Emote what?\n");
	return true;
      }
    }

    parsedact a;

    if (txt[0]=='#')
      a = parse_action(who, txt.c_str()+1, 0);

    if (ignorer != FL_NONE && who->get_flag(ignorer)) {
      who->printf("You had that turned off.\n");
      who->set_bflag(ignorer, 0);
    }
    
    Player *o;
    int i;
    foreach(players, o, i) {
      if (o==who && who->get_flag(FL_NOHEARBACK))
	continue;
      
      if (!o->get_flag(FL_LOGGEDIN))
	continue;

      if (!has_privs(o))
	continue;

      if (ignorer != FL_NONE && o->get_flag(ignorer))
	continue;

      if (checker(who, o))
	continue;

      if (!filter(who)(o))
	continue;
      
      const char *name = who->get("name");
      const char *say = "says";
      if (o->get_flag(FL_PLURAL))
	say = "say";

      if (!visible_to(o, who)) {
	name = "^pSomeone^n";
	say = "says";
      }		

      string rcol = defcol;
      if (colprop.length() && o->get(colprop.c_str())) {
	rcol = o->get(colprop.c_str());
      }
      string col = ssprintf("%c{%c", rcol[0], rcol[1]);

      if (prestr.length() || poststr.length()) {
	o->printf("%#s%s%s%s\2^}%s\n", name, prestr, col, txt, poststr);
	continue;
      }
      
      if (txt[0]==':') {
	if (txt[1]!=':') {
	  o->printf("[%s%s^}] %s %s\2\n", 
		    col.c_str(), channel, name, ltrim(txt.substr(1)));
	} else {
	  o->printf("[%s%s^}] %s's %s\2\n", 
		    col.c_str(), channel, name, ltrim(txt.substr(2)));
	}
      } else {
	if (txt[0]=='#') {
	  o->printf("[%s%s^}] ^Z%s\n", col.c_str(), channel, 
		    sprinta(o, a.a_rest.c_str(), who, a.targ, a.txt.c_str(), 0, a.prop));

	  if (a.r_rest.length())
	    o->printf("[%s%s^}] ^Z%s\n", col.c_str(), channel, 
		      sprinta(o, a.r_rest.c_str(), a.targ, who, a.txt.c_str(), 0, a.rprop));

	} else {
	  o->printf("[%s%s^}] %s %s ^`%s^Z%s\2^}^'\n", 
		    col.c_str(), channel, name, say, col.c_str(), txt.c_str());
	}
      }
    }

    return true;
  }

  ~Channel() {
    verbs->remove(this);
  }
};

static bool verb_commstats(MudObject *o, int argc, const char **argv) {
  std::vector<Player*> p = players_on(o);

    Header h(o, "Commstats", 1);

    size_t maxnamelen = 0;

    iforeach(ip, p) {
      Player *obj = *ip;
      maxnamelen >?= colour_strlen(obj->get("name")?:"", obj);
    }

    o->printf(" %-*s ", maxnamelen, "");

    iforeach(i, channels) {
      Channel *c = *i;

      if (c->priv!=PFL_NONE && !o->get_priv(c->priv))
	continue;
      
      if (privs_of(o) < c->privneeded)
	continue;
      
      if (c->checker(o, 0))
	continue;

      if (c->channel != c->id)
	continue;

      o->printf("%s ", c->id);
    }
    o->printf("\n");

    iforeach(ip, p) {
      Player *obj = *ip;
      const char *back = "";
      if (obj==o)
	back = "&-113B";
      
      o->printf(" %-*M %s", maxnamelen, obj, back);

      iforeach(i, channels) {
	Channel *c = *i;

	if (c->priv!=PFL_NONE && !o->get_priv(c->priv))
	  continue;

	if (privs_of(o) < c->privneeded)
	  continue;

	if (c->checker(o, 0))
	  continue;

	if (c->channel != c->id)
	  continue;

	bool can = 1;
	if (c->priv!=PFL_NONE && !obj->get_priv(c->priv))
	  can = 0;

	if (privs_of(obj) < c->privneeded)
	  can = 0;

	if (c->checker(o, obj))
	  can = 0;

	bool on = 1;
	if (c->ignorer != FL_NONE && obj->get_flag(c->ignorer))
	  on = 0;

	const char *str = can?(on?"^Gon^n":"^Roff^n"):"^-^-^-";
	int slen = can?on?2:3:3;

	int widto = strlen(c->id)-slen;
	int w = widto;
	w /= 2;
	widto -= w;

	o->printf("%-*s%s%s%-*s ", widto, "", str, back, w, "");
	  
      }
      o->printf("^n\n");
    }
    return true;
    
}

void docleanup() {
  iforeach(l, channels) {
    delete *l;
  }
}

#define CLEANUP docleanup();

#include "verbmodule.h"

Flag find_flag(const char *name)
{
  if (!name)
    return FL_NONE;

  for (Flag l=FL_FIRST;l<FL_MAX;l++)
    if (strcasecmp(name, flag_names[l])==0)
      return l;

  return FL_NONE;
}

extern "C" void after_reset() {
  MudObject *ch = planet->get("chat_zone");
  if (!ch)
    return;

  MudObject *o;
  int i;
  foreach(ch->children, o, i) 
    if (o->get_object("start")==ch && o->get("short")) {
      new Channel(o->get("short"),
		  find_flag(o->get("flag")),
		  o->get_int("minlen", 3),
		  o->get_int("minlev", 0),
		  o->get("priv")?find_priv(o->get("priv")):PFL_NONE,
		  o->get("defcol")?:"^R",
		  o->get("colprop"),
		  o->get("channel"),
		  o->get("prestr"),
		  o->get("poststr"),
		  o->id);
    }
}

void startup() {

  AUTO_VERB(commstats, 5, 0, PFL_NONE);
}