diff --git a/src/g_game.c b/src/g_game.c
index b79eedadfaaace083a5034baaa3d3c1ac5bf7860..3709488b7fbc4be0f3c695fc31b4662d5769ea23 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -2331,6 +2331,11 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost)
 		}
 	}
 	P_MovePlayerToSpawn(playernum, spawnpoint);
+	
+#ifdef HAVE_BLUA 
+	LUAh_PlayerSpawn(&players[playernum]); // Lua hook for player spawning :)
+#endif
+
 }
 
 mapthing_t *G_FindCTFStart(INT32 playernum)
diff --git a/src/lua_hook.h b/src/lua_hook.h
index da2dcdc380461cefd958b9f42bfbe738a98d724b..4eb083780ea69e5d1674483e9ef83908a5dd9cba 100644
--- a/src/lua_hook.h
+++ b/src/lua_hook.h
@@ -42,6 +42,7 @@ enum hook {
 	hook_LinedefExecute,
 	hook_PlayerMsg,
 	hook_HurtMsg,
+	hook_PlayerSpawn,
 
 	hook_MAX // last hook
 };
@@ -75,5 +76,6 @@ boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd); // Hook for B_B
 boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector); // Hook for linedef executors
 boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg); // Hook for chat messages
 boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source); // Hook for hurt messages
+#define LUAh_PlayerSpawn(player) LUAh_PlayerHook(player, hook_PlayerSpawn) // Hook for G_SpawnPlayer 
 
 #endif
diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c
index 5230886a8bb4dbb174eec9c6c41b9cc0dfdf2577..2c1aa1cea97cffcaf833015ac8cacaa5f6395ce6 100644
--- a/src/lua_hooklib.c
+++ b/src/lua_hooklib.c
@@ -53,6 +53,7 @@ const char *const hookNames[hook_MAX+1] = {
 	"LinedefExecute",
 	"PlayerMsg",
 	"HurtMsg",
+	"PlayerSpawn",
 	NULL
 };
 
diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c
index 5a83d95b56a6a3a39cf7d0364c39a2866964dd26..325f00b013e5495f67d79b2ca78775e02812a4c6 100644
--- a/src/lua_hudlib.c
+++ b/src/lua_hudlib.c
@@ -16,7 +16,9 @@
 #include "r_local.h"
 #include "st_stuff.h" // hudinfo[]
 #include "g_game.h"
+#include "i_video.h" // rendermode
 #include "p_local.h" // camera_t
+#include "screen.h" // screen width/height
 #include "v_video.h"
 #include "w_wad.h"
 #include "z_zone.h"
@@ -486,7 +488,7 @@ static int libd_getColormap(lua_State *L)
 	INT32 skinnum = TC_DEFAULT;
 	skincolors_t color = luaL_optinteger(L, 2, 0);
 	UINT8* colormap = NULL;
-	//HUDSAFE
+	HUDONLY
 	if (lua_isnoneornil(L, 1))
 		; // defaults to TC_DEFAULT
 	else if (lua_type(L, 1) == LUA_TNUMBER) // skin number
@@ -510,6 +512,31 @@ static int libd_getColormap(lua_State *L)
 	return 1;
 }
 
