diff --git a/src/deh_lua.c b/src/deh_lua.c
index a2ffca95b0622826dd69d350c60dba52e221b0f9..0bd906c1321f2126740494e34c450bc6887d8c6c 100644
--- a/src/deh_lua.c
+++ b/src/deh_lua.c
@@ -10,20 +10,7 @@
 /// \file  deh_lua.c
 /// \brief Lua SOC library
 
-#include "g_game.h"
-#include "s_sound.h"
-#include "z_zone.h"
-#include "m_menu.h"
-#include "m_misc.h"
-#include "p_local.h"
-#include "st_stuff.h"
-#include "fastcmp.h"
-#include "lua_script.h"
-#include "lua_libs.h"
-
-#include "dehacked.h"
 #include "deh_lua.h"
-#include "deh_tables.h"
 
 // freeslot takes a name (string only!)
 // and allocates it to the appropriate free slot.
@@ -89,6 +76,8 @@ static inline int lib_freeslot(lua_State *L)
 				strncpy(sprnames[j],word,4);
 				//sprnames[j][4] = 0;
 				used_spr[(j-SPR_FIRSTFREESLOT)/8] |= 1<<(j%8); // Okay, this sprite slot has been named now.
+				// Lua needs to update the value in _G if it exists
+				LUA_UpdateSprName(word, j);
 				lua_pushinteger(L, j);
 				r++;
 				break;
@@ -216,18 +205,27 @@ static int lib_dummysuper(lua_State *L)
 	return luaL_error(L, "Can't call super() outside of hardcode-replacing A_Action functions being called by state changes!"); // convoluted, I know. @_@;;
 }
 
