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 "actions.h"
#include "musictok.h"
#include "match.h"
#include "misc.h"
#include "hooks.h"
#include "emsg.h"
#include "Verb.h"
#include "trap.h"
#include "verbs.h"

string getstring(FILE *f, int t=1)
{
  char buf[1000];
  if (fgets(buf, 1000, f)==NULL) {
    if (t) {
      emsg e("File truncated.");
      throw e;
    }
  }
  if (char *s=strchr(buf, '\n'))
    *s = 0;
  return buf;
}

class File {
  FILE *fl;
public:
  File(FILE *f) : fl(f) {
  }
  ~File() {
    if (fl)
      xclose(fl);
  }
  operator FILE*() {
    return fl;
  }
};

Action::Action(const char *name, bool create) {
  File f = xopen("actions", name, "r");

  safe = 0;
  
  if (!f) {
    if (create)
      return;
    throw emsg("No such action.");
  }
  
  string s = getstring(f);
  
  if (s[0]=='#') {
    category = s;
    while (category.length() && category[0]=='#')
      category = category.substr(1);
    s = getstring(f);
  }
  
  string type = s;
  
  if (type == "lua") {
    int i = 0;
    while (1) {
      s = getstring(f);
      if (s == "/*")
	break;
      if (i == 0 && s == "safe") {
	safe = 1;
	continue;
      }
      lua += s;
      lua += "\n";
    }
    type = getstring(f);
  }

  int hasob = 0;
  if (type[0]=='o') {
    hasob = 1;
    type = type.substr(1);
  }
  
  int hasprop = 0;
  if (type[0]=='p') {
    hasprop = 1;
    type = type.substr(1);
  }

  if (type=="1") {
    u_me = getstring(f);
    u_rest = getstring(f);
  }
  
  if (type=="2") {
    t_me = getstring(f);
    t_you = getstring(f);
    t_rest = getstring(f);
  }
  
  if (type=="3") {
    u_me = getstring(f);
    t_me = getstring(f);
    t_you = getstring(f);
    u_rest = getstring(f);
    t_rest = getstring(f);
  }
  
  if (type=="4") {
    x_rest = getstring(f);
    x_err = getstring(f);
    x_me = getstring(f);
  }

  if (type=="5") {
    s_rest = getstring(f);
    x_err = getstring(f);
    s_err = getstring(f);
    s_me = getstring(f);
    s_you = getstring(f);
  }

  if (type=="6") {
    x_rest = getstring(f);
    s_rest = getstring(f);
    x_err = getstring(f);
    s_err = getstring(f);
    x_me = getstring(f);
    s_me = getstring(f);
    s_you = getstring(f);
  }

  if (type=="7") {
    u_rest = getstring(f);
    u_me = getstring(f);
    x_rest = getstring(f);
    x_err = getstring(f);
    x_me = getstring(f);
  }
  
  if (hasob) {
    do {
      o_me = getstring(f);
	if (o_me[0]=='|' || o_me[0]=='!')
	  o_req = o_me;
    } while (o_me[0]=='|' || o_me[0]=='!');
    o_rest = getstring(f);
  }

  if (hasprop) {
    do {
      p_me = getstring(f);
	if (p_me[0]=='|' || p_me[0]=='!')
	  p_req = p_me;
    } while (p_me[0]=='|' || p_me[0]=='!');
    p_you = getstring(f);
    p_rest = getstring(f);
  }

  if (type=="new") {
    while (type != "end") {
      if (type=="unt") {
	u_rest = getstring(f);
	u_me = getstring(f);
      }
      if (type=="tar") {
	t_rest = getstring(f);
	t_me = getstring(f);
	t_you = getstring(f);
      }
      if (type=="obj") {
	o_rest = getstring(f);
	o_me = getstring(f);
	o_req = getstring(f);
      }
      if (type=="text") {
	x_rest = getstring(f);
	x_me = getstring(f);
	x_err = getstring(f);
      }
      if (type=="tartext") {
	s_rest = getstring(f);
	s_me = getstring(f);
	s_you = getstring(f);
	s_err = getstring(f);
      }
      if (type=="prop") {
	p_rest = getstring(f);
	p_me = getstring(f);
	p_you = getstring(f);
      }
      type = getstring(f);
    }
  }
}

