lpc4/lib/
lpc4/lib/doc/efun/
lpc4/lib/doc/lfun/
lpc4/lib/doc/operators/
lpc4/lib/doc/simul_efuns/
lpc4/lib/doc/types/
lpc4/lib/etc/
lpc4/lib/include/
lpc4/lib/include/arpa/
lpc4/lib/obj/d/
lpc4/lib/save/
lpc4/lib/secure/
lpc4/lib/std/
lpc4/lib/std/living/
inherit "/std/thing";
inherit "/std/living";

object debug;
private mixed *states=({0});
mapping envmatch=([]);
mapping matchbase=([]);
string *output_queue=({});

void queue_texts(string *texts)
{
  output_queue+=texts;
  set_heart_beat(1);
}

void heart_beat()
{
  set_heart_beat(0);
  /* don't forget to add ::heart_beat() */
  if(sizeof(output_queue))
  {
    tell_room(environment(),output_queue[0],({this_object()}));
    /* we don't want to que to much, do we? */
    output_queue=output_queue[1..25];
    if(sizeof(output_queue))
      set_heart_beat(1);
  }
}


/* replaces all occurances of repls[n] (n=even) with repls[n+1] in string */
string replace(string qstr, string *repls)
{
  int e;
  if(!qstr || qstr=="") return qstr;
  for(e=0;e<sizeof(repls);e+=2)
	qstr=implode(explode(qstr+repls[e],repls[e]),repls[e+1]);
  return qstr;
}

varargs string treat_string(
		    string str,
		    string a1,
		    string a2,
		    string a3,
		    string a4,
		    string a5,
		    string a6)
{
  if(!a1) a1="";
  if(!a2) a2="";
  if(!a3) a3="";
  if(!a4) a4="";
  if(!a5) a5="";
  if(!a6) a6="";
  return replace(str,({
	"#S1",a1,"#S2",a1,"#S3",a1,"#S4",a1,"#S5",a1,"#S6",a1,
	"#C1",capitalize(a1),"#C2",capitalize(a2),"#C3",capitalize(a3),
	"#C4",capitalize(a4),"#C5",capitalize(a5),"#C6",capitalize(a6),
  }));
}


void set_state(mixed state) { states[0]=state; }
void clear_state(mixed state) { states[0]=({0}); }
void push_state(mixed state) { states=({state})+states; }
mixed query_state() { return states[0]; }

void pop_state()
{
  states=states[1..1000000];
  if(!sizeof(states)) states=({0});
}

void do_grejs(function f,
	      mixed foo,
	      string a,
	      string b,
	      string c,
	      string d,
	      string e,
	      string f)
{
  f(foo,a,b,c,d,e,f);
}

int matchmaker2(string str,mixed *c)
{
  int e;
  string a1,a2,a3,a4,a5,a6;
  mixed tmp,t;

  if(!c) return 0;
  foreach(c,t)
  {
    if(random(100) >= t[0]) continue;
    if((!t[1] && t[2]==str) ||
       t[1]==sscanf(str,t[2],a1,a2,a3,a4,a5,a6))
    {
      tmp=t;
      break;
    }
  }
  if(!tmp) return 0;
  if(debug) tell_object(debug,query_name()+" match:"+tmp[2]+"\n");
  foreach(tmp[3],t)
  {
    if(random(100)<t[0])
    {
      if(!t[1])
      {
        t[2](t[3],a1,a2,a3,a4,a5,a6);
      }else{
        call_out(do_grejs,t[1],t[2],t[3],a1,a2,a3,a4,a5,a6);
      }
    }
  }
  return 1;
}

int matchmaker(string s,mapping m)
{
  if(!stringp(s)) return;
  return matchmaker2(s,m[query_state()]) || matchmaker2(s,m["*"]);
}

void do_submatch(mapping data,
		 string a,
		 string b,
		 string c,
		 string d,
		 string e,
		 string f)
{
  matchmaker(a+"\t"+b+"\t"+c+"\t"+d+"\t"+e+"\t"+f,data[query_state()]);
}