-static inline int lib_getenum(lua_State *L)
+static void CacheAndPushConstant(lua_State *L, const char *name, lua_Integer value)
+{
+	// "cache" into _G
+	lua_pushstring(L, name);
+	lua_pushinteger(L, value);
+	lua_rawset(L, LUA_GLOBALSINDEX);
+	// push
+	lua_pushinteger(L, value);
+}
+
+// Search for a matching constant variable.
+// Result is stored into _G for faster subsequent use. (Except for SPR_ in the SOC parser)
+static int ScanConstants(lua_State *L, boolean mathlib, const char *word)
 {
-	const char *word, *p;
+	const char *p;
 	fixed_t i;
-	boolean mathlib = lua_toboolean(L, lua_upvalueindex(1));
-	if (lua_type(L,2) != LUA_TSTRING)
-		return 0;
-	word = lua_tostring(L,2);
+
 	if (strlen(word) == 1) { // Assume sprite frame if length 1.
 		if (*word >= 'A' && *word <= '~')
 		{
-			lua_pushinteger(L, *word-'A');
+			CacheAndPushConstant(L, word, *word-'A');
 			return 1;
 		}
 		if (mathlib) return luaL_error(L, "constant '%s' could not be parsed.\n", word);
@@ -237,7 +235,7 @@ static inline int lib_getenum(lua_State *L)
 		p = word+3;
 		for (i = 0; MOBJFLAG_LIST[i]; i++)
 			if (fastcmp(p, MOBJFLAG_LIST[i])) {
-				lua_pushinteger(L, ((lua_Integer)1<<i));
+				CacheAndPushConstant(L, word, ((lua_Integer)1<<i));
 				return 1;
 			}
 		if (mathlib) return luaL_error(L, "mobjflag '%s' could not be found.\n", word);
@@ -247,7 +245,7 @@ static inline int lib_getenum(lua_State *L)
 		p = word+4;
 		for (i = 0; MOBJFLAG2_LIST[i]; i++)
 			if (fastcmp(p, MOBJFLAG2_LIST[i])) {
-				lua_pushinteger(L, ((lua_Integer)1<<i));
+				CacheAndPushConstant(L, word, ((lua_Integer)1<<i));
 				return 1;
 			}
 		if (mathlib) return luaL_error(L, "mobjflag2 '%s' could not be found.\n", word);
@@ -257,12 +255,12 @@ static inline int lib_getenum(lua_State *L)
 		p = word+4;
 		for (i = 0; MOBJEFLAG_LIST[i]; i++)
 			if (fastcmp(p, MOBJEFLAG_LIST[i])) {
-				lua_pushinteger(L, ((lua_Integer)1<<i));
+				CacheAndPushConstant(L, word, ((lua_Integer)1<<i));
 				return 1;
 			}
 		if (fastcmp(p, "REVERSESUPER"))
 		{
-			lua_pushinteger(L, (lua_Integer)MFE_REVERSESUPER);
+			CacheAndPushConstant(L, word, (lua_Integer)MFE_REVERSESUPER);
 			return 1;
 		}
 		if (mathlib) return luaL_error(L, "mobjeflag '%s' could not be found.\n", word);
@@ -272,7 +270,7 @@ static inline int lib_getenum(lua_State *L)
 		p = word+4;
 		for (i = 0; i < 4; i++)
 			if (MAPTHINGFLAG_LIST[i] && fastcmp(p, MAPTHINGFLAG_LIST[i])) {
-				lua_pushinteger(L, ((lua_Integer)1<<i));
+				CacheAndPushConstant(L, word, ((lua_Integer)1<<i));
 				return 1;
 			}
 		if (mathlib) return luaL_error(L, "mapthingflag '%s' could not be found.\n", word);
@@ -282,17 +280,17 @@ static inline int lib_getenum(lua_State *L)
 		p = word+3;
 		for (i = 0; PLAYERFLAG_LIST[i]; i++)
 			if (fastcmp(p, PLAYERFLAG_LIST[i])) {
-				lua_pushinteger(L, ((lua_Integer)1<<i));
+				CacheAndPushConstant(L, word, ((lua_Integer)1<<i));
 				return 1;
 			}
 		if (fastcmp(p, "FULLSTASIS"))
 		{
-			lua_pushinteger(L, (lua_Integer)PF_FULLSTASIS);
+			CacheAndPushConstant(L, word, (lua_Integer)PF_FULLSTASIS);
 			return 1;
 		}
 		else if (fastcmp(p, "USEDOWN")) // Remove case when 2.3 nears release...
 		{
-			lua_pushinteger(L, (lua_Integer)PF_SPINDOWN);
+			CacheAndPushConstant(L, word, (lua_Integer)PF_SPINDOWN);
 			return 1;
 		}
 		if (mathlib) return luaL_error(L, "playerflag '%s' could not be found.\n", word);
@@ -302,7 +300,7 @@ static inline int lib_getenum(lua_State *L)
 		p = word;
 		for (i = 0; Gametype_ConstantNames[i]; i++)
 			if (fastcmp(p, Gametype_ConstantNames[i])) {
-				lua_pushinteger(L, i);
+				CacheAndPushConstant(L, word, i);
 				return 1;
 			}
 		if (mathlib) return luaL_error(L, "gametype '%s' could not be found.\n", word);
@@ -312,7 +310,7 @@ static inline int lib_getenum(lua_State *L)
 		p = word+4;
 		for (i = 0; GAMETYPERULE_LIST[i]; i++)
 			if (fastcmp(p, GAMETYPERULE_LIST[i])) {
-				lua_pushinteger(L, ((lua_Integer)1<<i));
+				CacheAndPushConstant(L, word, ((lua_Integer)1<<i));
 				return 1;
 			}
 		if (mathlib) return luaL_error(L, "game type rule '%s' could not be found.\n", word);
@@ -322,7 +320,7 @@ static inline int lib_getenum(lua_State *L)
 		p = word+4;
 		for (i = 0; TYPEOFLEVEL[i].name; i++)
 			if (fastcmp(p, TYPEOFLEVEL[i].name)) {
-				lua_pushinteger(L, TYPEOFLEVEL[i].flag);
+				CacheAndPushConstant(L, word, TYPEOFLEVEL[i].flag);
 				return 1;
 			}
 		if (mathlib) return luaL_error(L, "typeoflevel '%s' could not be found.\n", word);
@@ -332,7 +330,7 @@ static inline int lib_getenum(lua_State *L)
 		p = word+3;
 		for (i = 0; i < 16; i++)
 			if (ML_LIST[i] && fastcmp(p, ML_LIST[i])) {
-				lua_pushinteger(L, ((lua_Integer)1<<i));
+				CacheAndPushConstant(L, word, ((lua_Integer)1<<i));
 				return 1;
 			}
 		if (mathlib) return luaL_error(L, "linedef flag '%s' could not be found.\n", word);
@@ -344,13 +342,13 @@ static inline int lib_getenum(lua_State *L)
 			if (!FREE_STATES[i])
 				break;
 			if (fastcmp(p, FREE_STATES[i])) {
-				lua_pushinteger(L, S_FIRSTFREESLOT+i);
+				CacheAndPushConstant(L, word, S_FIRSTFREESLOT+i);
 				return 1;
 			}
 		}
 		for (i = 0; i < S_FIRSTFREESLOT; i++)
 			if (fastcmp(p, STATE_LIST[i]+2)) {
-				lua_pushinteger(L, i);
+				CacheAndPushConstant(L, word, i);
 				return 1;
 			}
 		return luaL_error(L, "state '%s' does not exist.\n", word);
@@ -361,13 +359,13 @@ static inline int lib_getenum(lua_State *L)
 			if (!FREE_MOBJS[i])
 				break;
 			if (fastcmp(p, FREE_MOBJS[i])) {
-				lua_pushinteger(L, MT_FIRSTFREESLOT+i);
+				CacheAndPushConstant(L, word, MT_FIRSTFREESLOT+i);
 				return 1;
 			}
 		}
 		for (i = 0; i < MT_FIRSTFREESLOT; i++)
 			if (fastcmp(p, MOBJTYPE_LIST[i]+3)) {
-				lua_pushinteger(L, i);
+				CacheAndPushConstant(L, word, i);
 				return 1;
 			}
 		return luaL_error(L, "mobjtype '%s' does not exist.\n", word);
