diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c
index 29e4970c1d3153536315e2d7151d0bf885854ad6..8175f1b9beacb2ac9e6920a66922c125d474500d 100644
--- a/src/lua_hudlib.c
+++ b/src/lua_hudlib.c
@@ -12,6 +12,7 @@
 
 #include "doomdef.h"
 #ifdef HAVE_BLUA
+#include "fastcmp.h"
 #include "r_defs.h"
 #include "r_local.h"
 #include "st_stuff.h" // hudinfo[]
@@ -343,6 +344,158 @@ static int libd_cachePatch(lua_State *L)
 	return 1;
 }
 
+// v.getSpritePatch(sprite, [frame, [angle]])
+static int libd_getSpritePatch(lua_State *L)
+{
+	UINT32 i; // sprite prefix
+	UINT32 frame = 0; // 'A'
+	UINT8 angle = 0;
+	spritedef_t *sprdef;
+	spriteframe_t *sprframe;
+	HUDONLY
+
+	if (lua_isnumber(L, 1)) // sprite number given, e.g. SPR_THOK
+	{
+		i = lua_tonumber(L, 1);
+		if (i >= NUMSPRITES)
+			return 0;
+	}
+	else if (lua_isstring(L, 1)) // sprite prefix name given, e.g. "THOK"
+	{
+		const char *name = lua_tostring(L, 1);
+		for (i = 0; i < NUMSPRITES; i++)
+			if (fastcmp(name, sprnames[i]))
+				break;
+		if (i >= NUMSPRITES)
+			return 0;
+	}
+	else
+		return 0;
+
+	if (i == SPR_PLAY) // Use getSprite2Patch instead!
+		return 0;
+
+	sprdef = &sprites[i];
+
+	// set frame number
+	frame = luaL_optinteger(L, 2, 0);
+	frame &= FF_FRAMEMASK; // ignore any bits that are not the actual frame, just in case
+	if (frame >= sprdef->numframes)
+		return 0;
+	// set angle number
+	sprframe = &sprdef->spriteframes[frame];
+	angle = luaL_optinteger(L, 3, 1);
+
+	// convert WAD editor angle numbers (1-8) to internal angle numbers (0-7)
+	// keep 0 the same since we'll make it default to angle 1 (which is internally 0)
+	// in case somebody didn't know that angle 0 really just maps all 8 angles to the same patch
+	if (angle != 0)
+		angle--;
+
+	if (angle >= 8) // out of range?
+		return 0;
+
+	// push both the patch and it's "flip" value
+	LUA_PushUserdata(L, W_CachePatchNum(sprframe->lumppat[angle], PU_STATIC), META_PATCH);
+	lua_pushboolean(L, (sprframe->flip & (1<<angle)) != 0);
+	return 2;
+}
+
+// v.getSprite2Patch(skin, sprite, [super?,] [frame, [angle]])
+static int libd_getSprite2Patch(lua_State *L)
+{
+	INT32 i; // skin number
+	UINT32 j; // sprite2 prefix
+	UINT32 frame = 0; // 'A'
+	UINT8 angle = 0;
+	spritedef_t *sprdef;
+	spriteframe_t *sprframe;
+	boolean super = false; // add FF_SPR2SUPER to sprite2 if true
+	HUDONLY
+
+	// get skin first!
+	if (lua_isnumber(L, 1)) // find skin by number
+	{
+		i = lua_tonumber(L, 1);
+		if (i < 0 || i >= MAXSKINS)
+			return luaL_error(L, "skin number %d out of range (0 - %d)", i, MAXSKINS-1);
+		if (i >= numskins)
+			return 0;
+	}
+	else // find skin by name
+	{
+		const char *name = luaL_checkstring(L, 1);
+		for (i = 0; i < numskins; i++)
+			if (fastcmp(skins[i].name, name))
+				break;
+		if (i >= numskins)
+			return 0;
+	}
+
+	lua_remove(L, 1); // remove skin now
+
+	if (lua_isnumber(L, 1)) // sprite number given, e.g. SPR2_STND
+	{
+		j = lua_tonumber(L, 1);
+		if (j & FF_SPR2SUPER) // e.g. SPR2_STND|FF_SPR2SUPER
+		{
+			super = true;
+			j &= ~FF_SPR2SUPER; // remove flag so the next check doesn't fail
+		}
+		if (j >= free_spr2)
+			return 0;
+	}
+	else if (lua_isstring(L, 1)) // sprite prefix name given, e.g. "STND"
+	{
+		const char *name = lua_tostring(L, 1);
+		for (j = 0; j < free_spr2; j++)
+			if (fastcmp(name, spr2names[j]))
+				break;
+		// if you want super flags you'll have to use the optional boolean following this
+		if (j >= free_spr2)
+			return 0;
+	}
+	else
+		return 0;
+
+	if (lua_isboolean(L, 2)) // optional boolean for superness
+	{
+		super = lua_toboolean(L, 2); // note: this can override FF_SPR2SUPER from sprite number
+		lua_remove(L, 2); // remove
+	}
+	// if it's not boolean then just assume it's the frame number
+
+	if (super)
+		j |= FF_SPR2SUPER;
+
+	j = P_GetSkinSprite2(&skins[i], j, NULL); // feed skin and current sprite2 through to change sprite2 used if necessary
+
+	sprdef = &skins[i].sprites[j];
+
+	// set frame number
+	frame = luaL_optinteger(L, 2, 0);
+	frame &= FF_FRAMEMASK; // ignore any bits that are not the actual frame, just in case
+	if (frame >= sprdef->numframes)
+		return 0;
+	// set angle number
+	sprframe = &sprdef->spriteframes[frame];
+	angle = luaL_optinteger(L, 3, 1);
+
+	// convert WAD editor angle numbers (1-8) to internal angle numbers (0-7)
+	// keep 0 the same since we'll make it default to angle 1 (which is internally 0)
+	// in case somebody didn't know that angle 0 really just maps all 8 angles to the same patch
+	if (angle != 0)
+		angle--;
+
+	if (angle >= 8) // out of range?
+		return 0;
+
+	// push both the patch and it's "flip" value
+	LUA_PushUserdata(L, W_CachePatchNum(sprframe->lumppat[angle], PU_STATIC), META_PATCH);
+	lua_pushboolean(L, (sprframe->flip & (1<<angle)) != 0);
+	return 2;
+}
+
 static int libd_draw(lua_State *L)
 {
 	INT32 x, y, flags;
@@ -568,6 +721,8 @@ static int libd_renderer(lua_State *L)
 static luaL_Reg lib_draw[] = {
 	{"patchExists", libd_patchExists},
 	{"cachePatch", libd_cachePatch},
+	{"getSpritePatch", libd_getSpritePatch},
+	{"getSprite2Patch", libd_getSprite2Patch},
 	{"draw", libd_draw},
 	{"drawScaled", libd_drawScaled},
 	{"drawNum", libd_drawNum},