diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 4667fdbf4..1324322a2 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -184,12 +184,15 @@ static const struct { {META_CVAR, "consvar_t"}, {META_SECTORLINES, "sector_t.lines"}, + {META_SECTORTAGLIST, "sector_t.taglist"}, {META_SIDENUM, "line_t.sidenum"}, {META_LINEARGS, "line_t.args"}, {META_LINESTRINGARGS, "line_t.stringargs"}, + {META_LINETAGLIST, "line_t.taglist"}, {META_THINGARGS, "mapthing.args"}, {META_THINGSTRINGARGS, "mapthing.stringargs"}, + {META_THINGTAGLIST, "mapthing_t.taglist"}, #ifdef HAVE_LUA_SEGS {META_NODEBBOX, "node_t.bbox"}, {META_NODECHILDREN, "node_t.children"}, diff --git a/src/lua_libs.h b/src/lua_libs.h index aa0638683..991fae3fd 100644 --- a/src/lua_libs.h +++ b/src/lua_libs.h @@ -56,11 +56,14 @@ extern lua_State *gL; #define META_CVAR "CONSVAR_T*" #define META_SECTORLINES "SECTOR_T*LINES" +#define META_SECTORTAGLIST "SECTOR_T*TAGLIST" #define META_SIDENUM "LINE_T*SIDENUM" #define META_LINEARGS "LINE_T*ARGS" #define META_LINESTRINGARGS "LINE_T*STRINGARGS" +#define META_LINETAGLIST "LINE_T*TAGLIST" #define META_THINGARGS "MAPTHING_T*ARGS" #define META_THINGSTRINGARGS "MAPTHING_T*STRINGARGS" +#define META_THINGTAGLIST "THING_T*TAGLIST" #define META_POLYOBJVERTICES "POLYOBJ_T*VERTICES" #define META_POLYOBJLINES "POLYOBJ_T*LINES" #ifdef HAVE_LUA_SEGS diff --git a/src/lua_maplib.c b/src/lua_maplib.c index a3df28cca..25edf83d8 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -37,6 +37,7 @@ enum sector_e { sector_lightlevel, sector_special, sector_tag, + sector_taglist, sector_thinglist, sector_heightsec, sector_camsec, @@ -55,6 +56,7 @@ static const char *const sector_opt[] = { "lightlevel", "special", "tag", + "taglist", "thinglist", "heightsec", "camsec", @@ -89,6 +91,7 @@ enum line_e { line_flags, line_special, line_tag, + line_taglist, line_args, line_stringargs, line_sidenum, @@ -113,6 +116,7 @@ static const char *const line_opt[] = { "flags", "special", "tag", + "taglist", "args", "stringargs", "sidenum", @@ -581,6 +585,9 @@ static int sector_get(lua_State *L) case sector_tag: lua_pushinteger(L, Tag_FGet(§or->tags)); return 1; + case sector_taglist: + LUA_PushUserdata(L, §or->tags, META_SECTORTAGLIST); + return 1; case sector_thinglist: // thinglist lua_pushcfunction(L, lib_iterateSectorThinglist); LUA_PushUserdata(L, sector->thinglist, META_MOBJ); @@ -682,6 +689,8 @@ static int sector_set(lua_State *L) case sector_tag: Tag_SectorFSet((UINT32)(sector - sectors), (INT16)luaL_checkinteger(L, 3)); break; + case sector_taglist: + return LUA_ErrSetDirectly(L, "sector_t", "taglist"); } return 0; } @@ -821,6 +830,9 @@ static int line_get(lua_State *L) case line_tag: lua_pushinteger(L, Tag_FGet(&line->tags)); return 1; + case line_taglist: + LUA_PushUserdata(L, &line->tags, META_LINETAGLIST); + return 1; case line_args: LUA_PushUserdata(L, line->args, META_LINEARGS); return 1; diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 134f104ee..8d205780d 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -902,6 +902,11 @@ static int mapthing_get(lua_State *L) number = mt->extrainfo; else if(fastcmp(field,"tag")) number = Tag_FGet(&mt->tags); + else if(fastcmp(field,"taglist")) + { + LUA_PushUserdata(L, &mt->tags, META_THINGTAGLIST); + return 1; + } else if(fastcmp(field,"args")) { LUA_PushUserdata(L, mt->args, META_THINGARGS); @@ -964,6 +969,8 @@ static int mapthing_set(lua_State *L) } else if (fastcmp(field,"tag")) Tag_FSet(&mt->tags, (INT16)luaL_checkinteger(L, 3)); + else if (fastcmp(field,"taglist")) + return LUA_ErrSetDirectly(L, "mapthing_t", "taglist"); else if(fastcmp(field,"mobj")) mt->mobj = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); else diff --git a/src/lua_script.h b/src/lua_script.h index 2dc34446a..77fbb7c1d 100644 --- a/src/lua_script.h +++ b/src/lua_script.h @@ -102,6 +102,8 @@ void COM_Lua_f(void); #define LUA_ErrInvalid(L, type) luaL_error(L, "accessed " type " doesn't exist anymore, please check 'valid' before using " type "."); +#define LUA_ErrSetDirectly(L, type, field) luaL_error(L, type " field " LUA_QL(field) " cannot be set directly.") + // Deprecation warnings // Shows once upon use. Then doesn't show again. #define LUA_Deprecated(L,this_func,use_instead)\ diff --git a/src/lua_taglib.c b/src/lua_taglib.c index 2e2a0d277..73f033312 100644 --- a/src/lua_taglib.c +++ b/src/lua_taglib.c @@ -150,6 +150,137 @@ static int lib_numTaggroupElements(lua_State *L) return 1; } +static void push_taglist(lua_State *L, int idx) +{ + lua_getmetatable(L, idx); + lua_pushliteral(L, "taglist"); + lua_rawget(L, -2); + lua_remove(L, -2); +} + +static int has_valid_field(lua_State *L) +{ + int equal; + lua_pushliteral(L, "valid"); + equal = lua_rawequal(L, 2, -1); + lua_pop(L, 1); + return equal; +} + +static taglist_t * valid_taglist(lua_State *L, int idx, boolean getting) +{ + taglist_t *list = *(taglist_t **)lua_touserdata(L, idx); + + if (list == NULL) + { + if (getting && has_valid_field(L)) + lua_pushboolean(L, 0); + else + LUA_ErrInvalid(L, "taglist_t");/* doesn't actually return */ + return NULL; + } + else + return list; +} + +static taglist_t * check_taglist(lua_State *L, int idx) +{ + luaL_checktype(L, idx, LUA_TUSERDATA); + push_taglist(L, idx); + luaL_argcheck(L, lua_toboolean(L, -1), idx, "must be a tag list"); + return valid_taglist(L, idx, false); +} + +static int taglist_get(lua_State *L) +{ + const taglist_t *list = valid_taglist(L, 1, true); + + if (list == NULL)/* valid check */ + return 1; + + if (lua_isnumber(L, 2)) + { + const size_t i = lua_tonumber(L, 2); + + if (list && i <= list->count) + { + lua_pushnumber(L, list->tags[i - 1]); + return 1; + } + else + return 0; + } + else if (has_valid_field(L)) + { + lua_pushboolean(L, 1); + return 1; + } + else + { + push_taglist(L, 1); + lua_replace(L, 1); + lua_rawget(L, 1); + return 1; + } +} + +static int taglist_len(lua_State *L) +{ + const taglist_t *list = valid_taglist(L, 1, false); + lua_pushnumber(L, list->count); + return 1; +} + +static int taglist_equal(lua_State *L) +{ + const taglist_t *lhs = check_taglist(L, 1); + const taglist_t *rhs = check_taglist(L, 2); + lua_pushboolean(L, Tag_Compare(lhs, rhs)); + return 1; +} + +static int taglist_iterator(lua_State *L) +{ + const taglist_t *list = valid_taglist(L, 1, false); + const size_t i = 1 + lua_tonumber(L, lua_upvalueindex(1)); + if (i <= list->count) + { + lua_pushnumber(L, list->tags[i - 1]); + /* watch me exploit an upvalue as a control because + I want to use the control as the value */ + lua_pushnumber(L, i); + lua_replace(L, lua_upvalueindex(1)); + return 1; + } + else + return 0; +} + +static int taglist_iterate(lua_State *L) +{ + check_taglist(L, 1); + lua_pushnumber(L, 0); + lua_pushcclosure(L, taglist_iterator, 1); + lua_pushvalue(L, 1); + return 2; +} + +static int taglist_find(lua_State *L) +{ + const taglist_t *list = check_taglist(L, 1); + const mtag_t tag = luaL_checknumber(L, 2); + lua_pushboolean(L, Tag_Find(list, tag)); + return 1; +} + +static int taglist_shares(lua_State *L) +{ + const taglist_t *lhs = check_taglist(L, 1); + const taglist_t *rhs = check_taglist(L, 2); + lua_pushboolean(L, Tag_Share(lhs, rhs)); + return 1; +} + void LUA_InsertTaggroupIterator ( lua_State *L, taggroup_t *garray[], @@ -179,6 +310,13 @@ void LUA_InsertTaggroupIterator lua_setfield(L, -2, "tagged"); } +static luaL_Reg taglist_lib[] = { + {"iterate", taglist_iterate}, + {"find", taglist_find}, + {"shares", taglist_shares}, + {0} +}; + int LUA_TagLib(lua_State *L) { lua_newuserdata(L, 0); @@ -193,5 +331,23 @@ int LUA_TagLib(lua_State *L) lua_setmetatable(L, -2); lua_setglobal(L, "tags"); + luaL_newmetatable(L, META_THINGTAGLIST); + luaL_register(L, "taglist", taglist_lib); + lua_getfield(L, -1, "find"); + lua_setfield(L, -2, "has"); + lua_setfield(L, -2, "taglist"); + + lua_pushcfunction(L, taglist_get); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, taglist_len); + lua_setfield(L, -2, "__len"); + + lua_pushcfunction(L, taglist_equal); + lua_setfield(L, -2, "__eq"); + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, META_LINETAGLIST); + lua_setfield(L, LUA_REGISTRYINDEX, META_SECTORTAGLIST); + return 0; }