@@ -376,7 +374,12 @@ static inline int lib_getenum(lua_State *L)
 		p = word+4;
 		for (i = 0; i < NUMSPRITES; i++)
 			if (!sprnames[i][4] && fastncmp(p,sprnames[i],4)) {
-				lua_pushinteger(L, i);
+				// updating overridden sprnames is not implemented for soc parser,
+				// so don't use cache
+				if (mathlib)
+					lua_pushinteger(L, i);
+				else
+					CacheAndPushConstant(L, word, i);
 				return 1;
 			}
 		if (mathlib) return luaL_error(L, "sprite '%s' could not be found.\n", word);
@@ -391,12 +394,12 @@ static inline int lib_getenum(lua_State *L)
 				// the spr2names entry will have "_" on the end, as in "RUN_"
 				if (spr2names[i][3] == '_' && !p[3]) {
 					if (fastncmp(p,spr2names[i],3)) {
-						lua_pushinteger(L, i);
+						CacheAndPushConstant(L, word, i);
 						return 1;
 					}
 				}
 				else if (fastncmp(p,spr2names[i],4)) {
-					lua_pushinteger(L, i);
+					CacheAndPushConstant(L, word, i);
 					return 1;
 				}
 			}
@@ -407,7 +410,7 @@ static inline int lib_getenum(lua_State *L)
 		p = word+4;
 		for (i = 0; i < NUMSFX; i++)
 			if (S_sfx[i].name && fastcmp(p, S_sfx[i].name)) {
-				lua_pushinteger(L, i);
+				CacheAndPushConstant(L, word, i);
 				return 1;
 			}
 		return 0;
@@ -416,7 +419,7 @@ static inline int lib_getenum(lua_State *L)
 		p = word+4;
 		for (i = 0; i < NUMSFX; i++)
 			if (S_sfx[i].name && fasticmp(p, S_sfx[i].name)) {
-				lua_pushinteger(L, i);
+				CacheAndPushConstant(L, word, i);
 				return 1;
 			}
 		return luaL_error(L, "sfx '%s' could not be found.\n", word);
@@ -425,7 +428,7 @@ static inline int lib_getenum(lua_State *L)
 		p = word+2;
 		for (i = 0; i < NUMSFX; i++)
 			if (S_sfx[i].name && fasticmp(p, S_sfx[i].name)) {
-				lua_pushinteger(L, i);
+				CacheAndPushConstant(L, word, i);
 				return 1;
 			}
 		if (mathlib) return luaL_error(L, "sfx '%s' could not be found.\n", word);
@@ -435,7 +438,7 @@ static inline int lib_getenum(lua_State *L)
 		p = word+3;
 		for (i = 0; i < NUMPOWERS; i++)
 			if (fasticmp(p, POWERS_LIST[i])) {
-				lua_pushinteger(L, i);
+				CacheAndPushConstant(L, word, i);
 				return 1;
 			}
 		return 0;
@@ -444,7 +447,7 @@ static inline int lib_getenum(lua_State *L)
 		p = word+3;
 		for (i = 0; i < NUMPOWERS; i++)
 			if (fastcmp(p, POWERS_LIST[i])) {
-				lua_pushinteger(L, i);
+				CacheAndPushConstant(L, word, i);
 				return 1;
 			}
 		return luaL_error(L, "power '%s' could not be found.\n", word);