void Action::output(const char *name) 
{
  if (!category.length() && !x_rest.length() && !s_rest.length() &&
      !lua.length() && !o_rest.length() && !u_rest.length() 
      && !t_rest.length()) {
    xunlink("actions", name);
    return;
  }

  File f = xopen("actions", name, "w");
  if (!f)
    throw emsg("Cannot create action file.");

  if (category.length()) {
    fprintf(f, "#%s\n", category.c_str());
  }

  if (lua.length()) {
    fprintf(f, "lua\n");
    if (safe)
      fprintf(f, "safe\n");
    fprintf(f, "%s/*\n", lua.c_str());
  }

  fprintf(f, "new\n");

  if (u_rest.length()) {
    fprintf(f, "unt\n%s\n%s\n", u_rest.c_str(), u_me.c_str());
  }

  if (x_rest.length()) {
    fprintf(f, "text\n%s\n%s\n%s\n", x_rest.c_str(), x_me.c_str(), x_err.c_str());
  }

  if (s_rest.length()) {
    fprintf(f, "tartext\n%s\n%s\n%s\n%s\n", s_rest.c_str(), s_me.c_str(), s_you.c_str(), s_err.c_str());
  }

  if (t_rest.length()) {
    fprintf(f, "tar\n%s\n%s\n%s\n", t_rest.c_str(), t_me.c_str(), t_you.c_str());
  }

  if (p_rest.length()) {
    fprintf(f, "prop\n%s\n%s\n%s\n", p_rest.c_str(), p_me.c_str(), p_you.c_str());
  }

  if (o_rest.length()) {
    fprintf(f, "obj\n%s\n%s\n%s\n", o_rest.c_str(), o_me.c_str(), o_req.c_str());
  }

  fprintf(f, "end\n");
}


std::vector<const char*> makearray(const std::vector<std::string> &a) {
  std::vector<const char *> v;
  iforeach(i, a) {
    v.push_back(i->c_str());
  }
  v.push_back(0);
  return v;
}

parsedact parse_action(MudObject *who, const string &s, bool trigger)
{
  vector<string> strvec = tokenize(s);
  vector<const char *> argvec = makearray(strvec);
  const char **argv = &argvec[0];
  int argc = argvec.size()-1;
  if (argc==0)
    throw emsg("Do what?");
  return parse_action(who, argc, argv, trigger);
}

string sw(const char *a, const string &b)
{
  if (a)
    return a;
  return b;
}

void assert_meetsreq(MudObject *player, MudObject *obj, const string &req)
{
  if ((req=="|HOLDING" || req=="!WORN") && obj->owner != player) {
    throw emsg(ssprintf("You aren't holding %P.\n", obj));
  }
  
  if (req=="!FLOORWALL" && ((streq(obj->get("short"), "wall") || obj->get_flag(FL_FLOOR)))) {
    throw emsg("You can't do that.\n");
  }
  
  if (req=="!WORN" && obj->get_object(KEY_WORNBY)==player) {
    throw emsg("You can't do that with something you are wearing.\n");
  }
}