+static int libd_width(lua_State *L)
+{
+	HUDONLY
+	lua_pushinteger(L, vid.width); // push screen width
+	return 1;
+}
+
+static int libd_height(lua_State *L)
+{
+	HUDONLY
+	lua_pushinteger(L, vid.height); // push screen height
+	return 1;
+}
+
+static int libd_renderer(lua_State *L)
+{
+	HUDONLY
+	switch (rendermode) {
+		case render_opengl: lua_pushliteral(L, "opengl");   break; // OpenGL renderer
+		case render_soft:   lua_pushliteral(L, "software"); break; // Software renderer
+		default:            lua_pushliteral(L, "none");     break; // render_none (for dedicated), in case there's any reason this should be run
+	}
+	return 1;
+}
+
 static luaL_Reg lib_draw[] = {
 	{"patchExists", libd_patchExists},
 	{"cachePatch", libd_cachePatch},
@@ -521,6 +548,9 @@ static luaL_Reg lib_draw[] = {
 	{"drawString", libd_drawString},
 	{"stringWidth", libd_stringWidth},
 	{"getColormap", libd_getColormap},
+	{"width", libd_width},
+	{"height", libd_height},
+	{"renderer", libd_renderer},
 	{NULL, NULL}
 };
 
diff --git a/src/lua_libs.h b/src/lua_libs.h
index d19ad88578de24bfa4a3f14163f2b39ac750c717..25552eacbe507a9c09f18007923959f0220a9e9a 100644
--- a/src/lua_libs.h
+++ b/src/lua_libs.h
@@ -42,6 +42,7 @@ extern lua_State *gL;
 
 #define META_CVAR "CONSVAR_T*"
 
+#define META_SECTORLINES "SECTOR_T*LINES"
 #define META_SIDENUM "LINE_T*SIDENUM"
 
 #define META_HUDINFO "HUDINFO_T*"
diff --git a/src/lua_maplib.c b/src/lua_maplib.c
index 0a5c5712a821a08110675e430b7967b60d773415..b6b5147a9abbfa939c14e3bb14a5f7bc0af9cf39 100644
--- a/src/lua_maplib.c
+++ b/src/lua_maplib.c
@@ -37,6 +37,7 @@ enum sector_e {
 	sector_thinglist,
 	sector_heightsec,
 	sector_camsec,
+	sector_lines,
 	sector_ffloors
 };
 
@@ -52,6 +53,7 @@ static const char *const sector_opt[] = {
 	"thinglist",
 	"heightsec",
 	"camsec",
+	"lines",
 	"ffloors",
 	NULL};
 
@@ -260,6 +262,67 @@ static int sector_iterate(lua_State *L)
 	return 3;
 }
 