@@ -453,7 +456,7 @@ static inline int lib_getenum(lua_State *L)
 		p = word+4;
 		for (i = 0; i < NUMHUDITEMS; i++)
 			if (fastcmp(p, HUDITEMS_LIST[i])) {
-				lua_pushinteger(L, i);
+				CacheAndPushConstant(L, word, i);
 				return 1;
 			}
 		if (mathlib) return luaL_error(L, "huditem '%s' could not be found.\n", word);
@@ -465,13 +468,13 @@ static inline int lib_getenum(lua_State *L)
 			if (!FREE_SKINCOLORS[i])
 				break;
 			if (fastcmp(p, FREE_SKINCOLORS[i])) {
-				lua_pushinteger(L, SKINCOLOR_FIRSTFREESLOT+i);
+				CacheAndPushConstant(L, word, SKINCOLOR_FIRSTFREESLOT+i);
 				return 1;
 			}
 		}
 		for (i = 0; i < SKINCOLOR_FIRSTFREESLOT; i++)
 			if (fastcmp(p, COLOR_ENUMS[i])) {
-				lua_pushinteger(L, i);
+				CacheAndPushConstant(L, word, i);
 				return 1;
 			}
 		return luaL_error(L, "skincolor '%s' could not be found.\n", word);
@@ -482,7 +485,7 @@ static inline int lib_getenum(lua_State *L)
 		for (i = 0; NIGHTSGRADE_LIST[i]; i++)
 			if (*p == NIGHTSGRADE_LIST[i])
 			{
-				lua_pushinteger(L, i);
+				CacheAndPushConstant(L, word, i);
 				return 1;
 			}
 		if (mathlib) return luaL_error(L, "NiGHTS grade '%s' could not be found.\n", word);
@@ -492,13 +495,41 @@ static inline int lib_getenum(lua_State *L)
 		p = word+3;
 		for (i = 0; i < NUMMENUTYPES; i++)
 			if (fastcmp(p, MENUTYPES_LIST[i])) {
-				lua_pushinteger(L, i);
+				CacheAndPushConstant(L, word, i);
 				return 1;
 			}
 		if (mathlib) return luaL_error(L, "menutype '%s' could not be found.\n", word);
 		return 0;
 	}
-	else if (!mathlib && fastncmp("A_",word,2)) {
+
+	if (fastcmp(word, "BT_USE")) // Remove case when 2.3 nears release...
+	{
+		CacheAndPushConstant(L, word, (lua_Integer)BT_SPIN);
+		return 1;
+	}
+
+	for (i = 0; INT_CONST[i].n; i++)
+		if (fastcmp(word,INT_CONST[i].n)) {
+			CacheAndPushConstant(L, word, INT_CONST[i].v);
+			return 1;
+		}
+
+	return 0;
+}
+
+static inline int lib_getenum(lua_State *L)
+{
+	const char *word;
+	fixed_t i;
+	boolean mathlib = lua_toboolean(L, lua_upvalueindex(1));
+	if (lua_type(L,2) != LUA_TSTRING)
+		return 0;
+	word = lua_tostring(L,2);
+
+	// check actions, super and globals first, as they don't have _G caching implemented
+	// so they benefit from being checked first
+
+	if (!mathlib && fastncmp("A_",word,2)) {
 		char *caps;
 		// Try to get a Lua action first.
 		/// \todo Push a closure that sets superactions[] and superstack.
@@ -537,25 +568,33 @@ static inline int lib_getenum(lua_State *L)
 			}
 		return 0;
 	}
-
-	if (fastcmp(word, "BT_USE")) // Remove case when 2.3 nears release...
-	{
-		lua_pushinteger(L, (lua_Integer)BT_SPIN);
+	else if ((!mathlib && LUA_PushGlobals(L, word)) || ScanConstants(L, mathlib, word))
 		return 1;
-	}
-
-	for (i = 0; INT_CONST[i].n; i++)
-		if (fastcmp(word,INT_CONST[i].n)) {
-			lua_pushinteger(L, INT_CONST[i].v);
-			return 1;
-		}
 
 	if (mathlib) return luaL_error(L, "constant '%s' could not be parsed.\n", word);
 