parsedact parse_action(MudObject *who, int argc, const char **argv, bool trigger)
{
  Action a(argv[0],1);

  a.u_rest = sw(who->get(ssprintf("myact.%s.u",argv[0]).c_str()), a.u_rest);
  a.t_rest = sw(who->get(ssprintf("myact.%s.t",argv[0]).c_str()), a.t_rest);
  a.o_rest = sw(who->get(ssprintf("myact.%s.o",argv[0]).c_str()), a.o_rest);
  a.p_rest = sw(who->get(ssprintf("myact.%s.p",argv[0]).c_str()), a.p_rest);
  a.x_rest = sw(who->get(ssprintf("myact.%s.x",argv[0]).c_str()), a.x_rest);
  a.s_rest = sw(who->get(ssprintf("myact.%s.s",argv[0]).c_str()), a.s_rest);
  a.x_err = sw(who->get(ssprintf("myact.%s.xe",argv[0]).c_str()), a.x_err);
  a.s_err = sw(who->get(ssprintf("myact.%s.se",argv[0]).c_str()), a.s_err);

  string txt = the_rest(argc, argv, 1);
  string ttxt = the_rest(argc, argv, 1);
  MudObject *targ = 0;
  MudObject *obj = 0;
  MudObject *obj2 = 0;

  /// XXX Better error messages in general

  /// object requirements - done
  /// Myact interface - done
  /// Aloof - done
  /// Invisiblity - done
  /// Self error messages - done

  if (argc>1 && argv[1]) {
    obj = get_player(who, argv[1]);
    if (!obj) {
      if (streq(argv[1], "$1"))
	obj = who->get_object("!$1");
      else {
	NewWorld a = match(who, argc-1, argv+1, NULL, LOOK_BOTH|IGNORE_EXITS|LOOK_MWIELD);
	if (a.getsize()==1) {
	  obj = a.get_nth(0);
	}
      }
    }
    
    string rag = argv[1];
    if (rag.length()>=4 && rag[rag.length()-1]=='>') {
      rag = rag.substr(0, rag.length()-1);
      targ = get_player(who, rag.c_str());
    }
    
    if (targ) {
      ttxt = the_rest(argc, argv, 2);
    }
  }
  
  if (argc>2 && argv[2]) {
    NewWorld prp = match(who, argc-2, argv+2, NULL, LOOK_BOTH|IGNORE_EXITS|LOOK_MWIELD);
    if (prp.getsize()>1) {
      throw emsg("One prop at a time, please.\n");
    }
    if (prp.getsize()) {
      obj2 = prp.get_nth(0);
    }
  }

  txt = possibly_drunkify(who, txt);
  ttxt = possibly_drunkify(who, ttxt);

  if (a.x_rest.length())
    // If we have a text action, we can't be using an object.
    obj = 0;

  if (obj == who || obj2 == who || targ == who)
    throw emsg("You can't do that to yourself.");

  if (obj && obj->get_flag(FL_ALOOF))
    throw emsg(ssprintf("%#M %[is/are] aloof.", obj));
  
  if (obj && !visible_to(obj, who))
    throw emsg(ssprintf("You aren't visible to %M.", obj));

  if (obj && who->get_flag(FL_ALOOF))
    throw emsg(ssprintf("You are aloof.", obj));

  if (a.lua.length() && LUA_DOTRAP && (trigger || a.safe)) {
    if (targ)
      txt = ttxt;

    if (txt.length() && !obj && !a.x_rest.length() && !a.s_rest.length()) {
      throw emsg(ssprintf("Can't match : %s.", txt));
    }

    if (obj && trigger && dotrap(ssprintf("before_act.%s", argv[0]).c_str(), who, obj, obj2))
      throw emsg("");
    /* ::: before_act.* o1==object or mobile an action has been done on; return 1 to abort. */

    who->set("!lua.ac", a.lua);
    LUA_DOTRAP("!lua.ac", who, who, targ?:obj, targ?0:obj2, targ?ttxt.c_str():txt.c_str(), NULL);
    who->unset("!lua.ac");
    
    if (const char *ds = who->get("!msg.me")) {
      MudObject *prop = who->get_object("!msg.prop")?:obj;
      
      parsedact r;
      r.who = who;
      r.a_rest = r.a_you = r.a_me = ds;
      r.targ = obj;
      r.prop = prop;
      r.txt = txt;
      
      if (const char *reply=who->get("!msg.target"))
	{
	  r.r_rest = r.r_you = r.r_me = reply;
	  r.rprop = who->get_object("!msg.tprop")?:obj;
	}

      who->unset("!msg.me");
      who->unset("!msg.prop");
      who->unset("!msg.target");
      who->unset("!msg.tprop");

      return r;
    }

    throw emsg("");
  }

  if (txt.length()==0 && a.u_rest.length()) {
    parsedact resp;
    resp.who = who;
    resp.a_me = a.u_me;
    resp.a_rest = a.u_rest;
    return resp;
  }

  if (obj && is_person(obj) && !obj2 && a.t_rest.length()) {
    if (trigger && dotrap(ssprintf("before_act.%s", argv[0]).c_str(), who, obj, obj2))
      throw emsg("");

    parsedact resp;
    resp.who = who;
    resp.a_me = a.t_me;
    resp.a_rest = a.t_rest;
    resp.a_you = a.t_you;
    resp.targ = resp.prop = obj;
    return resp;
  }

  if (obj && !obj2 && a.o_rest.length()) {
    if (trigger && dotrap(ssprintf("before_act.%s", argv[0]).c_str(), who, obj, obj2))
      throw emsg("");

    assert_meetsreq(who, obj, a.o_req);

    parsedact resp;
    resp.who = who;
    resp.a_me = a.o_me;
    resp.a_rest = a.o_rest;
    resp.targ = resp.prop = obj;
    return resp;
  }

  if (obj && is_person(obj) && obj2) {
    if (trigger && dotrap(ssprintf("before_act.%s", argv[0]).c_str(), who, obj, obj2))
      throw emsg("");

    assert_meetsreq(who, obj2, a.p_req);

    parsedact resp;
    resp.who = who;
    resp.a_me = a.p_me;
    resp.a_rest = a.p_rest;
    resp.a_you = a.p_you;
    resp.targ = obj;
    resp.prop = obj2;
    return resp;    
  }

  if (targ && a.s_rest.length()) {
    if (ttxt.length()==0)
      throw emsg(a.s_err);

    if (trigger && dotrap(ssprintf("before_act.%s", argv[0]).c_str(), who, targ))
      throw emsg("");

    parsedact resp;
    resp.who = who;
    resp.a_me = a.s_me;
    resp.a_rest = a.s_rest;
    resp.a_you = a.s_you;
    resp.targ = resp.prop = targ;
    resp.txt = ttxt;
    return resp;
  }

  if (a.x_rest.length()) {
    if (txt.length()==0)
      throw emsg(a.x_err);
    parsedact resp;
    resp.who = who;
    resp.a_me = a.x_me;
    resp.a_rest = a.x_rest;
    resp.txt = txt;
    return resp;
  }

  throw emsg("Pardon?");
}