/* * MusicMUD - Lua Interface Module * Copyright (C) 2002-2003 Paul Lettington * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include <signal.h> #include <sys/time.h> #include <setjmp.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <string.h> #include <vector> #include "musicmud.h" #include "pflags.h" #include "pflagnames.h" #include "flags.h" #include "flagnames.h" #include "events.h" #include "hooks.h" #include "verbs.h" #include "misc.h" #include "State.h" #include "eq.h" #include "death.h" #include "colour.h" extern "C" { #include "lua.h" #include "lualib.h" #include "../lua/src/lstate.h" #include "lauxlib.h" } #include "luaif.h" extern MudObject *worn_on(MudObject *by, const char *what, int wol); int LUA_TRACE=0; string LTRACE_ZONE=""; bool lua_tracing() { if (LUA_TRACE==3) { if (is_player(qui)) return 1; const char *z = qui?qui->get("zone"):""; if (z && streq(z, LTRACE_ZONE.c_str())) return 1; } if (LUA_TRACE==2 || (LUA_TRACE==1 && is_player(qui))) return 1; return 0; } #define MODULE "lua" sigjmp_buf env; lua_State *L; int objecttag=0; int flagtabletag=0; int privtabletag=0; int questtabletag=0; int minitabletag=0; int rotag=0; int sectag=0; int stacksize=0; void do_init(); vector<string> timerobjects; int luadotrap(const char*, MudObject*, MudObject*, MudObject*, MudObject*, const char*, MudObject*ta=0); void lua_verb(MudObject *who, int argc, const char **argv); void lua_timer() { time_t now = time(NULL); vector<string>::iterator iter = timerobjects.begin(); while(iter != timerobjects.end()) { MudObject *ob = planet->get(iter->c_str()); if(!ob) { iter = timerobjects.erase(iter); continue; } int removed=0; int left=0; restart: Object::strit st = ob->strs.begin(); while(st != ob->strs.end()) { const char *key = st->first.c_str(); if(strlen(key)>11 && !strncmp(key,"!lua.timer.",11)) { char * timestring = strdup(key+11); strtok(timestring,"."); if(atoi(timestring) <= now) { luadotrap( key, ob, ob, NULL, NULL, timestring); removed++; ob->unset(key); st = ob->strs.begin(); goto restart; } else { left++; } free(timestring); } st++; } if(!left) { iter = timerobjects.erase(iter); continue; } iter++; } } static int luaerror(lua_State *L) { log(PFL_SEELUASPAM,0,"lua", "error: %s", escape_colour(lua_tostring(L,1), 0).c_str()); return 0; } void do_cleanup() { if(!L) { log(PFL_SEEINFO,0,"lua","nothing to clean up"); } else { lua_close(L); //log(PFL_SEEINFO,0,"lua","cleaned up"); } LUA_DOTRAP=0; LUA_TIMERHOOK=0; LUA_VERB=0; stacksize=-1; } #define SEC_UNTRUSTED 0 #define SEC_TESTTRUSTED 1 #define SEC_APPROVED 2 const char *sec_as=0; int sec_pr=SEC_APPROVED; MudObject *sec_pl=0; MudObject *sec_o1=0; MudObject *sec_o2=0; MudObject *sec_o3=0; MudObject *sec_on=0; const char *sec_txt=0; const char *sec_prop=0; const char **sec_argv=0; int sec_argc=0; Divert *sec_div=0; class Sec { const char *my_as; int my_pr; MudObject *my_pl, *my_o1, *my_o2, *my_o3; MudObject *my_on; const char *my_txt, *my_prop; int my_argc; const char **my_argv; Divert *my_div; public: Sec(const char *as, int pr, MudObject *pl, MudObject *o1, MudObject *o2, MudObject *o3, const char *txt, const char *prop, MudObject *on, int argc=0, const char **argv=0) : my_as(sec_as), my_pr(sec_pr), my_pl(sec_pl), my_o1(sec_o1), my_o2(sec_o2), my_o3(sec_o3), my_on(sec_on), my_txt(sec_txt), my_prop(sec_prop), my_argc(sec_argc), my_argv(sec_argv), my_div(sec_div) { sec_as = as; sec_pr = pr; sec_pl = pl; sec_o1 = o1; sec_o2 = o2; sec_o3 = o3; sec_on = on; sec_txt = txt; sec_prop = prop; sec_argc = argc; sec_argv = argv; sec_div = 0; } ~Sec() { sec_as = my_as; sec_pr = my_pr; sec_pl = my_pl; sec_o1 = my_o1; sec_o2 = my_o2; sec_o3 = my_o3; sec_txt = my_txt; sec_prop = my_prop; sec_argc = my_argc; sec_argv = my_argv; if (sec_div) delete sec_div; sec_div = my_div; } }; void ldivert(MudObject *who, const char *s) { if (sec_div || !who || !s) return; sec_div = new Divert(who, s); } void lundivert(MudObject *who, const char *s) { if (!sec_div) return; delete sec_div; sec_div = 0; } bool writeaccess(MudObject *what) { if (sec_pr==SEC_APPROVED) return 1; if (sec_pr==SEC_TESTTRUSTED) return 1; if (sec_as) { if (!what->get("zone")) return 1; MudObject *z=getzone(what->get("zone")); if (!z) return 1; const char *author = z->get("author"); if (!author) return 1; char owners[4096]; strcpy(owners, author); char *user = strtok(owners, ","); while (user) { if (streq(user, sec_as)) { return true; } user = strtok(0, ","); } return 0; } return 1; } int luadotrap(const char *trig, MudObject *who, MudObject *o1, MudObject *o2, MudObject *o3, const char *txt, MudObject *ta) { string property,disabled; string vals; const char *value; int r, q=1; if (!trig) return 2; if (!who) return 2; if(!L) return 2; lookup: if(strncmp(trig,"lua.",4)==0 || strncmp(trig,"!lua.",5)==0) property=""; else property = "lua."; property += trig; if (!ta) ta = o1; value = (ta?ta:o1)->get(property.c_str()); if (!value) { NewWorld w; w.add(ta); MudObject *tat = ta; MudObject *prev; while (prev=tat,tat=tat->get_object("treatas")) { { if (!tat) break; if (const char *v=tat->get(property.c_str())) { value = v; ta = tat; break; } if (prev==tat) break; if (w.get(tat->id)) { log(PFL_SEEINFO,0,"lua","treatas loop from %s (%s)",o1->id, tat->id); return 0; } w.add(tat); } } } if (!ta) ta = o1; if(!value) { return 2; } const char *as = 0; string ass; int pv=0; if (value[0]==',') { ass = value+1; ass = ass.substr(0, ass.find(',')); if(q) pv = atoi(strchr(value+1, ',')+1); value = strchr(value, ';'); if (!value || !*value) return 2; value++; if (!value || !*value) return 2; if(q) as = ass.c_str(); } if (q && value[0]=='>') { q--; trig = value+1; char *sp=NULL; if((sp = strstr(trig, " "))) { char temp[4096]; int slen = sp-trig; /* hooray for evil hacks */ strncpy(temp,trig,slen); temp[slen]='\0'; MudObject *tempta = planet->get(temp); if(tempta) { ta=tempta; trig=sp+1; } //log(PFL_SEEINFO,0,"lua","dotrap > : temp=%s, trig=%s",temp,trig); } goto lookup; } if (value[0]=='#') { char *tvalue = strdup(value); char *spc=strchr(tvalue, ' '); char *nl=strchr(tvalue, '\n'); char *first = spc; if (nl && (!spc || (nl < spc))) { first = nl; } if (first) { *first = 0; first++; } string prop = tvalue+1; string nv = ""; MudObject *ifrom = ta; string from; if (prop.find(':')!=string::npos) { from = prop.substr(prop.find(':')); prop = prop.substr(0, prop.find(':')-1); ifrom = planet->get(from.c_str()); } if (ifrom) { if (const char *nva=ifrom->get(prop.c_str())) { nv += nva; } else { log(PFL_SEEINFO,0,"lua", "missing include (%s.%s) in %s.%s", ifrom->id, prop.c_str(), ta->id, property.c_str()); } } else { log(PFL_SEEINFO,0,"lua", "missing include (%s.%s) in %s.%s", from.c_str(), prop.c_str(), ta->id, property.c_str()); } nv += "\n"; nv += first; vals = nv; value = vals.c_str(); free(tvalue); } Sec securinfo(as, pv, who, o1, o2, o3, txt, property.c_str(), ta); disabled = property + ".disabled"; if((ta)->get(disabled.c_str())) { /* do we want a log message? could be too spammy if a common trap overran */ log(PFL_SEELUASPAM,0,"lua","%s::%s (%s) is disabled, not running", (ta)->id, property.c_str(), o1->id); return 2; } if (lua_tracing()) { if (ta==o1 || !ta) log(PFL_SEELUASPAM,0,"lua", "found %s on %s", property.c_str(), o1->id); else log(PFL_SEELUASPAM,0,"lua", "found %s on %s for %s", property.c_str(), ta->id, o1->id); } //L->maxopcount=1000000; //if (pv==2) L->maxopcount=1000000; /* trusted code */ int noprevioustimer=0; if(L->opcount == 0) { noprevioustimer=1; } if(L->maxopcount && L->opcount > L->maxopcount) { log(PFL_SEELUASPAM,0,"lua","%s::%s i'm exiting as well, but not disabling myself", (ta)->id,property.c_str()); if(noprevioustimer) L->opcount=0; return 2; } int toreturn=-1; int oldtop=lua_gettop(L); r=lua_dostring(L,value); //if (LUA_TRACE==2 || (LUA_TRACE==1 && is_player(qui))) { if(lua_tracing()) { log(PFL_SEELUASPAM,0,"lua", "%s::%s opcount: %d",(ta)->id, property.c_str(), L->opcount); } if(L->maxopcount && L->opcount > L->maxopcount) { log(PFL_SEELUASPAM,0,"lua","%s::%s took too long, disabling. (opcount=%d)", (ta)->id,property.c_str(),L->opcount); ta->setf(disabled.c_str(),"over-ran at time %lu", time(NULL)); if(noprevioustimer) L->opcount=0; return 2; } if(noprevioustimer) L->opcount=0; if(r) { log(PFL_SEELUASPAM,0,"lua", "%s::%s returned %d",o1->id,property.c_str(),r); toreturn=2; } int newtop = lua_gettop(L); if(oldtop==newtop) { toreturn=0; /* nothing returned */ } else { if(lua_isnumber(L,newtop)) { toreturn = (int) lua_tonumber(L,newtop); } else { toreturn=0; if (lua_isstring(L,newtop)) { who->set("!msg.me", lua_tostring(L, newtop)); } if (newtop == oldtop+4) { if (lua_isstring(L,newtop-3)) { who->set("!msg.me", lua_tostring(L, newtop-3)); } if (l_isobject(L,newtop-2)) { who->set("!msg.prop", l_getobject(L, newtop-2)->id); } if (lua_isstring(L,newtop-1)) { who->set("!msg.target", lua_tostring(L, newtop-1)); } if (l_isobject(L,newtop)) { who->set("!msg.tprop", l_getobject(L, newtop)->id); } } if (newtop == oldtop+3) { if (lua_isstring(L,newtop-2)) { who->set("!msg.me", lua_tostring(L, newtop-2)); } if (l_isobject(L,newtop-1)) { who->set("!msg.prop", l_getobject(L, newtop-1)->id); } if (lua_isstring(L,newtop)) { who->set("!msg.target", lua_tostring(L, newtop)); } } if (newtop == oldtop+2) { if (lua_isstring(L,newtop-1)) { who->set("!msg.me", lua_tostring(L, newtop-1)); } if (l_isobject(L,newtop)) { who->set("!msg.prop", l_getobject(L, newtop)->id); } } } lua_settop(L,oldtop); } //log(PFL_SEELUASPAM,0,"lua","stack: %d/%d, opcount: %d/%d",lua_gettop(L),lua_stackspace(L),L->opcount,L->maxopcount); if(toreturn!=-1) return toreturn; return 2; } void removetimer(const char *code) { const char *k = strchr(code, ':'); if (!k) return; string oid = string(code, k-code); string tid = string(k+1); if (strncmp(tid.c_str(), "!lua.timer.", 11)) return; MudObject *who = planet->get(oid); if (who && who->get(tid.c_str())) { who->unset(tid.c_str()); } } string addtimer(MudObject *obj, const char *code, int when) { string randomcrap; for(int i=0;i<10;i++) randomcrap += ('a' + random_number(26)); string key = ssprintf("!lua.timer.%u.%s",(unsigned int)time(NULL) + (int)lua_tonumber(L,3), randomcrap.c_str()); string value = ssprintf(",%s,%u;%s" , sec_as, sec_pr, lua_tostring(L,2)); obj->set(key, value); int found = 0; iforeach(iter, timerobjects) { if (planet->get(iter->c_str())==obj) found = 1; } if (!found) timerobjects.push_back(obj->id); return ssprintf("%s:%s", obj->id, key.c_str()); } int l_getprops(lua_State *L) { if (lua_gettop(L)!=1 && lua_gettop(L)!=2) { lua_error(L, "wrong number of arguments to getprops()"); } MudObject *obj = l_getobject(L, 1); if (!obj) { lua_error(L, "expected an object for arg 1 of getprops()"); } const char *pref = 0; if (lua_gettop(L)==2) if (lua_isstring(L, 2)) pref = lua_tostring(L, 2); else if (!lua_isnil(L, 2)) lua_error(L, "expected a string or nil for arg 1 of getprops()"); lua_newtable(L); iforeach(i, obj->strs) { if (pref && strncmp(i->first.c_str(), pref, strlen(pref))!=0) continue; lua_pushstring(L, i->first.c_str()); lua_pushstring(L, i->second.c_str()); lua_settable(L, -3); } if (obj->id && (!pref || strncmp("id", pref, strlen(pref))==0)) { lua_pushstring(L, "id"); lua_pushstring(L, obj->id); lua_settable(L, -3); } iforeach(i, obj->ints) { if (pref && strncmp(i->first.c_str(), pref, strlen(pref))!=0) continue; lua_pushstring(L, i->first.c_str()); lua_pushnumber(L, i->second); lua_settable(L, -3); } return 1; } int l_set(lua_State *L) { MudObject *a; const char *key; if(lua_gettop(L)!=3) lua_error(L,"wrong number of arguments to set()"); if(!l_isobject(L,1)) lua_error(L, "expected an object for arg 1 of set"); if(!lua_isstring(L,2)) lua_error(L,"expected string for arg 2 of set"); a= (MudObject*) l_getobject(L,1); key = lua_tostring(L,2); if (strncmp(key, "lua.", 4)==0 || strncmp(key, "!lua.",5)==0) { lua_error(L,"you can't set lua.* or !lua.*"); } if(!a) lua_error(L,"set() no such object"); if(!writeaccess(a)) lua_error(L,"permission violation in set"); switch(lua_type(L,3)) { case LUA_TUSERDATA: if(lua_tag(L,3)==objecttag) { MudObject *b = (MudObject*) lua_touserdata(L,3); a->set(key, b->id); if (lua_tracing()) log(PFL_SEELUASPAM, 0, "lua", "set(%s, %s, %s)", esc(a).c_str(), esc(key).c_str(), esc(b).c_str()); } else { lua_error(L,"bad 3rd argument to set()"); } break; case LUA_TNUMBER: { int num = (int)lua_tonumber(L,3); a->set(key, num); if (lua_tracing()) log(PFL_SEELUASPAM, 0, "lua", "set(%s, %s, %i)", esc(a).c_str(), esc(key).c_str(), num); break; } case LUA_TSTRING: { const char *str = lua_tostring(L, 3); a->set(key, str); if (lua_tracing()) log(PFL_SEELUASPAM, 0, "lua", "set(%s, %s, %s)", esc(a).c_str(), esc(key).c_str(), esc(str).c_str()); break; } default: lua_error(L,"bad 3rd argument to set()"); } return 1; } void l_pushworld(lua_State *L, World<MudObject> *world) { lua_newtable(L); MudObject *child; int i; foreach(world, child, i) { lua_pushnumber(L,i+1); l_pushobject(L,child); lua_settable(L,-3); } } int l_flagtableget(lua_State *L) { const char *key; int key2; if(lua_gettop(L)!=2) lua_error(L,"wrong number of arguments to flagtableget"); if(lua_type(L,1)!=LUA_TTABLE || lua_tag(L,1)!=flagtabletag) lua_error(L,"bad argument to flagtableget"); switch(lua_type(L,2)) { case LUA_TSTRING: key = lua_tostring(L,2); if(strcmp(key,"n")==0) { lua_pushnumber(L,FL_MAX); return 1; } for(int i=0;i<FL_MAX;i++) { if(strcasecmp(flag_names[i],key)==0) { lua_pushnumber(L,i+1); return 1; } } lua_error(L,"key not found in flag table"); lua_pushnil(L); return 1; break; case LUA_TNUMBER: key2 = (int)lua_tonumber(L,2); if(key2>=0 && key2<FL_MAX) { lua_pushstring(L,flag_names[key2-1]); return 1; } else { lua_pushnil(L); return 1; } break; default: lua_error(L,"flagtableget: that was not a number or a string"); } return 0; } int l_privtableget(lua_State *L) { const char *key; int key2; if(lua_gettop(L)!=2) lua_error(L,"wrong number of arguments to privtableget"); if(lua_type(L,1)!=LUA_TTABLE || lua_tag(L,1)!=privtabletag) lua_error(L,"bad argument to privtableget"); switch(lua_type(L,2)) { case LUA_TSTRING: key = lua_tostring(L,2); if(strcmp(key,"n")==0) { lua_pushnumber(L,PFL_MAX); return 1; } for(int i=PFL_NONE;i<PFL_MAX;i++) { if(strcasecmp(priv_names[i],key)==0) { lua_pushnumber(L,i+1); return 1; } } lua_error(L,"key not found in priv table"); lua_pushnil(L); return 1; break; case LUA_TNUMBER: key2 = (int)lua_tonumber(L,2); if(key2>=0 && key2<FL_MAX) { lua_pushstring(L, priv_names[key2-1]); return 1; } else { lua_pushnil(L); return 1; } break; default: lua_error(L,"privtableget: that was not a number or a string"); } return 0; } bool l_isobject(lua_State *L, int idx) { if(lua_tag(L, idx)== objecttag) return 1; if (lua_isstring(L, idx)) { const char *s = lua_tostring(L, idx); if (s && planet->get(s)) return 1; } return 0; } bool l_isnilobject(lua_State *L, int idx) { if(lua_tag(L, idx)== objecttag) return 1; if (lua_isstring(L, idx)) { const char *s = lua_tostring(L, idx); if (s && planet->get(s)) return 1; } if (lua_isnil(L, idx)) return 1; return 0; } MudObject *getobjbyname(const char *what, MudObject *holo); MudObject *l_getobject(lua_State *L, int idx) { if(lua_tag(L, idx)== objecttag) return (MudObject*)lua_touserdata(L, idx); if (lua_isstring(L, idx)) if (const char *s = lua_tostring(L, idx)) return planet->get(s); return 0; } void l_pushobject(lua_State *l, MudObject *o) { if (o) lua_pushusertag(L, o, objecttag); else lua_pushnil(L); } int l_questtableget(lua_State *L) { if(lua_gettop(L)!=2) lua_error(L,"wrong number of arguments to questtableget"); if(lua_type(L,1)!=LUA_TTABLE || lua_tag(L,1)!=questtabletag || !lua_isstring(L,2)) lua_error(L,"bad argument to questtableget"); const char *key = lua_tostring(L,2); MudObject *qu = find_questob(key); if (qu) { l_pushobject(L,qu); return 1; } lua_error(L,"key not found in quest table"); lua_pushnil(L); return 1; } int l_minitableget(lua_State *L) { if(lua_gettop(L)!=2) lua_error(L,"wrong number of arguments to minitableget"); if(lua_type(L,1)!=LUA_TTABLE || lua_tag(L,1)!=minitabletag || !lua_isstring(L,2)) lua_error(L,"bad argument to minitableget"); const char *key = lua_tostring(L,2); MudObject *min = planet->get("mini_zone"); MudObject *o; int i; if (min) { foreach(min->children, o, i) { if (!o->get("mname")) continue; if (!strcasecmp(o->get("mname"), key)) { l_pushobject(L, o); return 1; } } } lua_error(L,"key not found in mini table"); lua_pushnil(L); return 1; } int l_flagtableset(lua_State *L) { lua_error(L,"You can't create new flags, silly"); return 0; } int l_globalset(lua_State *L) { log(PFL_SEELUASPAM,0,"lua","You can't set global variables: %s",lua_tostring(L,-3)); lua_pushnil(L); return 1; } void do_flagload(lua_State *L) { lua_pushcfunction(L,l_flagtableget); lua_settagmethod(L,flagtabletag,"gettable"); lua_pushcfunction(L,l_flagtableset); lua_settagmethod(L,flagtabletag,"settable"); lua_newtable(L); lua_settag(L,flagtabletag); lua_setglobal(L,"flag"); lua_pushcfunction(L,l_privtableget); lua_settagmethod(L,privtabletag,"gettable"); lua_pushcfunction(L,l_flagtableset); lua_settagmethod(L,privtabletag,"settable"); lua_newtable(L); lua_settag(L,privtabletag); lua_setglobal(L,"priv"); lua_pushcfunction(L,l_questtableget); lua_settagmethod(L,questtabletag,"gettable"); lua_pushcfunction(L,l_flagtableset); lua_settagmethod(L,questtabletag,"settable"); lua_newtable(L); lua_settag(L,questtabletag); lua_setglobal(L,"quest"); lua_pushcfunction(L,l_minitableget); lua_settagmethod(L,minitabletag,"gettable"); lua_pushcfunction(L,l_flagtableset); lua_settagmethod(L,minitabletag,"settable"); lua_newtable(L); lua_settag(L,minitabletag); lua_setglobal(L,"mini"); } /* Based on trace-globals.lua in the lua-4.0.1 distribution * Instead of a normal global variable "foo", "foo" would be a table with a * special tag. The actual data is stored in "foo.value" */ int l_ro_setnew(lua_State *L) { //log(PFL_NONE,0,"lua", "ro_setnew: %s",lua_tostring(L,-3)); lua_getglobals(L); lua_pushvalue(L,-4); /* first of 3 passed parameters (name) */ lua_newtable(L); lua_pushstring(L,"value"); /* push the key */ lua_pushvalue(L,-5); /* push the value */ lua_settable(L,-3); /* put the key and the value in the new table */ lua_settag(L,rotag); lua_rawset(L,-3); /* push our new table into the globals */ lua_pop(L,1); /* clean the globals table off the stack */ lua_pushnil(L); return 1; } int l_ro_setnew2(lua_State *L) { log(PFL_SEELUASPAM,0,"lua", "ro_setnew2: You can't create new global variable: %s",lua_tostring(L,-3)); lua_pushnil(L); return 1; } int l_ro_setglobal(lua_State *L) { log(PFL_SEELUASPAM,0,"lua", "ro_setglobal: You can't overwrite global variable: %s",lua_tostring(L,-3)); lua_pushnil(L); return 1; } int l_ro_getglobal(lua_State *L) { lua_pushstring(L,"value"); lua_gettable(L,-2); /* -2 being the last passed argument, which is the value of the global variable (i.e., our table) */ return 1; } /* mark any future global variables as read only */ void ro_setup(lua_State *L) { lua_pushcfunction(L,l_ro_getglobal); lua_settagmethod(L,rotag,"getglobal"); lua_pushcfunction(L,l_ro_setglobal); lua_settagmethod(L,rotag,"setglobal"); lua_pushcfunction(L,l_ro_setnew); lua_settagmethod(L,LUA_TNIL,"setglobal"); } /* prevent the creating of any more global variables */ void ro_final(lua_State *L) { lua_pushcfunction(L,l_ro_setnew2); lua_settagmethod(L,LUA_TNIL,"setglobal"); } int l_sec_setglobal(lua_State *L) { lua_pushstring(L,"You can't change "); lua_pushvalue(L,-4); lua_pushstring(L,", silly"); lua_concat(L,3); lua_error(L,lua_tostring(L,-1)); return 0; } int l_sec_getglobal(lua_State *L) { const char *varname; varname = lua_tostring(L,1); if(strcasecmp(varname,"pl")==0) { if(sec_pl) l_pushobject(L,sec_pl); else lua_pushnil(L); } else if(strcasecmp(varname,"o1")==0) { if(sec_o1) l_pushobject(L,sec_o1); else lua_pushnil(L); } else if(strcasecmp(varname,"o2")==0) { if(sec_o2) l_pushobject(L,sec_o2); else lua_pushnil(L); } else if(strcasecmp(varname,"o3")==0) { if(sec_o3) l_pushobject(L,sec_o3); else lua_pushnil(L); } else if(strcasecmp(varname,"txt")==0) { if(sec_txt) lua_pushstring(L,sec_txt); else lua_pushnil(L); } else if(strcasecmp(varname,"arg")==0) { lua_newtable(L); for (int i=0;i<sec_argc;i++) { lua_pushnumber(L, i); lua_pushstring(L, sec_argv[i]); lua_settable(L, -3); } } else { lua_pushnil(L); } return 1; } void do_secload(lua_State *L) { lua_getglobals(L); lua_pushstring(L,"pl"); lua_pushusertag(L, NULL, sectag); lua_rawset(L,-3); lua_pushstring(L,"o1"); lua_pushusertag(L, NULL, sectag); lua_rawset(L,-3); lua_pushstring(L,"o2"); lua_pushusertag(L, NULL, sectag); lua_rawset(L,-3); lua_pushstring(L,"o3"); lua_pushusertag(L, NULL, sectag); lua_rawset(L,-3); lua_pushstring(L,"txt"); lua_pushusertag(L, NULL, sectag); lua_rawset(L,-3); lua_pushstring(L,"arg"); lua_pushusertag(L, NULL, sectag); lua_rawset(L,-3); lua_pop(L,1); lua_pushcfunction(L,l_sec_getglobal); lua_settagmethod(L,sectag,"getglobal"); lua_pushcfunction(L,l_sec_setglobal); lua_settagmethod(L,sectag,"setglobal"); } void do_init() { L=lua_open(300); if(!L) { log(PFL_SEEINFO,0,"lua","Lua is borken"); } else { //log(PFL_NONE,0,"lua","started"); stacksize = lua_stackspace(L); LUA_DOTRAP = luadotrap; LUA_TIMERHOOK = lua_timer; LUA_VERB = lua_verb; objecttag = lua_newtag(L); flagtabletag = lua_newtag(L); privtabletag = lua_newtag(L); questtabletag = lua_newtag(L); minitabletag = lua_newtag(L); rotag = lua_newtag(L); sectag = lua_newtag(L); ro_setup(L); /* this must be called _before_ any functions are defined */ lua_baselibopen(L); lua_strlibopen(L); lua_mathlibopen(L); do_flagload(L); do_secload(L); lua_register(L,"_ERRORMESSAGE",luaerror); lua_register(L,"set",l_set); lua_register(L,"getprops",l_getprops); autodefine(L); lua_dofile(L,"data/init.lua"); ro_final(L); /* this must be called after all functions are defined */ L->opcount=0; L->maxopcount=1000000; } } bool verb_lstats(MudObject *who, int, const char **) { who->printf("Lua is%s running. Stack: %d/%d. Opcount: %d/%d.\n", (L?"":" not"), (L?lua_stackspace(L):-1), stacksize, L->opcount, L->maxopcount); return true; } bool verb_ltrace(MudObject *who, int argc, const char **argv) { int all=0, zone=0; if(argc==2 && !strcmp("all",argv[1])) all=1; if(argc==3 && streq("zone",argv[1])) { zone=1; } if(zone && LUA_TRACE!=3) { LUA_TRACE = 3; LTRACE_ZONE = argv[2]; log(PFL_SEELUASPAM, 0, "lua", "Tracing players and everything with zone %s", argv[2]); return true; } if(all && LUA_TRACE!=2) { LUA_TRACE = 2; log(PFL_SEELUASPAM, 0, "lua", "Tracing everything. This may get spammy."); return true; } else LUA_TRACE = !LUA_TRACE; log(PFL_SEELUASPAM, 0, "lua", "Tracing %s.", LUA_TRACE?"players only":"turned off"); return true; } bool verb_lua(MudObject *who, int argc, const char *argv[]) { Divert d(who, "lua"); World<MudObject> *blah = planet; if (argc>1 && zones->get(argv[1])) { blah = zones->get(argv[1])->children; } MudObject *o; int i; foreach_alpha(blah, o, i) { MudObject::strit it = o->strs.begin(); while (it != o->strs.end()) { if (strncmp(it->first.c_str(), "lua.", 4)==0) { who->printf("%30s %20s %s\n", o->id, it->first.c_str()+4, o->get(ssprintf("%s.disabled", it->first.c_str()).c_str())? "Disabled":""); } it++; } } return true; } bool verb_export(MudObject *who, int argc, const char *argv[]) { World<MudObject> *blah = planet; if (argc>1 && zones->get(argv[1])) { blah = zones->get(argv[1])->children; } else { who->printf("Export what?\n"); return true; } MudObject *o; int i; string fn = argv[1]; fn += ".lua"; XFILE *f = xopen("data/converted", fn.c_str(), "w"); if (!f) { return true; } foreach_alpha(blah, o, i) { MudObject::strit it = o->strs.begin(); while (it != o->strs.end()) { if (strncmp(it->first.c_str(), "lua.", 4)==0) { fprintf(f, "desc %s %s\n", o->id, it->first.c_str()); const char *l = it->second.c_str(); if (l[0]==',') { l = strchr(l, ';'); if (l) l++; } fprintf(f, "%s\n", l); fprintf(f, ".\n"); } it++; } } xclose(f); return true; } bool verb_import(MudObject *who, int argc, const char *argv[]) { if (!is_player(who)) { return true; } Player *p = (Player *)who; if (argc<2) { who->printf("Import what?\n"); return true; } string fn = argv[1]; fn += ".lua"; XFILE *f = xopen("data/converted", fn.c_str(), "r"); if (!f) { who->printf("Can't find that to import.\n"); return true; } while (1) { char bar[1000]; fgets(bar, 1000, f); if (feof(f)) break; if (strchr(bar, '\n')) { *strchr(bar, '\n')=0; } who->printf("%s\n", bar); if (p->get_state()) p->get_state()->invoke(p, bar); } xclose(f); return true; } void lua_verb(MudObject *who, int argc, const char **argv) { string v = "verb:"; v += argv[0]; string st = the_rest(argc, argv, 1); Sec s("@musicmud", 2, who, NULL, NULL, NULL, st.c_str(), v.c_str(), NULL, argc, argv); string f = DATA_VERBS "/"; f += argv[0]; int oldt = lua_gettop(L); int prev = L->opcount == 0; lua_dofile(L, f.c_str()); if (oldt != lua_gettop(L)) lua_settop(L, oldt); if(L->maxopcount && L->opcount > L->maxopcount) { log(PFL_SEELUASPAM,0,"lua", "verb %s overran!", argv[0]); // should think about disabling it as well } if (prev) L->opcount = 0; return; } bool verb_eval(MudObject *who, int argc, const char **argv) { Sec s("@musicmud", 2, who, NULL, NULL, NULL, NULL, "eval", NULL, 0, NULL); int oldt = lua_gettop(L); int prev = L->opcount == 0; lua_dostring(L, the_rest(argc, argv, 1).c_str()); if(L->maxopcount && L->opcount > L->maxopcount) { log(PFL_SEELUASPAM,0,"lua", "verb %s overran!", argv[0]); // should think about disabling it as well } if (prev) L->opcount = 0; if (oldt != lua_gettop(L)) lua_settop(L, oldt); return true; } #define CLEANUP do_cleanup(); #include "verbmodule.h" void startup() { do_init(); AUTO_VERB(eval, 3, 0, PFL_CODER); AUTO_VERB(lstats, 3, 0, PFL_CODER); AUTO_VERB(lua, 3, 0, PFL_CODER); AUTO_VERB(import, 6, 0, PFL_CODER); AUTO_VERB(export, 6, 0, PFL_CODER); AUTO_VERB(ltrace, 5, 0, PFL_CODER); }