diff --git a/SRB2.cbp b/SRB2.cbp
index 99a71226467e07aeb3e6f01f01cb99608bea6cf7..f56a9a16039c4981e0633d7e83374975e438b0f2 100644
--- a/SRB2.cbp
+++ b/SRB2.cbp
@@ -2561,6 +2561,21 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw64/DirectX" />
 			<Option target="Release Mingw64/DirectX" />
 		</Unit>
+		<Unit filename="src/lua_blockmaplib.c">
+			<Option compilerVar="CC" />
+			<Option target="Debug Native/SDL" />
+			<Option target="Release Native/SDL" />
+			<Option target="Debug Mingw/SDL" />
+			<Option target="Release Mingw/SDL" />
+			<Option target="Debug Mingw/DirectX" />
+			<Option target="Release Mingw/DirectX" />
+			<Option target="Debug Linux/SDL" />
+			<Option target="Release Linux/SDL" />
+			<Option target="Debug Mingw64/SDL" />
+			<Option target="Release Mingw64/SDL" />
+			<Option target="Debug Mingw64/DirectX" />
+			<Option target="Release Mingw64/DirectX" />
+		</Unit>
 		<Unit filename="src/lua_consolelib.c">
 			<Option compilerVar="CC" />
 			<Option target="Debug Native/SDL" />
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ba354c2899870ccb7d4d850863b6a20ebd618110..cc728a61363ae095ee6746cc36811c1d7f981731 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -231,6 +231,7 @@ if(${SRB2_CONFIG_HAVE_BLUA})
 	add_definitions(-DHAVE_BLUA)
 	set(SRB2_LUA_SOURCES
 		lua_baselib.c
+		lua_blockmaplib.c
 		lua_consolelib.c
 		lua_hooklib.c
 		lua_hudlib.c
diff --git a/src/blua/Makefile.cfg b/src/blua/Makefile.cfg
index e3fb3df4664e4943aff54361dd32be4500675bdd..8d2e7371428db75ced4042be0f33167a594d65f3 100644
--- a/src/blua/Makefile.cfg
+++ b/src/blua/Makefile.cfg
@@ -48,4 +48,5 @@ OBJS:=$(OBJS) \
 	$(OBJDIR)/lua_skinlib.o \
 	$(OBJDIR)/lua_thinkerlib.o \
 	$(OBJDIR)/lua_maplib.o \
+	$(OBJDIR)/lua_blockmaplib.o \
 	$(OBJDIR)/lua_hudlib.o
diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index 9eec5bc6e7dd0a561a770c9ad0ecc1ed7486a5b1..78e42f7a42e00c476cb709204a00ea340eb56786 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -28,7 +28,8 @@
 #define NOHUD if (hud_running) return luaL_error(L, "HUD rendering code should not call this function!");
 
 // uncomment if you want to test
- #define LUA_BLOCKMAP
+// note: now outdated
+//#define LUA_BLOCKMAP
 
 boolean luaL_checkboolean(lua_State *L, int narg) {
 	luaL_checktype(L, narg, LUA_TBOOLEAN);
diff --git a/src/lua_blockmaplib.c b/src/lua_blockmaplib.c
new file mode 100644
index 0000000000000000000000000000000000000000..f7ead76823873c73564f1ccbe804dfd85314af24
--- /dev/null
+++ b/src/lua_blockmaplib.c
@@ -0,0 +1,248 @@
+// SONIC ROBO BLAST 2
+//-----------------------------------------------------------------------------
+// Copyright (C) 2016 by Iestyn "Monster Iestyn" Jealous.
+// Copyright (C) 2016 by Sonic Team Junior.
+//
+// This program is free software distributed under the
+// terms of the GNU General Public License, version 2.
+// See the 'LICENSE' file for more details.
+//-----------------------------------------------------------------------------
+/// \file  lua_blockmaplib.c
+/// \brief blockmap library for Lua scripting
+
+#include "doomdef.h"
+#ifdef HAVE_BLUA
+#include "p_local.h"
+#include "r_main.h" // validcount
+#include "lua_script.h"
+#include "lua_libs.h"
+//#include "lua_hud.h" // hud_running errors
+
+static const char *const search_opt[] = {
+	"objects",
+	"lines",
+	NULL};
+
+// a quickly-made function pointer typedef used by lib_searchBlockmap...
+typedef boolean (*blockmap_func)(lua_State *, INT32, INT32, mobj_t *);
+
+static boolean blockfuncerror = false; // errors should only print once per search blockmap call
+
+// Helper function for "objects" search
+static boolean lib_searchBlockmap_Objects(lua_State *L, INT32 x, INT32 y, mobj_t *thing)
+{
+	mobj_t *mobj, *bnext = NULL;
+
+	if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)
+		return true;
+
+	// Check interaction with the objects in the blockmap.
+	for (mobj = blocklinks[y*bmapwidth + x]; mobj; mobj = bnext)
+	{
+		P_SetTarget(&bnext, mobj->bnext); // We want to note our reference to bnext here incase it is MF_NOTHINK and gets removed!
+		if (mobj == thing)
+			continue; // our thing just found itself, so move on
+		lua_pushvalue(L, 1); // push function
+		LUA_PushUserdata(L, thing, META_MOBJ);
+		LUA_PushUserdata(L, mobj, META_MOBJ);
+		if (lua_pcall(gL, 2, 1, 0)) {
+			if (!blockfuncerror || cv_debug & DBG_LUA)
+				CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+			lua_pop(gL, 1);
+			blockfuncerror = true;
+			return true;
+		}
+		if (!lua_isnil(gL, -1))
+		{ // if nil, continue
+			if (lua_toboolean(gL, -1))
+				return false;
+		}
+		lua_pop(gL, 1);
+		if (P_MobjWasRemoved(thing) // func just popped our thing, cannot continue.
+		|| (bnext && P_MobjWasRemoved(bnext))) // func just broke blockmap chain, cannot continue.
+		{
+			P_SetTarget(&bnext, NULL);
+			return true;
+		}
+	}
+	return true;
+}
+
+// Helper function for "lines" search
+static boolean lib_searchBlockmap_Lines(lua_State *L, INT32 x, INT32 y, mobj_t *thing)
+{
+	INT32 offset;
+	const INT32 *list; // Big blockmap
+#ifdef POLYOBJECTS
+	polymaplink_t *plink; // haleyjd 02/22/06
+#endif
+	line_t *ld;
+
+	if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)
+		return true;
+
+	offset = y*bmapwidth + x;
+
+#ifdef POLYOBJECTS
+	// haleyjd 02/22/06: consider polyobject lines
+	plink = polyblocklinks[offset];
+
+	while (plink)
+	{
+		polyobj_t *po = plink->po;
+
+		if (po->validcount != validcount) // if polyobj hasn't been checked
+		{
+			size_t i;
+			po->validcount = validcount;
+
+			for (i = 0; i < po->numLines; ++i)
+			{
+				if (po->lines[i]->validcount == validcount) // line has been checked
+					continue;
+				po->lines[i]->validcount = validcount;
+
+				lua_pushvalue(L, 1);
+				LUA_PushUserdata(L, thing, META_MOBJ);
+				LUA_PushUserdata(L, po->lines[i], META_LINE);
+				if (lua_pcall(gL, 2, 1, 0)) {
+					if (!blockfuncerror || cv_debug & DBG_LUA)
+						CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+					lua_pop(gL, 1);
+					blockfuncerror = true;
+					return true;
+				}
+				if (!lua_isnil(gL, -1))
+				{ // if nil, continue
+					if (lua_toboolean(gL, -1))
+						return false;
+				}
+				lua_pop(gL, 1);
+				if (P_MobjWasRemoved(thing))
+					return true;
+			}
+		}
+		plink = (polymaplink_t *)(plink->link.next);
+	}
+#endif
+
+	offset = *(blockmap + offset); // offset = blockmap[y*bmapwidth+x];
+
+	// First index is really empty, so +1 it.
+	for (list = blockmaplump + offset + 1; *list != -1; list++)
+	{
+		ld = &lines[*list];
+
+		if (ld->validcount == validcount)
+			continue; // Line has already been checked.
+
+		ld->validcount = validcount;
+
+		lua_pushvalue(L, 1);
+		LUA_PushUserdata(L, thing, META_MOBJ);
+		LUA_PushUserdata(L, ld, META_LINE);
+		if (lua_pcall(gL, 2, 1, 0)) {
+			if (!blockfuncerror || cv_debug & DBG_LUA)
+				CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+			lua_pop(gL, 1);
+			blockfuncerror = true;
+			return true;
+		}
+		if (!lua_isnil(gL, -1))
+		{ // if nil, continue
+			if (lua_toboolean(gL, -1))
+				return false;
+		}
+		lua_pop(gL, 1);
+		if (P_MobjWasRemoved(thing))
+			return true;
+	}
+	return true; // Everything was checked.
+}
+
+// The searchBlockmap function
+// arguments: searchBlockmap(searchtype, function, mobj, [x1, x2, y1, y2])
+// return value:
+//   true = search completely uninteruppted,
+//   false = searching of at least one block stopped mid-way (doesn't stop the whole search though)
+static int lib_searchBlockmap(lua_State *L)
+{
+	int searchtype = luaL_checkoption(L, 1, "objects", search_opt);
+	int n;
+	mobj_t *mobj;
+	INT32 xl, xh, yl, yh, bx, by;
+	fixed_t x1, x2, y1, y2;
+	boolean retval = true;
+	blockmap_func searchFunc;
+
+	lua_remove(L, 1); // remove searchtype, stack is now function, mobj, [x1, x2, y1, y2]
+	luaL_checktype(L, 1, LUA_TFUNCTION);
+
+	switch (searchtype)
+	{
+		case 0: // "objects"
+		default:
+			searchFunc = lib_searchBlockmap_Objects;
+			break;
+		case 1: // "lines"
+			searchFunc = lib_searchBlockmap_Lines;
+			break;
+	}
+
+	// the mobj we are searching around, the "calling" mobj we could say
+	mobj = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
+	if (!mobj)
+		return LUA_ErrInvalid(L, "mobj_t");
+
+	n = lua_gettop(L);
+
+	if (n > 2) // specific x/y ranges have been supplied
+	{
+		if (n < 6)
+			return luaL_error(L, "arguments 4 to 6 not all given (expected 4 fixed-point integers)");
+
+		x1 = luaL_checkfixed(L, 3);
+		x2 = luaL_checkfixed(L, 4);
+		y1 = luaL_checkfixed(L, 5);
+		y2 = luaL_checkfixed(L, 6);
+	}
+	else // mobj and function only - search around mobj's radius by default
+	{
+		fixed_t radius = mobj->radius + MAXRADIUS;
+		x1 = mobj->x - radius;
+		x2 = mobj->x + radius;
+		y1 = mobj->y - radius;
+		y2 = mobj->y + radius;
+	}
+	lua_settop(L, 2); // pop everything except function, mobj
+
+	xl = (unsigned)(x1 - bmaporgx)>>MAPBLOCKSHIFT;
+	xh = (unsigned)(x2 - bmaporgx)>>MAPBLOCKSHIFT;
+	yl = (unsigned)(y1 - bmaporgy)>>MAPBLOCKSHIFT;
+	yh = (unsigned)(y2 - bmaporgy)>>MAPBLOCKSHIFT;
+
+	BMBOUNDFIX(xl, xh, yl, yh);
+
+	blockfuncerror = false; // reset
+	validcount++;
+	for (bx = xl; bx <= xh; bx++)
+		for (by = yl; by <= yh; by++)
+		{
+			if (!searchFunc(L, bx, by, mobj))
+				retval = false;
+			if (P_MobjWasRemoved(mobj)){
+				lua_pushboolean(L, false);
+				return 1;
+			}	
+		}
+	lua_pushboolean(L, retval);
+	return 1;
+}
+
+int LUA_BlockmapLib(lua_State *L)
+{
+	lua_register(L, "searchBlockmap", lib_searchBlockmap);
+	return 0;
+}
+
+#endif
\ No newline at end of file
diff --git a/src/lua_libs.h b/src/lua_libs.h
index 8cca200861d890fa5fa18a190b15b77d670c40a5..fc8da25c11518e12513233b403ecfa4165861ae3 100644
--- a/src/lua_libs.h
+++ b/src/lua_libs.h
@@ -70,6 +70,7 @@ int LUA_PlayerLib(lua_State *L);
 int LUA_SkinLib(lua_State *L);
 int LUA_ThinkerLib(lua_State *L);
 int LUA_MapLib(lua_State *L);
