#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?"); }