+// sector.lines, i -> sector.lines[i]
+// sector.lines.valid, for validity checking
+static int sectorlines_get(lua_State *L)
+{
+	line_t **seclines = *((line_t ***)luaL_checkudata(L, 1, META_SECTORLINES));
+	size_t i;
+	size_t numoflines = 0;
+	lua_settop(L, 2);
+	if (!lua_isnumber(L, 2))
+	{
+		int field = luaL_checkoption(L, 2, NULL, valid_opt);
+		if (!seclines)
+		{
+			if (field == 0) {
+				lua_pushboolean(L, 0);
+				return 1;
+			}
+			return luaL_error(L, "accessed sector_t doesn't exist anymore.");
+		} else if (field == 0) {
+			lua_pushboolean(L, 1);
+			return 1;
+		}
+	}
+
+	// check first linedef to figure which of its sectors owns this sector->lines pointer
+	// then check that sector's linecount to get a maximum index
+	//if (!seclines[0])
+		//return luaL_error(L, "no lines found!"); // no first linedef?????
+	if (seclines[0]->frontsector->lines == seclines)
+		numoflines = seclines[0]->frontsector->linecount;
+	else if (seclines[0]->backsector && seclines[0]->backsector->lines == seclines) // check backsector exists first
+		numoflines = seclines[0]->backsector->linecount;
+	//if neither sector has it then ???
+
+	if (!numoflines)
+		return luaL_error(L, "no lines found!");
+
+	i = (size_t)lua_tointeger(L, 2);
+	if (i >= numoflines)
+		return 0;
+	LUA_PushUserdata(L, seclines[i], META_LINE);
+	return 1;
+}
+
+static int sectorlines_num(lua_State *L)
+{
+	line_t **seclines = *((line_t ***)luaL_checkudata(L, 1, META_SECTORLINES));
+	size_t numoflines = 0;
+	// check first linedef to figure which of its sectors owns this sector->lines pointer
+	// then check that sector's linecount to get a maximum index
+	//if (!seclines[0])
+		//return luaL_error(L, "no lines found!"); // no first linedef?????
+	if (seclines[0]->frontsector->lines == seclines)
+		numoflines = seclines[0]->frontsector->linecount;
+	else if (seclines[0]->backsector && seclines[0]->backsector->lines == seclines) // check backsector exists first
+		numoflines = seclines[0]->backsector->linecount;
+	//if neither sector has it then ???
+	lua_pushinteger(L, numoflines);
+	return 1;
+}
+
 static int sector_get(lua_State *L)
 {
 	sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
@@ -325,6 +388,9 @@ static int sector_get(lua_State *L)
 			return 0;
 		LUA_PushUserdata(L, &sectors[sector->camsec], META_SECTOR);
 		return 1;
+	case sector_lines: // lines
+		LUA_PushUserdata(L, sector->lines, META_SECTORLINES);
+		return 1;
 	case sector_ffloors: // ffloors
 		lua_pushcfunction(L, lib_iterateSectorFFloors);
 		LUA_PushUserdata(L, sector->ffloors, META_FFLOOR);
@@ -1234,6 +1300,14 @@ static int mapheaderinfo_get(lua_State *L)
 
 int LUA_MapLib(lua_State *L)
 {
+	luaL_newmetatable(L, META_SECTORLINES);
+		lua_pushcfunction(L, sectorlines_get);
+		lua_setfield(L, -2, "__index");
+
+		lua_pushcfunction(L, sectorlines_num);
+		lua_setfield(L, -2, "__len");
+	lua_pop(L, 1);
+
 	luaL_newmetatable(L, META_SECTOR);
 		lua_pushcfunction(L, sector_get);
 		lua_setfield(L, -2, "__index");
diff --git a/src/w_wad.c b/src/w_wad.c
index 9d6a11fb5c9f863def81c261a5893aa4aded98a8..132df8fcb838d97e0ad56e29ee19c269c5932459 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -32,6 +32,7 @@
 
 #include "w_wad.h"
 #include "z_zone.h"
+#include "fastcmp.h"
 
 #include "i_video.h" // rendermode
 #include "d_netfil.h"
@@ -147,24 +148,32 @@ static inline void W_LoadDehackedLumps(UINT16 wadnum)
 	}
 #endif
 
-	// Check for MAINCFG
-	for (lump = 0;lump != INT16_MAX;lump++)
-	{
-		lump = W_CheckNumForNamePwad("MAINCFG", wadnum, lump);
-		if (lump == INT16_MAX)
-			break;
-		CONS_Printf(M_GetText("Loading main config from %s\n"), wadfiles[wadnum]->filename);
-		DEH_LoadDehackedLumpPwad(wadnum, lump);
-	}
-
-	// Check for OBJCTCFG
-	for (lump = 0;lump < INT16_MAX;lump++)
 	{
-		lump = W_CheckNumForNamePwad("OBJCTCFG", wadnum, lump);
-		if (lump == INT16_MAX)
-			break;
-		CONS_Printf(M_GetText("Loading object config from %s\n"), wadfiles[wadnum]->filename);
-		DEH_LoadDehackedLumpPwad(wadnum, lump);
+		lumpinfo_t *lump_p = wadfiles[wadnum]->lumpinfo;
+		for (lump = 0; lump < wadfiles[wadnum]->numlumps; lump++, lump_p++)
+			if (memcmp(lump_p->name,"SOC_",4)==0) // Check for generic SOC lump
+			{	// shameless copy+paste of code from LUA_LoadLump
+				char *name = malloc(strlen(wadfiles[wadnum]->filename)+10);
+				strcpy(name, wadfiles[wadnum]->filename);
+				if (!fasticmp(&name[strlen(name) - 4], ".soc")) {
+					// If it's not a .soc file, copy the lump name in too.
+					name[strlen(wadfiles[wadnum]->filename)] = '|';
+					M_Memcpy(name+strlen(wadfiles[wadnum]->filename)+1, lump_p->name, 8);
+					name[strlen(wadfiles[wadnum]->filename)+9] = '\0';
+				}
+				CONS_Printf(M_GetText("Loading SOC from %s\n"), name);
+				DEH_LoadDehackedLumpPwad(wadnum, lump);
+			}
+			else if (memcmp(lump_p->name,"MAINCFG",8)==0) // Check for MAINCFG
+			{
+				CONS_Printf(M_GetText("Loading main config from %s\n"), wadfiles[wadnum]->filename);
+				DEH_LoadDehackedLumpPwad(wadnum, lump);
+			}
+			else if (memcmp(lump_p->name,"OBJCTCFG",8)==0) // Check for OBJCTCFG
+			{
+				CONS_Printf(M_GetText("Loading object config from %s\n"), wadfiles[wadnum]->filename);
+				DEH_LoadDehackedLumpPwad(wadnum, lump);
+			}
 	}
 
 #ifdef SCANTHINGS