+int LUA_BlockmapLib(lua_State *L);
 int LUA_HudLib(lua_State *L);
 
 #endif
diff --git a/src/lua_script.c b/src/lua_script.c
index 35d3fd51f178c6bf0acb8296b6e5bcd54b600850..6252330a4f4615748f7fa78ec4da0c79a7b8b259 100644
--- a/src/lua_script.c
+++ b/src/lua_script.c
@@ -48,6 +48,7 @@ static lua_CFunction liblist[] = {
 	LUA_SkinLib, // skin_t, skins[]
 	LUA_ThinkerLib, // thinker_t
 	LUA_MapLib, // line_t, side_t, sector_t, subsector_t
+	LUA_BlockmapLib, // blockmap stuff
 	LUA_HudLib, // HUD stuff
 	NULL
 };
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj
index 820192649d981adeaa477f0791d200f46d3ddfe9..abf6d76d2935d7546f445cf9b53880963d0b1433 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj
+++ b/src/sdl/Srb2SDL-vc10.vcxproj
@@ -295,6 +295,7 @@
     </ClCompile>
     <ClCompile Include="..\i_tcp.c" />
     <ClCompile Include="..\lua_baselib.c" />
+    <ClCompile Include="..\lua_blockmaplib.c" />
     <ClCompile Include="..\lua_consolelib.c" />
     <ClCompile Include="..\lua_hooklib.c" />
     <ClCompile Include="..\lua_hudlib.c" />
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters
index d04007dd77d026e48e8480bf93a54b86d279b7c5..bdb029cf9437e8c960a84a111bbcbfaf5dc9b82b 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj.filters
+++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters
@@ -633,6 +633,9 @@
     <ClCompile Include="..\lua_baselib.c">
       <Filter>LUA</Filter>
     </ClCompile>