-	// DYNAMIC variables too!!
-	// Try not to add anything that would break netgames or timeattack replays here.
-	// You know, like consoleplayer, displayplayer, secondarydisplayplayer, or gametime.
-	return LUA_PushGlobals(L, word);
+	return 0;
+}
+
+// If a sprname has been "cached" to _G, update it to a new value.
+void LUA_UpdateSprName(const char *name, lua_Integer value)
+{
+	char fullname[9] = "SPR_XXXX";
+
+	if (!gL)
+		return;
+
+	strncpy(&fullname[4], name, 4);
+	lua_pushstring(gL, fullname);
+	lua_rawget(gL, LUA_GLOBALSINDEX);
+
+	if (!lua_isnil(gL, -1))
+	{
+		lua_pop(gL, 1);
+		lua_pushstring(gL, name);
+		lua_pushinteger(gL, value);
+		lua_rawset(gL, LUA_GLOBALSINDEX);
+	}
 }
 
 int LUA_EnumLib(lua_State *L)
diff --git a/src/deh_lua.h b/src/deh_lua.h
index 9df4028bdcf9619a14fe267d202aed2343125e2f..76c68860f3a1cb069d6f496c068881ec53aae673 100644
--- a/src/deh_lua.h
+++ b/src/deh_lua.h
@@ -13,6 +13,21 @@
 #ifndef __DEH_LUA_H__
 #define __DEH_LUA_H__
 
+#include "g_game.h"
+#include "s_sound.h"
+#include "z_zone.h"
+#include "m_menu.h"
+#include "m_misc.h"
+#include "p_local.h"
+#include "st_stuff.h"
+#include "fastcmp.h"
+#include "lua_script.h"
+#include "lua_libs.h"
+
+#include "dehacked.h"
+#include "deh_tables.h"
+
+void LUA_UpdateSprName(const char *name, lua_Integer value);
 boolean LUA_SetLuaAction(void *state, const char *actiontocompare);
 const char *LUA_GetActionName(void *action);
 void LUA_SetActionByName(void *state, const char *actiontocompare);
diff --git a/src/deh_soc.c b/src/deh_soc.c
index 3a611f3ba18daaacd3c9f5154505176f3a1ad4cd..e1979789e8774e41a7d3fd1a8d1ebfa3789f98cc 100644
--- a/src/deh_soc.c
+++ b/src/deh_soc.c
@@ -45,6 +45,7 @@
 #include "dehacked.h"
 #include "deh_soc.h"
 #include "deh_lua.h" // included due to some LUA_SetLuaAction hack smh
+// also used for LUA_UpdateSprName
 #include "deh_tables.h"
 
 // Loops through every constant and operation in word and performs its calculations, returning the final value.
@@ -439,6 +440,8 @@ void readfreeslots(MYFILE *f)
 					strncpy(sprnames[i],word,4);
 					//sprnames[i][4] = 0;
 					used_spr[(i-SPR_FIRSTFREESLOT)/8] |= 1<<(i%8); // Okay, this sprite slot has been named now.
+					// Lua needs to update the value in _G if it exists
+					LUA_UpdateSprName(word, i);
 					break;
 				}
 			}
diff --git a/src/lua_script.c b/src/lua_script.c
index a1376ca2e37fbdad25f9c2db6fb34907e87c8cdd..d7670fe35144be538d2691654be44dbfedffd502 100644
--- a/src/lua_script.c
+++ b/src/lua_script.c
@@ -694,20 +694,23 @@ void LUA_DumpFile(const char *filename)
 
 fixed_t LUA_EvalMath(const char *word)
 {
-	lua_State *L = NULL;
+	static lua_State *L = NULL;
 	char buf[1024], *b;
 	const char *p;
 	fixed_t res = 0;
 
-	// make a new state so SOC can't interefere with scripts
-	// allocate state
-	L = lua_newstate(LUA_Alloc, NULL);
-	lua_atpanic(L, LUA_Panic);
-
-	// open only enum lib
-	lua_pushcfunction(L, LUA_EnumLib);
-	lua_pushboolean(L, true);
-	lua_call(L, 1, 0);
+	if (!L)
+	{
+		// make a new state so SOC can't interefere with scripts
+		// allocate state
+		L = lua_newstate(LUA_Alloc, NULL);
+		lua_atpanic(L, LUA_Panic);
+
+		// open only enum lib
+		lua_pushcfunction(L, LUA_EnumLib);
+		lua_pushboolean(L, true);
+		lua_call(L, 1, 0);
+	}
 
 	// change ^ into ^^ for Lua.
 	strcpy(buf, "return ");
@@ -732,8 +735,6 @@ fixed_t LUA_EvalMath(const char *word)
 	else
 		res = lua_tointeger(L, -1);
 
-	// clean up and return.
-	lua_close(L);
 	return res;
 }