void do_answer_echo(string s,
		    string a1,
		    string a2,
		    string a3,
		    string a4,
		    string a5,
		    string a6)
{
  enable_commands();
  tell_room(environment(),treat_string(s+"\n",a1,a2,a3,a4,a5,a6));
}

void do_answer_say(string s,
		   string a1,
		   string a2,
		   string a3,
		   string a4,
		   string a5,
		   string a6)
{
  string t;
  enable_commands();
  s=treat_string(s+"\n",a1,a2,a3,a4,a5,a6);
  t=query_name()+" says: ";
  queue_texts(explode(sprintf("%*s%-=*s",strlen(t),t,77-strlen(t),s),"\n"));
}

void do_answer_command(string s,
		  string a1,
		  string a2,
		  string a3,
		  string a4,
		  string a5,
		  string a6)
{
  string q;
  q=treat_string(s,a1,a2,a3,a4,a5,a6);
  if(debug)
    tell_object(debug,query_name()+" doing: "+q+"\n");
  command(q);
}

/*** configuration ****/

/* remember, this is just a pointer */
static mapping _tmp;
private static mixed *current_match;

void new_talk_match() { _tmp=matchbase=([]); }
void continue_talk_match() { _tmp=matchbase; }

void new_env_match() { _tmp=envmatch=([]); }
void continue_env_match() { _tmp=envmatch; }

static void stoppa_in_match(mixed *match,mixed stat)
{
  mixed e;
  if(pointerp(stat))
  {
    foreach(stat,e)
    {
      if(!_tmp[e]) _tmp[e]=({});
      _tmp[e]+=({current_match});
    }
  }else{
    if(!_tmp[stat]) _tmp[stat]=({});
    _tmp[stat]+=({current_match});
  }
}

void add_match(int chance,string str,mixed stat)
{
  current_match=({ chance,sizeof(explode(str,"%")),str, ({}) });
  stoppa_in_match(current_match,stat);
}

void copy_match(int chance,string str,mixed stat)
{
  current_match=({ chance,sizeof(explode(str,"%")),str, current_match[3] });
  stoppa_in_match(current_match,stat);
}

void add_call(int chanse,function func,int delay,mixed arg)
{
  current_match[3]+=({({ chanse,delay,func,arg })});
}

void push_matches(int chanse,mixed state)
{
  mapping tmp;
  tmp=([]);
  add_call(chanse,do_submatch,state,tmp);
  push_state(_tmp);
  _tmp=tmp;
}

void pop_matches() 
{
  _tmp=query_state();
  pop_state();
}

void add_echo(int chance,string str,int delay)
{ add_call(chance,do_answer_echo,delay,str); }

void add_emote(int chance,string str,int delay)
{ add_echo(chance,query_name()+" "+str,delay); }

void add_say(int chance,string str,int delay)
{ add_call(chance,do_answer_say,delay,str,this_object()); }

void add_command(int chance,string com,int delay)
{ add_call(chance,do_answer_command,delay,com); }

void add_set_state(int chance,string stat,int delay)
{ add_call(chance,set_state,delay,stat); }

void add_push_state(int chance,string stat,int delay)
{ add_call(chance,push_state,delay,stat); }

void add_pop_state(int chance,int delay)
{ add_call(chance,pop_state,delay,0); }

void add_clear_state(int chance,int delay)
{ add_call(chance,clear_state,delay,0); }


/* lfuns */
void catch_tell(string msg)
{
  if(!stringp(msg)) return;
  if(debug)
    tell_object(debug,query_name()+" got: "+msg+"from:"+
		file_name(previous_object())+"\n");
  msg=lower_case(msg);
  matchmaker(msg,matchbase);
}

object get() { return 0; }

void move_player(string how, mixed where)
{
  ::move_player(how,where);
  matchmaker(hash_name(environment()),envmatch);
}


void set_name(string n)
{
  full_name=capitalize(name=n);
  set_living_name(n);
}

int id(string id)
{
  return living::id(id) || thing::id(id);
}