+    <ClCompile Include="..\lua_blockmaplib.c">
+      <Filter>LUA</Filter>
+    </ClCompile>
     <ClCompile Include="..\lua_consolelib.c">
       <Filter>LUA</Filter>
     </ClCompile>
diff --git a/src/win32/Srb2win-vc10.vcxproj b/src/win32/Srb2win-vc10.vcxproj
index 064f75d7d06cdee1aa62d70dda03e9e28d53e6f2..95f9c85f94aeb1e6b62b2ac9447402a01c811840 100644
--- a/src/win32/Srb2win-vc10.vcxproj
+++ b/src/win32/Srb2win-vc10.vcxproj
@@ -131,6 +131,7 @@
     </ClCompile>
     <ClCompile Include="..\i_tcp.c" />
     <ClCompile Include="..\lua_baselib.c" />
+    <ClCompile Include="..\lua_blockmaplib.c" />
     <ClCompile Include="..\lua_consolelib.c" />
     <ClCompile Include="..\lua_hooklib.c" />
     <ClCompile Include="..\lua_hudlib.c" />
diff --git a/src/win32/Srb2win-vc10.vcxproj.filters b/src/win32/Srb2win-vc10.vcxproj.filters
index b2647ea1c21518389b7061276f6464d05998721b..cfd46f1f81d260f7f9645759f7601626c6a64dad 100644
--- a/src/win32/Srb2win-vc10.vcxproj.filters
+++ b/src/win32/Srb2win-vc10.vcxproj.filters
@@ -225,6 +225,9 @@
     <ClCompile Include="..\lua_baselib.c">
       <Filter>LUA</Filter>
     </ClCompile>
+    <ClCompile Include="..\lua_blockmaplib.c">
+      <Filter>LUA</Filter>
+    </ClCompile>
     <ClCompile Include="..\lua_consolelib.c">
       <Filter>LUA</Filter>
     </ClCompile>