From 8dd964e3a726a30ad50e7cfc3a5d0356351f24bf Mon Sep 17 00:00:00 2001
From: James R <justsomejames2@gmail.com>
Date: Sat, 5 Dec 2020 02:02:06 -0800
Subject: [PATCH] Lua: taglist.add and taglist.remove for sector tag lists

---
 src/lua_baselib.c |   6 ++-
 src/lua_libs.h    |  10 +++--
 src/lua_maplib.c  |   2 +-
 src/lua_mobjlib.c |   2 +-
 src/lua_taglib.c  | 110 +++++++++++++++++++++++++++++++++++++++-------
 5 files changed, 108 insertions(+), 22 deletions(-)

diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index 1324322a28..59c1d411b7 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -155,6 +155,8 @@ static const struct {
 	{META_PIVOTLIST,    "spriteframepivot_t[]"},
 	{META_FRAMEPIVOT,   "spriteframepivot_t"},
 
+	{META_TAGLIST,      "taglist"},
+
 	{META_MOBJ,         "mobj_t"},
 	{META_MAPTHING,     "mapthing_t"},
 
@@ -184,15 +186,15 @@ static const struct {
 	{META_CVAR,         "consvar_t"},
 
 	{META_SECTORLINES,  "sector_t.lines"},
+#ifdef MUTABLE_TAGS
 	{META_SECTORTAGLIST, "sector_t.taglist"},
+#endif
 	{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 991fae3fd0..e7f4ae253c 100644
--- a/src/lua_libs.h
+++ b/src/lua_libs.h
@@ -12,6 +12,8 @@
 
 extern lua_State *gL;
 
+#define MUTABLE_TAGS
+
 #define LREG_VALID "VALID_USERDATA"
 #define LREG_EXTVARS "LUA_VARS"
 #define LREG_STATEACTION "STATE_ACTION"
@@ -27,6 +29,8 @@ extern lua_State *gL;
 #define META_PIVOTLIST "SPRITEFRAMEPIVOT_T[]"
 #define META_FRAMEPIVOT "SPRITEFRAMEPIVOT_T*"
 
+#define META_TAGLIST "TAGLIST"
+
 #define META_MOBJ "MOBJ_T*"
 #define META_MAPTHING "MAPTHING_T*"
 
@@ -56,14 +60,14 @@ extern lua_State *gL;
 #define META_CVAR "CONSVAR_T*"
 
 #define META_SECTORLINES "SECTOR_T*LINES"
-#define META_SECTORTAGLIST "SECTOR_T*TAGLIST"
+#ifdef MUTABLE_TAGS
+#define META_SECTORTAGLIST "sector_t.taglist"
+#endif
 #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 25edf83d8c..3520cdbda8 100644
--- a/src/lua_maplib.c
+++ b/src/lua_maplib.c
@@ -831,7 +831,7 @@ static int line_get(lua_State *L)
 		lua_pushinteger(L, Tag_FGet(&line->tags));
 		return 1;
 	case line_taglist:
-		LUA_PushUserdata(L, &line->tags, META_LINETAGLIST);
+		LUA_PushUserdata(L, &line->tags, META_TAGLIST);
 		return 1;
 	case line_args:
 		LUA_PushUserdata(L, line->args, META_LINEARGS);
diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c
index 8d205780d0..65adceb154 100644
--- a/src/lua_mobjlib.c
+++ b/src/lua_mobjlib.c
@@ -904,7 +904,7 @@ static int mapthing_get(lua_State *L)
 		number = Tag_FGet(&mt->tags);
 	else if(fastcmp(field,"taglist"))
 	{
-		LUA_PushUserdata(L, &mt->tags, META_THINGTAGLIST);
+		LUA_PushUserdata(L, &mt->tags, META_TAGLIST);
 		return 1;
 	}
 	else if(fastcmp(field,"args"))
diff --git a/src/lua_taglib.c b/src/lua_taglib.c
index 07646af871..7994b6625d 100644
--- a/src/lua_taglib.c
+++ b/src/lua_taglib.c
@@ -17,6 +17,10 @@
 #include "lua_script.h"
 #include "lua_libs.h"
 
+#ifdef MUTABLE_TAGS
+#include "z_zone.h"
+#endif
+
 static int tag_iterator(lua_State *L)
 {
 	INT32 tag = lua_isnil(L, 2) ? -1 : lua_tonumber(L, 2);
@@ -281,6 +285,63 @@ static int taglist_shares(lua_State *L)
 	return 1;
 }
 
+/* only sector tags are mutable... */
+
+#ifdef MUTABLE_TAGS
+static size_t sector_of_taglist(taglist_t *list)
+{
+	return (sector_t *)((char *)list - offsetof (sector_t, tags)) - sectors;
+}
+
+static int this_taglist(lua_State *L)
+{
+	lua_settop(L, 1);
+	return 1;
+}
+
+static int taglist_add(lua_State *L)
+{
+	taglist_t *list = *(taglist_t **)luaL_checkudata(L, 1, META_SECTORTAGLIST);
+	const mtag_t tag = luaL_checknumber(L, 2);
+
+	if (! Tag_Find(list, tag))
+	{
+		Taggroup_Add(tags_sectors, tag, sector_of_taglist(list));
+		Tag_Add(list, tag);
+	}
+
+	return this_taglist(L);
+}
+
+static int taglist_remove(lua_State *L)
+{
+	taglist_t *list = *(taglist_t **)luaL_checkudata(L, 1, META_SECTORTAGLIST);
+	const mtag_t tag = luaL_checknumber(L, 2);
+
+	size_t i;
+
+	for (i = 0; i < list->count; ++i)
+	{
+		if (list->tags[i] == tag)
+		{
+			if (list->count > 1)
+			{
+				memmove(&list->tags[i], &list->tags[i + 1],
+						(list->count - 1 - i) * sizeof (mtag_t));
+				list->tags = Z_Realloc(list->tags,
+						(--list->count) * sizeof (mtag_t), PU_LEVEL, NULL);
+				Taggroup_Remove(tags_sectors, tag, sector_of_taglist(list));
+			}
+			else/* reset to default tag */
+				Tag_SectorFSet(sector_of_taglist(list), 0);
+			break;
+		}
+	}
+
+	return this_taglist(L);
+}
+#endif/*MUTABLE_TAGS*/
+
 void LUA_InsertTaggroupIterator
 (		lua_State *L,
 		taggroup_t *garray[],
@@ -314,9 +375,38 @@ static luaL_Reg taglist_lib[] = {
 	{"iterate", taglist_iterate},
 	{"find", taglist_find},
 	{"shares", taglist_shares},
+#ifdef MUTABLE_TAGS
+	{"add", taglist_add},
+	{"remove", taglist_remove},
+#endif
 	{0}
 };
 
+static void open_taglist(lua_State *L)
+{
+	luaL_register(L, "taglist", taglist_lib);
+
+	lua_getfield(L, -1, "find");
+	lua_setfield(L, -2, "has");
+}
+
+static void set_taglist_metatable(lua_State *L, const char *meta)
+{
+	lua_createtable(L, 0, 4);
+		lua_getglobal(L, "taglist");
+		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_setfield(L, LUA_REGISTRYINDEX, meta);
+}
+
 int LUA_TagLib(lua_State *L)
 {
 	lua_newuserdata(L, 0);
@@ -331,23 +421,13 @@ 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");
+	open_taglist(L);
 
-		lua_pushcfunction(L, taglist_get);
-		lua_setfield(L, -2, "__index");
-
-		lua_pushcfunction(L, taglist_len);
-		lua_setfield(L, -2, "__len");
+	set_taglist_metatable(L, META_TAGLIST);
 
-		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);
+#ifdef MUTABLE_TAGS
+	set_taglist_metatable(L, META_SECTORTAGLIST);
+#endif
 
 	return 0;
 }
-- 
GitLab