diff --git a/src/blua/luaconf.h b/src/blua/luaconf.h
index 4fb9407996c3cd884f23fa87c9f5a415436d1177..9e2948f414bf771202b2d1b25e4d7378b086bda3 100644
--- a/src/blua/luaconf.h
+++ b/src/blua/luaconf.h
@@ -11,6 +11,13 @@
 #include <limits.h>
 #include <stddef.h>
 
+#ifdef _MSC_VER
+#define INT32 __int32
+#else
+#include <stdint.h>
+#define INT32 int32_t
+#endif
+
 
 /*
 ** ==================================================================
@@ -140,7 +147,7 @@
 ** CHANGE that if ptrdiff_t is not adequate on your machine. (On most
 ** machines, ptrdiff_t gives a good choice between int or long.)
 */
-#define LUA_INTEGER	ptrdiff_t
+#define LUA_INTEGER	INT32
 
 
 /*
@@ -502,13 +509,13 @@
 */
 
 //#define LUA_NUMBER_DOUBLE
-#define LUA_NUMBER	ptrdiff_t
+#define LUA_NUMBER	INT32
 
 /*
 @@ LUAI_UACNUMBER is the result of an 'usual argument conversion'
 @* over a number.
 */
-#define LUAI_UACNUMBER	ptrdiff_t
+#define LUAI_UACNUMBER	INT32
 
 
 /*
@@ -519,14 +526,14 @@
 @@ lua_str2number converts a string to a number.
 */
 #ifdef LUA_WIN
-	#define LUA_NUMBER_SCAN		"%Ii"
-	#define LUA_NUMBER_FMT		"%Ii"
+	#define LUA_NUMBER_SCAN		"%d"
+	#define LUA_NUMBER_FMT		"%d"
 #else
-	#define LUA_NUMBER_SCAN		"%ti"
-	#define LUA_NUMBER_FMT		"%ti"
+	#define LUA_NUMBER_SCAN		"%d"
+	#define LUA_NUMBER_FMT		"%d"
 #endif
 #define lua_number2str(s,n)	sprintf((s), LUA_NUMBER_FMT, (n))
-#define LUAI_MAXNUMBER2STR	32 /* 16 digits, sign, point, and \0 */
+#define LUAI_MAXNUMBER2STR	12 /* 10 digits, sign, and \0 */
 #define lua_str2number(s,p)	strtol((s), (p), 10)
 
 
diff --git a/src/d_main.c b/src/d_main.c
index 61255e2722574bc6e28a6acd2fa461913c4fd67b..3918d8118c0c1cfd242c70b7f04148b26612f8c8 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -96,6 +96,10 @@ int	snprintf(char *str, size_t n, const char *fmt, ...);
 #include "hardware/hw3sound.h"
 #endif
 
+#ifdef HAVE_BLUA
+#include "lua_script.h"
+#endif
+
 // platform independant focus loss
 UINT8 window_notinfocus = false;
 
@@ -634,6 +638,10 @@ void D_SRB2Loop(void)
 #ifdef HW3SOUND
 		HW3S_EndFrameUpdate();
 #endif
+
+#ifdef HAVE_BLUA
+		LUA_Step();
+#endif
 	}
 }
 
diff --git a/src/dehacked.c b/src/dehacked.c
index 72c9b28d0ebee440863390bf3c2e74191ed429c0..6b7900f76e1ddea4fa7154afb4c9b0b42345e9ea 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -7757,36 +7757,36 @@ struct {
 	{"FF_GOOWATER",FF_GOOWATER},               ///< Used with ::FF_SWIMMABLE. Makes thick bouncey goop.
 
 	// Angles
-	{"ANG1",ANG1},
-	{"ANG2",ANG2},
-	{"ANG10",ANG10},
-	{"ANG15",ANG15},
-	{"ANG20",ANG20},
-	{"ANG30",ANG30},
-	{"ANG60",ANG60},
-	{"ANG64h",ANG64h},
-	{"ANG105",ANG105},
-	{"ANG210",ANG210},
-	{"ANG255",ANG255},
-	{"ANG340",ANG340},
-	{"ANG350",ANG350},
-	{"ANGLE_11hh",ANGLE_11hh},
-	{"ANGLE_22h",ANGLE_22h},
-	{"ANGLE_45",ANGLE_45},
-	{"ANGLE_67h",ANGLE_67h},
-	{"ANGLE_90",ANGLE_90},
-	{"ANGLE_112h",ANGLE_112h},
-	{"ANGLE_135",ANGLE_135},
-	{"ANGLE_157h",ANGLE_157h},
-	{"ANGLE_180",ANGLE_180},
-	{"ANGLE_202h",ANGLE_202h},
-	{"ANGLE_225",ANGLE_225},
-	{"ANGLE_247h",ANGLE_247h},
-	{"ANGLE_270",ANGLE_270},
-	{"ANGLE_292h",ANGLE_292h},
-	{"ANGLE_315",ANGLE_315},
-	{"ANGLE_337h",ANGLE_337h},
-	{"ANGLE_MAX",ANGLE_MAX},
+	{"ANG1",ANG1>>16},
+	{"ANG2",ANG2>>16},
+	{"ANG10",ANG10>>16},
+	{"ANG15",ANG15>>16},
+	{"ANG20",ANG20>>16},
+	{"ANG30",ANG30>>16},
+	{"ANG60",ANG60>>16},
+	{"ANG64h",ANG64h>>16},
+	{"ANG105",ANG105>>16},
+	{"ANG210",ANG210>>16},
+	{"ANG255",ANG255>>16},
+	{"ANG340",ANG340>>16},
+	{"ANG350",ANG350>>16},
+	{"ANGLE_11hh",ANGLE_11hh>>16},
+	{"ANGLE_22h",ANGLE_22h>>16},
+	{"ANGLE_45",ANGLE_45>>16},
+	{"ANGLE_67h",ANGLE_67h>>16},
+	{"ANGLE_90",ANGLE_90>>16},
+	{"ANGLE_112h",ANGLE_112h>>16},
+	{"ANGLE_135",ANGLE_135>>16},
+	{"ANGLE_157h",ANGLE_157h>>16},
+	{"ANGLE_180",ANGLE_180>>16},
+	{"ANGLE_202h",ANGLE_202h>>16},
+	{"ANGLE_225",ANGLE_225>>16},
+	{"ANGLE_247h",ANGLE_247h>>16},
+	{"ANGLE_270",ANGLE_270>>16},
+	{"ANGLE_292h",ANGLE_292h>>16},
+	{"ANGLE_315",ANGLE_315>>16},
+	{"ANGLE_337h",ANGLE_337h>>16},
+	{"ANGLE_MAX",ANGLE_MAX>>16},
 
 	// P_Chase directions (dirtype_t)
 	{"DI_NODIR",DI_NODIR},
diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index ad5d740f8edbb1da5521971fc2844c57436f4e90..d76839e73b6b95f7e8a1ae91c1d36a190f94787c 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -85,13 +85,6 @@ static int lib_print(lua_State *L)
 	return 0;
 }
 
-static int lib_evalMath(lua_State *L)
-{
-	const char *word = luaL_checkstring(L, 1);
-	lua_pushinteger(L, LUA_EvalMath(word));
-	return 1;
-}
-
 // M_RANDOM
 //////////////
 
@@ -138,25 +131,25 @@ static int lib_pRandomRange(lua_State *L)
 
 static int lib_pAproxDistance(lua_State *L)
 {
-	fixed_t dx = (fixed_t)luaL_checkinteger(L, 1);
-	fixed_t dy = (fixed_t)luaL_checkinteger(L, 2);
+	fixed_t dx = luaL_checkfixed(L, 1);
+	fixed_t dy = luaL_checkfixed(L, 2);
 	//HUDSAFE
-	lua_pushinteger(L, P_AproxDistance(dx, dy));
+	lua_pushfixed(L, P_AproxDistance(dx, dy));
 	return 1;
 }
 
 static int lib_pClosestPointOnLine(lua_State *L)
 {
-	fixed_t x = (fixed_t)luaL_checkinteger(L, 1);
-	fixed_t y = (fixed_t)luaL_checkinteger(L, 2);
+	fixed_t x = luaL_checkfixed(L, 1);
+	fixed_t y = luaL_checkfixed(L, 2);
 	line_t *line = *((line_t **)luaL_checkudata(L, 3, META_LINE));
 	vertex_t result;
 	//HUDSAFE
 	if (!line)
 		return LUA_ErrInvalid(L, "line_t");
 	P_ClosestPointOnLine(x, y, line, &result);
-	lua_pushinteger(L, result.x);
-	lua_pushinteger(L, result.y);
+	lua_pushfixed(L, result.x);
+	lua_pushfixed(L, result.y);
 	return 2;
 }
 
@@ -241,9 +234,9 @@ static int lib_pLookForPlayers(lua_State *L)
 
 static int lib_pSpawnMobj(lua_State *L)
 {
-	fixed_t x = (fixed_t)luaL_checkinteger(L, 1);
-	fixed_t y = (fixed_t)luaL_checkinteger(L, 2);
-	fixed_t z = (fixed_t)luaL_checkinteger(L, 3);
+	fixed_t x = luaL_checkfixed(L, 1);
+	fixed_t y = luaL_checkfixed(L, 2);
+	fixed_t z = luaL_checkfixed(L, 3);
 	mobjtype_t type = luaL_checkinteger(L, 4);
 	NOHUD
 	if (type > MT_LASTFREESLOT)
@@ -283,9 +276,9 @@ static int lib_pSpawnXYZMissile(lua_State *L)
 	mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
 	mobj_t *dest = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
 	mobjtype_t type = luaL_checkinteger(L, 3);
-	fixed_t x = (fixed_t)luaL_checkinteger(L, 4);
-	fixed_t y = (fixed_t)luaL_checkinteger(L, 5);
-	fixed_t z = (fixed_t)luaL_checkinteger(L, 6);
+	fixed_t x = luaL_checkfixed(L, 4);
+	fixed_t y = luaL_checkfixed(L, 5);
+	fixed_t z = luaL_checkfixed(L, 6);
 	NOHUD
 	if (!source || !dest)
 		return LUA_ErrInvalid(L, "mobj_t");
@@ -298,13 +291,13 @@ static int lib_pSpawnXYZMissile(lua_State *L)
 static int lib_pSpawnPointMissile(lua_State *L)
 {
 	mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
-	fixed_t xa = (fixed_t)luaL_checkinteger(L, 2);
-	fixed_t ya = (fixed_t)luaL_checkinteger(L, 3);
-	fixed_t za = (fixed_t)luaL_checkinteger(L, 4);
+	fixed_t xa = luaL_checkfixed(L, 2);
+	fixed_t ya = luaL_checkfixed(L, 3);
+	fixed_t za = luaL_checkfixed(L, 4);
 	mobjtype_t type = luaL_checkinteger(L, 5);
-	fixed_t x = (fixed_t)luaL_checkinteger(L, 6);
-	fixed_t y = (fixed_t)luaL_checkinteger(L, 7);
-	fixed_t z = (fixed_t)luaL_checkinteger(L, 8);
+	fixed_t x = luaL_checkfixed(L, 6);
+	fixed_t y = luaL_checkfixed(L, 7);
+	fixed_t z = luaL_checkfixed(L, 8);
 	NOHUD
 	if (!source)
 		return LUA_ErrInvalid(L, "mobj_t");
@@ -318,9 +311,9 @@ static int lib_pSpawnAlteredDirectionMissile(lua_State *L)
 {
 	mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
 	mobjtype_t type = luaL_checkinteger(L, 2);
-	fixed_t x = (fixed_t)luaL_checkinteger(L, 3);
-	fixed_t y = (fixed_t)luaL_checkinteger(L, 4);
-	fixed_t z = (fixed_t)luaL_checkinteger(L, 5);
+	fixed_t x = luaL_checkfixed(L, 3);
+	fixed_t y = luaL_checkfixed(L, 4);
+	fixed_t z = luaL_checkfixed(L, 5);
 	INT32 shiftingAngle = (INT32)luaL_checkinteger(L, 5);
 	NOHUD
 	if (!source)
@@ -348,7 +341,7 @@ static int lib_pSPMAngle(lua_State *L)
 {
 	mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
 	mobjtype_t type = luaL_checkinteger(L, 2);
-	angle_t angle = (angle_t)luaL_checkinteger(L, 3);
+	angle_t angle = luaL_checkangle(L, 3);
 	UINT8 allowaim = (UINT8)luaL_optinteger(L, 4, 0);
 	UINT32 flags2 = (UINT32)luaL_optinteger(L, 5, 0);
 	NOHUD
@@ -418,13 +411,13 @@ static int lib_pGetClosestAxis(lua_State *L)
 
 static int lib_pSpawnParaloop(lua_State *L)
 {
-	fixed_t x = (fixed_t)luaL_checkinteger(L, 1);
-	fixed_t y = (fixed_t)luaL_checkinteger(L, 2);
-	fixed_t z = (fixed_t)luaL_checkinteger(L, 3);
-	fixed_t radius = (fixed_t)luaL_checkinteger(L, 4);
+	fixed_t x = luaL_checkfixed(L, 1);
+	fixed_t y = luaL_checkfixed(L, 2);
+	fixed_t z = luaL_checkfixed(L, 3);
+	fixed_t radius = luaL_checkfixed(L, 4);
 	INT32 number = (INT32)luaL_checkinteger(L, 5);
 	mobjtype_t type = luaL_checkinteger(L, 6);
-	angle_t rotangle = (angle_t)luaL_checkinteger(L, 7);
+	angle_t rotangle = luaL_checkangle(L, 7);
 	statenum_t nstate = luaL_optinteger(L, 8, S_NULL);
 	boolean spawncenter = lua_optboolean(L, 9);
 	NOHUD
@@ -458,7 +451,7 @@ static int lib_pSupermanLook4Players(lua_State *L)
 static int lib_pSetScale(lua_State *L)
 {
 	mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
-	fixed_t newscale = (fixed_t)luaL_checkinteger(L, 2);
+	fixed_t newscale = luaL_checkfixed(L, 2);
 	NOHUD
 	if (!mobj)
 		return LUA_ErrInvalid(L, "mobj_t");
@@ -526,7 +519,7 @@ static int lib_pGetPlayerHeight(lua_State *L)
 	//HUDSAFE
 	if (!player)
 		return LUA_ErrInvalid(L, "player_t");
-	lua_pushinteger(L, P_GetPlayerHeight(player));
+	lua_pushfixed(L, P_GetPlayerHeight(player));
 	return 1;
 }
 
@@ -536,7 +529,7 @@ static int lib_pGetPlayerSpinHeight(lua_State *L)
 	//HUDSAFE
 	if (!player)
 		return LUA_ErrInvalid(L, "player_t");
-	lua_pushinteger(L, P_GetPlayerSpinHeight(player));
+	lua_pushfixed(L, P_GetPlayerSpinHeight(player));
 	return 1;
 }
 
@@ -639,7 +632,7 @@ static int lib_pInQuicksand(lua_State *L)
 static int lib_pSetObjectMomZ(lua_State *L)
 {
 	mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
-	fixed_t value = (fixed_t)luaL_checkinteger(L, 2);
+	fixed_t value = luaL_checkfixed(L, 2);
 	boolean relative = lua_optboolean(L, 3);
 	NOHUD
 	if (!mo)
@@ -753,8 +746,8 @@ static int lib_pDoPlayerExit(lua_State *L)
 static int lib_pInstaThrust(lua_State *L)
 {
 	mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
-	angle_t angle = (angle_t)luaL_checkinteger(L, 2);
-	fixed_t move = (fixed_t)luaL_checkinteger(L, 3);
+	angle_t angle = luaL_checkangle(L, 2);
+	fixed_t move = luaL_checkfixed(L, 3);
 	NOHUD
 	if (!mo)
 		return LUA_ErrInvalid(L, "mobj_t");
@@ -768,10 +761,10 @@ static int lib_pReturnThrustX(lua_State *L)
 	fixed_t move;
 	if (lua_isnil(L, 1) || lua_isuserdata(L, 1))
 		lua_remove(L, 1); // ignore mobj as arg1
-	angle = (angle_t)luaL_checkinteger(L, 1);
-	move = (fixed_t)luaL_checkinteger(L, 2);
+	angle = luaL_checkangle(L, 1);
+	move = luaL_checkfixed(L, 2);
 	//HUDSAFE
-	lua_pushinteger(L, P_ReturnThrustX(NULL, angle, move));
+	lua_pushfixed(L, P_ReturnThrustX(NULL, angle, move));
 	return 1;
 }
 
@@ -781,10 +774,10 @@ static int lib_pReturnThrustY(lua_State *L)
 	fixed_t move;
 	if (lua_isnil(L, 1) || lua_isuserdata(L, 1))
 		lua_remove(L, 1); // ignore mobj as arg1
-	angle = (angle_t)luaL_checkinteger(L, 1);
-	move = (fixed_t)luaL_checkinteger(L, 2);
+	angle = luaL_checkangle(L, 1);
+	move = luaL_checkfixed(L, 2);
 	//HUDSAFE
-	lua_pushinteger(L, P_ReturnThrustY(NULL, angle, move));
+	lua_pushfixed(L, P_ReturnThrustY(NULL, angle, move));
 	return 1;
 }
 
@@ -802,7 +795,7 @@ static int lib_pNukeEnemies(lua_State *L)
 {
 	mobj_t *inflictor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
 	mobj_t *source = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
-	fixed_t radius = (fixed_t)luaL_checkinteger(L, 3);
+	fixed_t radius = luaL_checkfixed(L, 3);
 	NOHUD
 	if (!inflictor || !source)
 		return LUA_ErrInvalid(L, "mobj_t");
@@ -868,8 +861,8 @@ static int lib_pSpawnSpinMobj(lua_State *L)
 static int lib_pTelekinesis(lua_State *L)
 {
 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
-	fixed_t thrust = (fixed_t)luaL_checkinteger(L, 2);
-	fixed_t range = (fixed_t)luaL_checkinteger(L, 3);
+	fixed_t thrust = luaL_checkfixed(L, 2);
+	fixed_t range = luaL_checkfixed(L, 3);
 	NOHUD
 	if (!player)
 		return LUA_ErrInvalid(L, "player_t");
@@ -884,8 +877,8 @@ static int lib_pCheckPosition(lua_State *L)
 {
 	mobj_t *ptmthing = tmthing;
 	mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
-	fixed_t x = (fixed_t)luaL_checkinteger(L, 2);
-	fixed_t y = (fixed_t)luaL_checkinteger(L, 3);
+	fixed_t x = luaL_checkfixed(L, 2);
+	fixed_t y = luaL_checkfixed(L, 3);
 	NOHUD
 	if (!thing)
 		return LUA_ErrInvalid(L, "mobj_t");
@@ -899,8 +892,8 @@ static int lib_pTryMove(lua_State *L)
 {
 	mobj_t *ptmthing = tmthing;
 	mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
-	fixed_t x = (fixed_t)luaL_checkinteger(L, 2);
-	fixed_t y = (fixed_t)luaL_checkinteger(L, 3);
+	fixed_t x = luaL_checkfixed(L, 2);
+	fixed_t y = luaL_checkfixed(L, 3);
 	boolean allowdropoff = lua_optboolean(L, 4);
 	NOHUD
 	if (!thing)
@@ -915,7 +908,7 @@ static int lib_pMove(lua_State *L)
 {
 	mobj_t *ptmthing = tmthing;
 	mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
-	fixed_t speed = (fixed_t)luaL_checkinteger(L, 2);
+	fixed_t speed = luaL_checkfixed(L, 2);
 	NOHUD
 	if (!actor)
 		return LUA_ErrInvalid(L, "mobj_t");
@@ -929,9 +922,9 @@ static int lib_pTeleportMove(lua_State *L)
 {
 	mobj_t *ptmthing = tmthing;
 	mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
-	fixed_t x = (fixed_t)luaL_checkinteger(L, 2);
-	fixed_t y = (fixed_t)luaL_checkinteger(L, 3);
-	fixed_t z = (fixed_t)luaL_checkinteger(L, 4);
+	fixed_t x = luaL_checkfixed(L, 2);
+	fixed_t y = luaL_checkfixed(L, 3);
+	fixed_t z = luaL_checkfixed(L, 4);
 	NOHUD
 	if (!thing)
 		return LUA_ErrInvalid(L, "mobj_t");
@@ -975,10 +968,10 @@ static int lib_pCheckSight(lua_State *L)
 static int lib_pCheckHoopPosition(lua_State *L)
 {
 	mobj_t *hoopthing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
-	fixed_t x = (fixed_t)luaL_checkinteger(L, 2);
-	fixed_t y = (fixed_t)luaL_checkinteger(L, 3);
-	fixed_t z = (fixed_t)luaL_checkinteger(L, 4);
-	fixed_t radius = (fixed_t)luaL_checkinteger(L, 5);
+	fixed_t x = luaL_checkfixed(L, 2);
+	fixed_t y = luaL_checkfixed(L, 3);
+	fixed_t z = luaL_checkfixed(L, 4);
+	fixed_t radius = luaL_checkfixed(L, 5);
 	NOHUD
 	if (!hoopthing)
 		return LUA_ErrInvalid(L, "mobj_t");
@@ -990,7 +983,7 @@ static int lib_pRadiusAttack(lua_State *L)
 {
 	mobj_t *spot = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
 	mobj_t *source = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
-	fixed_t damagedist = (fixed_t)luaL_checkinteger(L, 3);
+	fixed_t damagedist = luaL_checkfixed(L, 3);
 	NOHUD
 	if (!spot || !source)
 		return LUA_ErrInvalid(L, "mobj_t");
@@ -1000,12 +993,12 @@ static int lib_pRadiusAttack(lua_State *L)
 
 static int lib_pFloorzAtPos(lua_State *L)
 {
-	fixed_t x = (fixed_t)luaL_checkinteger(L, 1);
-	fixed_t y = (fixed_t)luaL_checkinteger(L, 2);
-	fixed_t z = (fixed_t)luaL_checkinteger(L, 3);
-	fixed_t height = (fixed_t)luaL_checkinteger(L, 4);
+	fixed_t x = luaL_checkfixed(L, 1);
+	fixed_t y = luaL_checkfixed(L, 2);
+	fixed_t z = luaL_checkfixed(L, 3);
+	fixed_t height = luaL_checkfixed(L, 4);
 	//HUDSAFE
-	lua_pushinteger(L, P_FloorzAtPos(x, y, z, height));
+	lua_pushfixed(L, P_FloorzAtPos(x, y, z, height));
 	return 1;
 }
 
@@ -1209,8 +1202,8 @@ static int lib_pDoNightsScore(lua_State *L)
 static int lib_pThrust(lua_State *L)
 {
 	mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
-	angle_t angle = (angle_t)luaL_checkinteger(L, 2);
-	fixed_t move = (fixed_t)luaL_checkinteger(L, 3);
+	angle_t angle = luaL_checkangle(L, 2);
+	fixed_t move = luaL_checkfixed(L, 3);
 	NOHUD
 	if (!mo)
 		return LUA_ErrInvalid(L, "mobj_t");
@@ -1485,48 +1478,48 @@ static int lib_evCrumbleChain(lua_State *L)
 
 static int lib_rPointToAngle(lua_State *L)
 {
-	fixed_t x = (fixed_t)luaL_checkinteger(L, 1);
-	fixed_t y = (fixed_t)luaL_checkinteger(L, 2);
+	fixed_t x = luaL_checkfixed(L, 1);
+	fixed_t y = luaL_checkfixed(L, 2);
 	//HUDSAFE
-	lua_pushinteger(L, R_PointToAngle(x, y));
+	lua_pushangle(L, R_PointToAngle(x, y));
 	return 1;
 }
 
 static int lib_rPointToAngle2(lua_State *L)
 {
-	fixed_t px2 = (fixed_t)luaL_checkinteger(L, 1);
-	fixed_t py2 = (fixed_t)luaL_checkinteger(L, 2);
-	fixed_t px1 = (fixed_t)luaL_checkinteger(L, 3);
-	fixed_t py1 = (fixed_t)luaL_checkinteger(L, 4);
+	fixed_t px2 = luaL_checkfixed(L, 1);
+	fixed_t py2 = luaL_checkfixed(L, 2);
+	fixed_t px1 = luaL_checkfixed(L, 3);
+	fixed_t py1 = luaL_checkfixed(L, 4);
 	//HUDSAFE
-	lua_pushinteger(L, R_PointToAngle2(px2, py2, px1, py1));
+	lua_pushangle(L, R_PointToAngle2(px2, py2, px1, py1));
 	return 1;
 }
 
 static int lib_rPointToDist(lua_State *L)
 {
-	fixed_t x = (fixed_t)luaL_checkinteger(L, 1);
-	fixed_t y = (fixed_t)luaL_checkinteger(L, 2);
+	fixed_t x = luaL_checkfixed(L, 1);
+	fixed_t y = luaL_checkfixed(L, 2);
 	//HUDSAFE
-	lua_pushinteger(L, R_PointToDist(x, y));
+	lua_pushfixed(L, R_PointToDist(x, y));
 	return 1;
 }
 
 static int lib_rPointToDist2(lua_State *L)
 {
-	fixed_t px2 = (fixed_t)luaL_checkinteger(L, 1);
-	fixed_t py2 = (fixed_t)luaL_checkinteger(L, 2);
-	fixed_t px1 = (fixed_t)luaL_checkinteger(L, 3);
-	fixed_t py1 = (fixed_t)luaL_checkinteger(L, 4);
+	fixed_t px2 = luaL_checkfixed(L, 1);
+	fixed_t py2 = luaL_checkfixed(L, 2);
+	fixed_t px1 = luaL_checkfixed(L, 3);
+	fixed_t py1 = luaL_checkfixed(L, 4);
 	//HUDSAFE
-	lua_pushinteger(L, R_PointToDist2(px2, py2, px1, py1));
+	lua_pushfixed(L, R_PointToDist2(px2, py2, px1, py1));
 	return 1;
 }
 
 static int lib_rPointInSubsector(lua_State *L)
 {
-	fixed_t x = (fixed_t)luaL_checkinteger(L, 1);
-	fixed_t y = (fixed_t)luaL_checkinteger(L, 2);
+	fixed_t x = luaL_checkfixed(L, 1);
+	fixed_t y = luaL_checkfixed(L, 2);
 	//HUDSAFE
 	LUA_PushUserdata(L, R_PointInSubsector(x, y), META_SUBSECTOR);
 	return 1;
@@ -1660,7 +1653,7 @@ static int lib_sChangeMusic(lua_State *L)
 
 static int lib_sSpeedMusic(lua_State *L)
 {
-	fixed_t fixedspeed = (fixed_t)luaL_checkinteger(L, 1);
+	fixed_t fixedspeed = luaL_checkfixed(L, 1);
 	float speed = FIXED_TO_FLOAT(fixedspeed);
 	player_t *player = NULL;
 	NOHUD
@@ -1861,7 +1854,6 @@ static int lib_gTicsToMilliseconds(lua_State *L)
 
 static luaL_Reg lib[] = {
 	{"print", lib_print},
-	{"EvalMath", lib_evalMath},
 
 	// m_random
 	{"P_Random",lib_pRandom},
diff --git a/src/lua_hook.h b/src/lua_hook.h
index fae3bb7e6d1672a50f72d7d5e58c524bb65317c1..da2dcdc380461cefd958b9f42bfbe738a98d724b 100644
--- a/src/lua_hook.h
+++ b/src/lua_hook.h
@@ -41,7 +41,7 @@ enum hook {
 	hook_BotAI,
 	hook_LinedefExecute,
 	hook_PlayerMsg,
-	hook_DeathMsg,
+	hook_HurtMsg,
 
 	hook_MAX // last hook
 };
@@ -54,8 +54,9 @@ void LUAh_ThinkFrame(void); // Hook for frame (after mobj and player thinkers)
 boolean LUAh_MobjHook(mobj_t *mo, enum hook which);
 boolean LUAh_PlayerHook(player_t *plr, enum hook which);
 #define LUAh_MobjSpawn(mo) LUAh_MobjHook(mo, hook_MobjSpawn) // Hook for P_SpawnMobj by mobj type
-UINT8 LUAh_MobjCollide(mobj_t *thing1, mobj_t *thing2); // Hook for PIT_CheckThing by (thing) mobj type
-UINT8 LUAh_MobjMoveCollide(mobj_t *thing1, mobj_t *thing2); // Hook for PIT_CheckThing by (tmthing) mobj type
+UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which);
+#define LUAh_MobjCollide(thing1, thing2) LUAh_MobjCollideHook(thing1, thing2, hook_MobjCollide) // Hook for PIT_CheckThing by (thing) mobj type
+#define LUAh_MobjMoveCollide(thing1, thing2) LUAh_MobjCollideHook(thing1, thing2, hook_MobjMoveCollide) // Hook for PIT_CheckThing by (tmthing) mobj type
 boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher); // Hook for P_TouchSpecialThing by mobj type
 #define LUAh_MobjFuse(mo) LUAh_MobjHook(mo, hook_MobjFuse) // Hook for mobj->fuse == 0 by mobj type
 #define LUAh_MobjThinker(mo) LUAh_MobjHook(mo, hook_MobjThinker) // Hook for P_MobjThinker or P_SceneryThinker by mobj type
@@ -73,6 +74,6 @@ boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd); // Hook for B_BuildTiccmd
 boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd); // Hook for B_BuildTailsTiccmd by skin name
 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_DeathMsg(player_t *player, mobj_t *inflictor, mobj_t *source); // Hook for hurt messages
+boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source); // Hook for hurt messages
 
 #endif
diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c
index 532726ac223afa4d686029cc0917731e405c0cfc..0415d23e61acfe98705ec8855846b06297fcdf02 100644
--- a/src/lua_hooklib.c
+++ b/src/lua_hooklib.c
@@ -56,23 +56,40 @@ const char *const hookNames[hook_MAX+1] = {
 	NULL
 };
 
+// Hook metadata
+struct hook_s
+{
+	struct hook_s *next;
+	enum hook type;
+	UINT16 id;
+	union {
+		mobjtype_t mt;
+		char *skinname;
+		char *funcname;
+	} s;
+	boolean error;
+};
+typedef struct hook_s* hook_p;
+
+#define FMT_HOOKID "hook_%d"
+
+hook_p roothook;
+
 // Takes hook, function, and additional arguments (mobj type to act on, etc.)
 static int lib_addHook(lua_State *L)
 {
-	UINT16 hook;
-	boolean notable = false;
-	boolean subtable = false;
-	UINT32 subindex = 0;
-	char *subfield = NULL;
-	const char *lsubfield = NULL;
+	static struct hook_s hook = {NULL, 0, 0, {0}, false};
+	hook_p hookp, *lastp;
+
+	hook.type = luaL_checkoption(L, 1, NULL, hookNames);
+	lua_remove(L, 1);
 
-	hook = (UINT16)luaL_checkoption(L, 1, NULL, hookNames);
-	luaL_checktype(L, 2, LUA_TFUNCTION);
+	luaL_checktype(L, 1, LUA_TFUNCTION);
 
 	if (hud_running)
 		return luaL_error(L, "HUD rendering code should not call this function!");
 
-	switch(hook)
+	switch(hook.type)
 	{
 	// Take a mobjtype enum which this hook is specifically for.
 	case hook_MobjSpawn:
@@ -87,918 +104,668 @@ static int lib_addHook(lua_State *L)
 	case hook_MobjDeath:
 	case hook_BossDeath:
 	case hook_MobjRemoved:
-		subtable = true;
-		if (lua_isnumber(L, 3))
-			subindex = (UINT32)luaL_checkinteger(L, 3);
-		else
-			lsubfield = "a";
-		lua_settop(L, 2);
+	case hook_HurtMsg:
+		hook.s.mt = MT_NULL;
+		if (lua_isnumber(L, 2))
+			hook.s.mt = lua_tonumber(L, 2);
 		break;
-	case hook_BotAI: // Only one AI function per skin, please!
-		notable = true;
-		subtable = true;
-		subfield = ZZ_Alloc(strlen(luaL_checkstring(L, 3))+1);
+	case hook_BotAI:
+		hook.s.skinname = NULL;
+		if (lua_isstring(L, 2))
 		{ // lowercase copy
-			char *p = subfield;
-			const char *s = luaL_checkstring(L, 3);
+			const char *s = lua_tostring(L, 2);
+			char *p = hook.s.skinname = ZZ_Alloc(strlen(s)+1);
 			do {
 				*p = tolower(*s);
 				++p;
 			} while(*(++s));
 			*p = 0;
 		}
-		lua_settop(L, 3);
 		break;
-	case hook_LinedefExecute: // Get one linedef executor function by name
-		notable = true;
-		subtable = true;
-		subfield = ZZ_Alloc(strlen(luaL_checkstring(L, 3))+1);
+	case hook_LinedefExecute: // Linedef executor functions
 		{ // uppercase copy
-			char *p = subfield;
-			const char *s = luaL_checkstring(L, 3);
+			const char *s = luaL_checkstring(L, 2);
+			char *p = hook.s.funcname = ZZ_Alloc(strlen(s)+1);
 			do {
 				*p = toupper(*s);
 				++p;
 			} while(*(++s));
 			*p = 0;
 		}
-		lua_settop(L, 3);
 		break;
 	default:
-		lua_settop(L, 2);
 		break;
 	}
+	lua_settop(L, 1); // lua stack contains only the function now.
 
-	lua_getfield(L, LUA_REGISTRYINDEX, "hook");
-	I_Assert(lua_istable(L, -1));
+	hooksAvailable[hook.type/8] |= 1<<(hook.type%8);
 
-	// This hook type only allows one entry, not an array of hooks.
-	// New hooks will overwrite the previous ones, and the stack is one table shorter.
-	if (notable)
+	// iterate the hook metadata structs
+	// set hook.id to the highest id + 1
+	// set lastp to the last hook struct's "next" pointer.
+	lastp = &roothook;
+	hook.id = 0;
+	for (hookp = roothook; hookp; hookp = hookp->next)
 	{
-		if (subtable)
-		{
-			lua_rawgeti(L, -1, hook);
-			lua_remove(L, -2); // pop "hook"
-			I_Assert(lua_istable(L, -1));
-			lua_pushvalue(L, 2);
-			if (subfield)
-				lua_setfield(L, -2, subfield);
-			else if (lsubfield)
-				lua_setfield(L, -2, lsubfield);
-			else
-				lua_rawseti(L, -2, subindex);
-		} else {
-			lua_pushvalue(L, 2);
-			lua_rawseti(L, -2, hook);
-		}
-		hooksAvailable[hook/8] |= 1<<(hook%8);
-		return 0;
+		if (hookp->id >= hook.id)
+			hook.id = hookp->id+1;
+		lastp = &hookp->next;
 	}
 
-	// Fetch the hook's table from the registry.
-	// It should always exist, since LUA_HookLib creates a table for every hook.
-	lua_rawgeti(L, -1, hook);
-	lua_remove(L, -2); // pop "hook"
-	I_Assert(lua_istable(L, -1));
-	if (subtable)
-	{
-		// Fetch a subtable based on index
-		if (subfield)
-			lua_getfield(L, -1, subfield);
-		else if (lsubfield)
-			lua_getfield(L, -1, lsubfield);
-		else
-			lua_rawgeti(L, -1, subindex);
-
-		// Subtable doesn't exist, make one now.
-		if (lua_isnil(L, -1))
-		{
-			lua_pop(L, 1);
-			lua_newtable(L);
-
-			// Store a link to the subtable for later.
-			lua_pushvalue(L, -1);
-			if (subfield)
-				lua_setfield(L, -3, subfield);
-			else if (lsubfield)
-				lua_setfield(L, -3, lsubfield);
-			else
-				lua_rawseti(L, -3, subindex);
-	}	}
-
-	// Add function to the table.
-	lua_pushvalue(L, 2);
-	lua_rawseti(L, -2, (int)(lua_objlen(L, -2) + 1));
-
-	if (subfield)
-		Z_Free(subfield);
-
-	hooksAvailable[hook/8] |= 1<<(hook%8);
+	// allocate a permanent memory struct to stuff hook.
+	hookp = ZZ_Alloc(sizeof(struct hook_s));
+	memcpy(hookp, &hook, sizeof(struct hook_s));
+	// tack it onto the end of the linked list.
+	*lastp = hookp;
+
+	// set the hook function in the registry.
+	lua_pushfstring(L, FMT_HOOKID, hook.id);
+	lua_pushvalue(L, 1);
+	lua_settable(L, LUA_REGISTRYINDEX);
 	return 0;
 }
 
 int LUA_HookLib(lua_State *L)
 {
-	// Create all registry tables
-	enum hook i;
 	memset(hooksAvailable,0,sizeof(UINT8[(hook_MAX/8)+1]));
-
-	lua_newtable(L);
-	for (i = 0; i < hook_MAX; i++)
-	{
-		lua_newtable(L);
-		switch(i)
-		{
-		default:
-			break;
-		case hook_MobjSpawn:
-		case hook_MobjCollide:
-		case hook_MobjMoveCollide:
-		case hook_TouchSpecial:
-		case hook_MobjFuse:
-		case hook_MobjThinker:
-		case hook_BossThinker:
-		case hook_ShouldDamage:
-		case hook_MobjDamage:
-		case hook_MobjDeath:
-		case hook_BossDeath:
-		case hook_MobjRemoved:
-			lua_pushstring(L, "a");
-			lua_newtable(L);
-			lua_rawset(L, -3);
-			break;
-		}
-		lua_rawseti(L, -2, i);
-	}
-	lua_setfield(L, LUA_REGISTRYINDEX, "hook");
+	roothook = NULL;
 	lua_register(L, "addHook", lib_addHook);
 	return 0;
 }
 
 boolean LUAh_MobjHook(mobj_t *mo, enum hook which)
 {
+	hook_p hookp;
 	boolean hooked = false;
 	if (!gL || !(hooksAvailable[which/8] & (1<<(which%8))))
 		return false;
 
-	// clear the stack (just in case)
-	lua_pop(gL, -1);
-
-	// hook table
-	lua_getfield(gL, LUA_REGISTRYINDEX, "hook");
-	I_Assert(lua_istable(gL, -1));
-	lua_rawgeti(gL, -1, which);
-	lua_remove(gL, -2);
-	I_Assert(lua_istable(gL, -1));
-
-	// generic subtable
-	lua_pushstring(gL, "a");
-	lua_rawget(gL, -2);
-	I_Assert(lua_istable(gL, -1));
-
-	LUA_PushUserdata(gL, mo, META_MOBJ);
-	lua_pushnil(gL);
-	while (lua_next(gL, -3)) {
-		CONS_Debug(DBG_LUA, "MobjHook: Calling hook_%s for generic mobj types\n", hookNames[which]);
-		lua_pushvalue(gL, -3); // mo
-		// stack is: hook_Mobj table, subtable "a", mobj, i, function, mobj
-		if (lua_pcall(gL, 1, 1, 0)) {
-			// A run-time error occurred.
-			CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1));
-			lua_pop(gL, 1);
-			// Remove this function from the hook table to prevent further errors.
-			lua_pushvalue(gL, -1); // key
-			lua_pushnil(gL); // value
-			lua_rawset(gL, -5); // table
-			CONS_Printf("Hook removed.\n");
-		}
-		else
-		{
-			if (lua_toboolean(gL, -1))
-				hooked = true;
-			lua_pop(gL, 1);
-		}
-	}
-	// stack is: hook_Mobj table, subtable "a", mobj
-	lua_remove(gL, -2); // pop subtable, leave mobj
-
-	// mobjtype subtable
-	// stack is: hook_Mobj table, mobj
-	lua_rawgeti(gL, -2, mo->type);
-	if (lua_isnil(gL, -1)) {
-		lua_pop(gL, 3); // pop hook_Mobj table, mobj, and nil
-		// the stack should now be empty.
-		return false;
-	}
-	lua_remove(gL, -3); // remove hook table
-	// stack is: mobj, mobjtype subtable
-	lua_insert(gL, lua_gettop(gL)-1); // swap subtable with mobj
-	// stack is: mobjtype subtable, mobj
-
-	lua_pushnil(gL);
-	while (lua_next(gL, -3)) {
-		CONS_Debug(DBG_LUA, "MobjHook: Calling hook_%s for mobj type %d\n", hookNames[which], mo->type);
-		lua_pushvalue(gL, -3); // mo
-		// stack is: mobjtype subtable, mobj, i, function, mobj
-		if (lua_pcall(gL, 1, 1, 0)) {
-			// A run-time error occurred.
-			CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1));
-			lua_pop(gL, 1);
-			// Remove this function from the hook table to prevent further errors.
-			lua_pushvalue(gL, -1); // key
-			lua_pushnil(gL); // value
-			lua_rawset(gL, -5); // table
-			CONS_Printf("Hook removed.\n");
-		}
-		else
+	lua_settop(gL, 0);
+
+	for (hookp = roothook; hookp; hookp = hookp->next)
+		if (hookp->type == which
+		&& (hookp->s.mt == MT_NULL || hookp->s.mt == mo->type))
 		{
+			if (lua_gettop(gL) == 0)
+				LUA_PushUserdata(gL, mo, META_MOBJ);
+			lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+			lua_gettable(gL, LUA_REGISTRYINDEX);
+			lua_pushvalue(gL, -2);
+			if (lua_pcall(gL, 1, 1, 0)) {
+				if (!hookp->error || cv_debug & DBG_LUA)
+					CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+				lua_pop(gL, 1);
+				hookp->error = true;
+				continue;
+			}
 			if (lua_toboolean(gL, -1))
 				hooked = true;
 			lua_pop(gL, 1);
 		}
-	}
 
-	lua_pop(gL, 2); // pop mobj and subtable
-	// the stack should now be empty.
-
-	lua_gc(gL, LUA_GCSTEP, 3);
+	lua_settop(gL, 0);
 	return hooked;
 }
 
 boolean LUAh_PlayerHook(player_t *plr, enum hook which)
 {
+	hook_p hookp;
 	boolean hooked = false;
 	if (!gL || !(hooksAvailable[which/8] & (1<<(which%8))))
 		return false;
 
-	// clear the stack (just in case)
-	lua_pop(gL, -1);
-
-	// hook table
-	lua_getfield(gL, LUA_REGISTRYINDEX, "hook");
-	I_Assert(lua_istable(gL, -1));
-	lua_rawgeti(gL, -1, which);
-	lua_remove(gL, -2);
-	I_Assert(lua_istable(gL, -1));
+	lua_settop(gL, 0);
 
-	LUA_PushUserdata(gL, plr, META_PLAYER);
-
-	lua_pushnil(gL);
-	while (lua_next(gL, -3) != 0) {
-		lua_pushvalue(gL, -3); // player
-		if (lua_pcall(gL, 1, 1, 0)) { // pops hook function, player, pushes 1 return result
-			CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1));
+	for (hookp = roothook; hookp; hookp = hookp->next)
+		if (hookp->type == which)
+		{
+			if (lua_gettop(gL) == 0)
+				LUA_PushUserdata(gL, plr, META_PLAYER);
+			lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+			lua_gettable(gL, LUA_REGISTRYINDEX);
+			lua_pushvalue(gL, -2);
+			if (lua_pcall(gL, 1, 1, 0)) {
+				if (!hookp->error || cv_debug & DBG_LUA)
+					CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+				lua_pop(gL, 1);
+				hookp->error = true;
+				continue;
+			}
+			if (lua_toboolean(gL, -1))
+				hooked = true;
 			lua_pop(gL, 1);
-			continue;
 		}
-		if (lua_toboolean(gL, -1)) // if return true,
-			hooked = true; // override vanilla behavior
-		lua_pop(gL, 1); // pop return value
-	}
 
-	lua_pop(gL, -1);
-	lua_gc(gL, LUA_GCSTEP, 1);
+	lua_settop(gL, 0);
 	return hooked;
 }
 
 // Hook for map change (before load)
 void LUAh_MapChange(void)
 {
+	hook_p hookp;
 	if (!gL || !(hooksAvailable[hook_MapChange/8] & (1<<(hook_MapChange%8))))
 		return;
 
-	lua_getfield(gL, LUA_REGISTRYINDEX, "hook");
-	I_Assert(lua_istable(gL, -1));
-	lua_rawgeti(gL, -1, hook_MapChange);
-	lua_remove(gL, -2);
-	I_Assert(lua_istable(gL, -1));
-
+	lua_settop(gL, 0);
 	lua_pushinteger(gL, gamemap);
-	lua_pushnil(gL);
-	while (lua_next(gL, -3) != 0) {
-		lua_pushvalue(gL, -3); // gamemap
-		LUA_Call(gL, 1);
-	}
-	lua_pop(gL, 1);
-	lua_gc(gL, LUA_GCSTEP, 1);
+
+	for (hookp = roothook; hookp; hookp = hookp->next)
+		if (hookp->type == hook_MapChange)
+		{
+			lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+			lua_gettable(gL, LUA_REGISTRYINDEX);
+			lua_pushvalue(gL, -2);
+			LUA_Call(gL, 1);
+		}
+
+	lua_settop(gL, 0);
 }
 
 // Hook for map load
 void LUAh_MapLoad(void)
 {
+	hook_p hookp;
 	if (!gL || !(hooksAvailable[hook_MapLoad/8] & (1<<(hook_MapLoad%8))))
 		return;
 
-	lua_pop(gL, -1);
+	lua_settop(gL, 0);
+	lua_pushinteger(gL, gamemap);
 
-	lua_getfield(gL, LUA_REGISTRYINDEX, "hook");
-	I_Assert(lua_istable(gL, -1));
-	lua_rawgeti(gL, -1, hook_MapLoad);
-	lua_remove(gL, -2);
-	I_Assert(lua_istable(gL, -1));
+	for (hookp = roothook; hookp; hookp = hookp->next)
+		if (hookp->type == hook_MapLoad)
+		{
+			lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+			lua_gettable(gL, LUA_REGISTRYINDEX);
+			lua_pushvalue(gL, -2);
+			LUA_Call(gL, 1);
+		}
 
-	lua_pushinteger(gL, gamemap);
-	lua_pushnil(gL);
-	while (lua_next(gL, -3) != 0) {
-		lua_pushvalue(gL, -3); // gamemap
-		LUA_Call(gL, 1);
-	}
-	lua_pop(gL, -1);
-	lua_gc(gL, LUA_GCCOLLECT, 0);
+	lua_settop(gL, 0);
 }
 
 // Hook for Got_AddPlayer
 void LUAh_PlayerJoin(int playernum)
 {
+	hook_p hookp;
 	if (!gL || !(hooksAvailable[hook_PlayerJoin/8] & (1<<(hook_PlayerJoin%8))))
 		return;
 
-	lua_pop(gL, -1);
+	lua_settop(gL, 0);
+	lua_pushinteger(gL, playernum);
 
-	lua_getfield(gL, LUA_REGISTRYINDEX, "hook");
-	I_Assert(lua_istable(gL, -1));
-	lua_rawgeti(gL, -1, hook_PlayerJoin);
-	lua_remove(gL, -2);
-	I_Assert(lua_istable(gL, -1));
+	for (hookp = roothook; hookp; hookp = hookp->next)
+		if (hookp->type == hook_PlayerJoin)
+		{
+			lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+			lua_gettable(gL, LUA_REGISTRYINDEX);
+			lua_pushvalue(gL, -2);
+			LUA_Call(gL, 1);
+		}
 
-	lua_pushinteger(gL, playernum);
-	lua_pushnil(gL);
-	while (lua_next(gL, -3) != 0) {
-		lua_pushvalue(gL, -3); // playernum
-		LUA_Call(gL, 1);
-	}
-	lua_pop(gL, -1);
-	lua_gc(gL, LUA_GCCOLLECT, 0);
+	lua_settop(gL, 0);
 }
 
 // Hook for frame (after mobj and player thinkers)
 void LUAh_ThinkFrame(void)
 {
+	hook_p hookp;
 	if (!gL || !(hooksAvailable[hook_ThinkFrame/8] & (1<<(hook_ThinkFrame%8))))
 		return;
 
-	lua_pop(gL, -1);
-
-	lua_getfield(gL, LUA_REGISTRYINDEX, "hook");
-	I_Assert(lua_istable(gL, -1));
-	lua_rawgeti(gL, -1, hook_ThinkFrame);
-	lua_remove(gL, -2);
-	I_Assert(lua_istable(gL, -1));
-
-	lua_pushnil(gL);
-	while (lua_next(gL, -2) != 0)
-	{
-		//LUA_Call(gL, 0);
-		if (lua_pcall(gL, 0, 0, 0))
+	for (hookp = roothook; hookp; hookp = hookp->next)
+		if (hookp->type == hook_ThinkFrame)
 		{
-			// A run-time error occurred.
-			CONS_Alert(CONS_WARNING,"%s\n", lua_tostring(gL, -1));
-			lua_pop(gL, 1);
-			// Remove this function from the hook table to prevent further errors.
-			lua_pushvalue(gL, -1); // key
-			lua_pushnil(gL); // value
-			lua_rawset(gL, -4); // table
-			CONS_Printf("Hook removed.\n");
+			lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+			lua_gettable(gL, LUA_REGISTRYINDEX);
+			if (lua_pcall(gL, 0, 0, 0)) {
+				if (!hookp->error || cv_debug & DBG_LUA)
+					CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+				lua_pop(gL, 1);
+				hookp->error = true;
+			}
 		}
-	}
-	lua_pop(gL, -1);
-	lua_gc(gL, LUA_GCCOLLECT, 0);
 }
 
-// Hook for PIT_CheckThing by (thing) mobj type (thing1 = thing, thing2 = tmthing)
-UINT8 LUAh_MobjCollide(mobj_t *thing1, mobj_t *thing2)
+// Hook for mobj collisions
+UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which)
 {
+	hook_p hookp;
 	UINT8 shouldCollide = 0; // 0 = default, 1 = force yes, 2 = force no.
-	if (!gL || !(hooksAvailable[hook_MobjCollide/8] & (1<<(hook_MobjCollide%8))))
-		return 0;
-
-	// clear the stack
-	lua_pop(gL, -1);
-
-	// hook table
-	lua_getfield(gL, LUA_REGISTRYINDEX, "hook");
-	I_Assert(lua_istable(gL, -1));
-	lua_rawgeti(gL, -1, hook_MobjCollide);
-	lua_remove(gL, -2);
-	I_Assert(lua_istable(gL, -1));
-
-	// mobjtype subtable
-	lua_rawgeti(gL, -1, thing1->type);
-	if (lua_isnil(gL, -1)) {
-		lua_pop(gL, 2);
-		return 0;
-	}
-	lua_remove(gL, -2); // remove hook table
-
-	LUA_PushUserdata(gL, thing1, META_MOBJ);
-	LUA_PushUserdata(gL, thing2, META_MOBJ);
-	lua_pushnil(gL);
-	while (lua_next(gL, -4)) {
-		lua_pushvalue(gL, -4); // thing1
-		lua_pushvalue(gL, -4); // thing2
-		if (lua_pcall(gL, 2, 1, 0)) {
-			CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1));
-			lua_pop(gL, 1);
-			continue;
-		}
-		if (!lua_isnil(gL, -1))
-		{ // if nil, leave shouldCollide = 0.
-			if (lua_toboolean(gL, -1))
-				shouldCollide = 1; // Force yes
-			else
-				shouldCollide = 2; // Force no
-		}
-		lua_pop(gL, 1); // pop return value
-	}
-	lua_pop(gL, 3); // pop arguments and mobjtype table
-
-	lua_gc(gL, LUA_GCSTEP, 1);
-	return shouldCollide;
-}
-
-// Hook for PIT_CheckThing by (tmthing) mobj type (thing1 = tmthing, thing2 = thing)
-UINT8 LUAh_MobjMoveCollide(mobj_t *thing1, mobj_t *thing2)
-{
-	UINT8 shouldCollide = 0; // 0 = default, 1 = force yes, 2 = force no.
-	if (!gL || !(hooksAvailable[hook_MobjMoveCollide/8] & (1<<(hook_MobjMoveCollide%8))))
+	if (!gL || !(hooksAvailable[which/8] & (1<<(which%8))))
 		return 0;
 
-	// clear the stack
-	lua_pop(gL, -1);
-
-	// hook table
-	lua_getfield(gL, LUA_REGISTRYINDEX, "hook");
-	I_Assert(lua_istable(gL, -1));
-	lua_rawgeti(gL, -1, hook_MobjMoveCollide);
-	lua_remove(gL, -2);
-	I_Assert(lua_istable(gL, -1));
+	lua_settop(gL, 0);
 
-	// mobjtype subtable
-	lua_rawgeti(gL, -1, thing1->type);
-	if (lua_isnil(gL, -1)) {
-		lua_pop(gL, 2);
-		return 0;
-	}
-	lua_remove(gL, -2); // remove hook table
-
-	LUA_PushUserdata(gL, thing1, META_MOBJ);
-	LUA_PushUserdata(gL, thing2, META_MOBJ);
-	lua_pushnil(gL);
-	while (lua_next(gL, -4)) {
-		lua_pushvalue(gL, -4); // thing1
-		lua_pushvalue(gL, -4); // thing2
-		if (lua_pcall(gL, 2, 1, 0)) {
-			CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1));
+	for (hookp = roothook; hookp; hookp = hookp->next)
+		if (hookp->type == which
+		&& (hookp->s.mt == MT_NULL || hookp->s.mt == thing1->type))
+		{
+			if (lua_gettop(gL) == 0)
+			{
+				LUA_PushUserdata(gL, thing1, META_MOBJ);
+				LUA_PushUserdata(gL, thing2, META_MOBJ);
+			}
+			lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+			lua_gettable(gL, LUA_REGISTRYINDEX);
+			lua_pushvalue(gL, -3);
+			lua_pushvalue(gL, -3);
+			if (lua_pcall(gL, 2, 1, 0)) {
+				if (!hookp->error || cv_debug & DBG_LUA)
+					CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+				lua_pop(gL, 1);
+				hookp->error = true;
+				continue;
+			}
+			if (!lua_isnil(gL, -1))
+			{ // if nil, leave shouldCollide = 0.
+				if (lua_toboolean(gL, -1))
+					shouldCollide = 1; // Force yes
+				else
+					shouldCollide = 2; // Force no
+			}
 			lua_pop(gL, 1);
-			continue;
 		}
-		if (!lua_isnil(gL, -1))
-		{ // if nil, leave shouldCollide = 0.
-			if (lua_toboolean(gL, -1))
-				shouldCollide = 1; // Force yes
-			else
-				shouldCollide = 2; // Force no
-		}
-		lua_pop(gL, 1); // pop return value
-	}
-	lua_pop(gL, 3); // pop arguments and mobjtype table
 
-	lua_gc(gL, LUA_GCSTEP, 1);
+	lua_settop(gL, 0);
 	return shouldCollide;
 }
 
 // Hook for P_TouchSpecialThing by mobj type
 boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher)
 {
+	hook_p hookp;
 	boolean hooked = false;
 	if (!gL || !(hooksAvailable[hook_TouchSpecial/8] & (1<<(hook_TouchSpecial%8))))
-		return false;
-
-	// clear the stack
-	lua_pop(gL, -1);
-
-	// get hook table
-	lua_getfield(gL, LUA_REGISTRYINDEX, "hook");
-	I_Assert(lua_istable(gL, -1));
-	lua_rawgeti(gL, -1, hook_TouchSpecial);
-	lua_remove(gL, -2);
-	I_Assert(lua_istable(gL, -1));
-
-	// get mobjtype subtable
-	lua_pushinteger(gL, special->type);
-	lua_rawget(gL, 1);
-	if (lua_isnil(gL, -1)) {
-		lua_pop(gL, 2);
-		return false;
-	}
-	lua_remove(gL, 1); // pop hook table off the stack
+		return 0;
 
-	LUA_PushUserdata(gL, special, META_MOBJ);
-	LUA_PushUserdata(gL, toucher, META_MOBJ);
+	lua_settop(gL, 0);
 
-	lua_pushnil(gL);
-	while (lua_next(gL, 1) != 0) {
-		lua_pushvalue(gL, 2); // special
-		lua_pushvalue(gL, 3); // toucher
-		if (lua_pcall(gL, 2, 1, 0)) { // pops hook function, special, toucher, pushes 1 return result
-			CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1));
+	for (hookp = roothook; hookp; hookp = hookp->next)
+		if (hookp->type == hook_TouchSpecial
+		&& (hookp->s.mt == MT_NULL || hookp->s.mt == special->type))
+		{
+			if (lua_gettop(gL) == 0)
+			{
+				LUA_PushUserdata(gL, special, META_MOBJ);
+				LUA_PushUserdata(gL, toucher, META_MOBJ);
+			}
+			lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+			lua_gettable(gL, LUA_REGISTRYINDEX);
+			lua_pushvalue(gL, -3);
+			lua_pushvalue(gL, -3);
+			if (lua_pcall(gL, 2, 1, 0)) {
+				if (!hookp->error || cv_debug & DBG_LUA)
+					CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+				lua_pop(gL, 1);
+				hookp->error = true;
+				continue;
+			}
+			if (lua_toboolean(gL, -1))
+				hooked = true;
 			lua_pop(gL, 1);
-			continue;
 		}
-		if (lua_toboolean(gL, -1)) // if return true,
-			hooked = true; // override vanilla behavior
-		lua_pop(gL, 1); // pop return value
-	}
 
-	lua_pop(gL, -1);
-	lua_gc(gL, LUA_GCSTEP, 1);
+	lua_settop(gL, 0);
 	return hooked;
 }
 
 // Hook for P_DamageMobj by mobj type (Should mobj take damage?)
 UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage)
 {
+	hook_p hookp;
 	UINT8 shouldDamage = 0; // 0 = default, 1 = force yes, 2 = force no.
 	if (!gL || !(hooksAvailable[hook_ShouldDamage/8] & (1<<(hook_ShouldDamage%8))))
 		return 0;
 
-	// clear the stack
-	lua_pop(gL, -1);
-
-	// hook table
-	lua_getfield(gL, LUA_REGISTRYINDEX, "hook");
-	I_Assert(lua_istable(gL, -1));
-	lua_rawgeti(gL, -1, hook_ShouldDamage);
-	lua_remove(gL, -2);
-	I_Assert(lua_istable(gL, -1));
+	lua_settop(gL, 0);
 
-	// mobjtype subtable
-	lua_rawgeti(gL, -1, target->type);
-	if (lua_isnil(gL, -1)) {
-		lua_pop(gL, 2);
-		return 0;
-	}
-	lua_remove(gL, -2); // remove hook table
-
-	LUA_PushUserdata(gL, target, META_MOBJ);
-	LUA_PushUserdata(gL, inflictor, META_MOBJ);
-	LUA_PushUserdata(gL, source, META_MOBJ);
-	lua_pushinteger(gL, damage);
-	lua_pushnil(gL);
-	while (lua_next(gL, -6)) {
-		lua_pushvalue(gL, -6); // target
-		lua_pushvalue(gL, -6); // inflictor
-		lua_pushvalue(gL, -6); // source
-		lua_pushvalue(gL, -6); // damage
-		if (lua_pcall(gL, 4, 1, 0)) {
-			CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1));
+	for (hookp = roothook; hookp; hookp = hookp->next)
+		if (hookp->type == hook_ShouldDamage
+		&& (hookp->s.mt == MT_NULL || hookp->s.mt == target->type))
+		{
+			if (lua_gettop(gL) == 0)
+			{
+				LUA_PushUserdata(gL, target, META_MOBJ);
+				LUA_PushUserdata(gL, inflictor, META_MOBJ);
+				LUA_PushUserdata(gL, source, META_MOBJ);
+				lua_pushinteger(gL, damage);
+			}
+			lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+			lua_gettable(gL, LUA_REGISTRYINDEX);
+			lua_pushvalue(gL, -5);
+			lua_pushvalue(gL, -5);
+			lua_pushvalue(gL, -5);
+			lua_pushvalue(gL, -5);
+			if (lua_pcall(gL, 4, 1, 0)) {
+				if (!hookp->error || cv_debug & DBG_LUA)
+					CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+				lua_pop(gL, 1);
+				hookp->error = true;
+				continue;
+			}
+			if (!lua_isnil(gL, -1))
+			{
+				if (lua_toboolean(gL, -1))
+					shouldDamage = 1; // Force yes
+				else
+					shouldDamage = 2; // Force no
+			}
 			lua_pop(gL, 1);
-			continue;
 		}
-		if (!lua_isnil(gL, -1))
-		{ // if nil, leave shouldDamage = 0.
-			if (lua_toboolean(gL, -1))
-				shouldDamage = 1; // Force yes
-			else
-				shouldDamage = 2; // Force no
-		}
-		lua_pop(gL, 1); // pop return value
-	}
-	lua_pop(gL, 5); // pop arguments and mobjtype table
 
-	lua_gc(gL, LUA_GCSTEP, 1);
+	lua_settop(gL, 0);
 	return shouldDamage;
 }
 
 // Hook for P_DamageMobj by mobj type (Mobj actually takes damage!)
 boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage)
 {
-	boolean handled = false;
+	hook_p hookp;
+	boolean hooked = false;
 	if (!gL || !(hooksAvailable[hook_MobjDamage/8] & (1<<(hook_MobjDamage%8))))
-		return false;
-
-	// clear the stack
-	lua_pop(gL, -1);
+		return 0;
 
-	// hook table
-	lua_getfield(gL, LUA_REGISTRYINDEX, "hook");
-	I_Assert(lua_istable(gL, -1));
-	lua_rawgeti(gL, -1, hook_MobjDamage);
-	lua_remove(gL, -2);
-	I_Assert(lua_istable(gL, -1));
+	lua_settop(gL, 0);
 
-	// mobjtype subtable
-	lua_rawgeti(gL, -1, target->type);
-	if (lua_isnil(gL, -1)) {
-		lua_pop(gL, 2);
-		return false;
-	}
-	lua_remove(gL, -2); // remove hook table
-
-	LUA_PushUserdata(gL, target, META_MOBJ);
-	LUA_PushUserdata(gL, inflictor, META_MOBJ);
-	LUA_PushUserdata(gL, source, META_MOBJ);
-	lua_pushinteger(gL, damage);
-	lua_pushnil(gL);
-	while (lua_next(gL, -6)) {
-		lua_pushvalue(gL, -6); // target
-		lua_pushvalue(gL, -6); // inflictor
-		lua_pushvalue(gL, -6); // source
-		lua_pushvalue(gL, -6); // damage
-		if (lua_pcall(gL, 4, 1, 0)) {
-			CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1));
+	for (hookp = roothook; hookp; hookp = hookp->next)
+		if (hookp->type == hook_MobjDamage
+		&& (hookp->s.mt == MT_NULL || hookp->s.mt == target->type))
+		{
+			if (lua_gettop(gL) == 0)
+			{
+				LUA_PushUserdata(gL, target, META_MOBJ);
+				LUA_PushUserdata(gL, inflictor, META_MOBJ);
+				LUA_PushUserdata(gL, source, META_MOBJ);
+				lua_pushinteger(gL, damage);
+			}
+			lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+			lua_gettable(gL, LUA_REGISTRYINDEX);
+			lua_pushvalue(gL, -5);
+			lua_pushvalue(gL, -5);
+			lua_pushvalue(gL, -5);
+			lua_pushvalue(gL, -5);
+			if (lua_pcall(gL, 4, 1, 0)) {
+				if (!hookp->error || cv_debug & DBG_LUA)
+					CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+				lua_pop(gL, 1);
+				hookp->error = true;
+				continue;
+			}
+			if (lua_toboolean(gL, -1))
+				hooked = true;
 			lua_pop(gL, 1);
-			continue;
 		}
-		if (lua_toboolean(gL, -1))
-			handled = true;
-		lua_pop(gL, 1); // pop return value
-	}
-	lua_pop(gL, 5); // pop arguments and mobjtype table
 
-	lua_gc(gL, LUA_GCSTEP, 1);
-	return handled;
+	lua_settop(gL, 0);
+	return hooked;
 }
 
 // Hook for P_KillMobj by mobj type
 boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source)
 {
-	boolean handled = false;
+	hook_p hookp;
+	boolean hooked = false;
 	if (!gL || !(hooksAvailable[hook_MobjDeath/8] & (1<<(hook_MobjDeath%8))))
-		return false;
-
-	// clear the stack
-	lua_pop(gL, -1);
+		return 0;
 
-	// hook table
-	lua_getfield(gL, LUA_REGISTRYINDEX, "hook");
-	I_Assert(lua_istable(gL, -1));
-	lua_rawgeti(gL, -1, hook_MobjDeath);
-	lua_remove(gL, -2);
-	I_Assert(lua_istable(gL, -1));
+	lua_settop(gL, 0);
 
-	// mobjtype subtable
-	lua_rawgeti(gL, -1, target->type);
-	if (lua_isnil(gL, -1)) {
-		lua_pop(gL, 2);
-		return false;
-	}
-	lua_remove(gL, -2); // remove hook table
-
-	LUA_PushUserdata(gL, target, META_MOBJ);
-	LUA_PushUserdata(gL, inflictor, META_MOBJ);
-	LUA_PushUserdata(gL, source, META_MOBJ);
-	lua_pushnil(gL);
-	while (lua_next(gL, -5)) {
-		lua_pushvalue(gL, -5); // target
-		lua_pushvalue(gL, -5); // inflictor
-		lua_pushvalue(gL, -5); // source
-		if (lua_pcall(gL, 3, 1, 0)) {
-			CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1));
+	for (hookp = roothook; hookp; hookp = hookp->next)
+		if (hookp->type == hook_MobjDeath
+		&& (hookp->s.mt == MT_NULL || hookp->s.mt == target->type))
+		{
+			if (lua_gettop(gL) == 0)
+			{
+				LUA_PushUserdata(gL, target, META_MOBJ);
+				LUA_PushUserdata(gL, inflictor, META_MOBJ);
+				LUA_PushUserdata(gL, source, META_MOBJ);
+			}
+			lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+			lua_gettable(gL, LUA_REGISTRYINDEX);
+			lua_pushvalue(gL, -4);
+			lua_pushvalue(gL, -4);
+			lua_pushvalue(gL, -4);
+			if (lua_pcall(gL, 3, 1, 0)) {
+				if (!hookp->error || cv_debug & DBG_LUA)
+					CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+				lua_pop(gL, 1);
+				hookp->error = true;
+				continue;
+			}
+			if (lua_toboolean(gL, -1))
+				hooked = true;
 			lua_pop(gL, 1);
-			continue;
 		}
-		if (lua_toboolean(gL, -1))
-			handled = true;
-		lua_pop(gL, 1); // pop return value
-	}
-	lua_pop(gL, 4); // pop arguments and mobjtype table
 
-	lua_gc(gL, LUA_GCSTEP, 1);
-	return handled;
+	lua_settop(gL, 0);
+	return hooked;
 }
 
 // Hook for B_BuildTiccmd
 boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd)
 {
+	hook_p hookp;
 	boolean hooked = false;
 	if (!gL || !(hooksAvailable[hook_BotTiccmd/8] & (1<<(hook_BotTiccmd%8))))
 		return false;
 
-	// clear the stack
-	lua_pop(gL, -1);
-
-	// hook table
-	lua_getfield(gL, LUA_REGISTRYINDEX, "hook");
-	I_Assert(lua_istable(gL, -1));
-	lua_rawgeti(gL, -1, hook_BotTiccmd);
-	lua_remove(gL, -2);
-	I_Assert(lua_istable(gL, -1));
-
-	LUA_PushUserdata(gL, bot, META_PLAYER);
-	LUA_PushUserdata(gL, cmd, META_TICCMD);
-
-	lua_pushnil(gL);
-	while (lua_next(gL, 1)) {
-		lua_pushvalue(gL, 2); // bot
-		lua_pushvalue(gL, 3); // cmd
-		if (lua_pcall(gL, 2, 1, 0)) {
-			CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1));
+	lua_settop(gL, 0);
+
+	for (hookp = roothook; hookp; hookp = hookp->next)
+		if (hookp->type == hook_BotTiccmd)
+		{
+			if (lua_gettop(gL) == 0)
+			{
+				LUA_PushUserdata(gL, bot, META_PLAYER);
+				LUA_PushUserdata(gL, cmd, META_TICCMD);
+			}
+			lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+			lua_gettable(gL, LUA_REGISTRYINDEX);
+			lua_pushvalue(gL, -3);
+			lua_pushvalue(gL, -3);
+			if (lua_pcall(gL, 2, 1, 0)) {
+				if (!hookp->error || cv_debug & DBG_LUA)
+					CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+				lua_pop(gL, 1);
+				hookp->error = true;
+				continue;
+			}
+			if (lua_toboolean(gL, -1))
+				hooked = true;
 			lua_pop(gL, 1);
-			continue;
 		}
-		if (lua_toboolean(gL, -1))
-			hooked = true;
-		lua_pop(gL, 1); // pop return value
-	}
 
-	lua_pop(gL, -1);
-	lua_gc(gL, LUA_GCSTEP, 1);
+	lua_settop(gL, 0);
 	return hooked;
 }
 
 // Hook for B_BuildTailsTiccmd by skin name
 boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
 {
-	if (!gL || !tails->skin || !(hooksAvailable[hook_BotAI/8] & (1<<(hook_BotAI%8))))
-		return false;
-
-	// clear the stack
-	lua_pop(gL, -1);
-
-	// hook table
-	lua_getfield(gL, LUA_REGISTRYINDEX, "hook");
-	I_Assert(lua_istable(gL, -1));
-	lua_rawgeti(gL, -1, hook_BotAI);
-	lua_remove(gL, -2);
-	I_Assert(lua_istable(gL, -1));
-
-	// bot skin ai function
-	lua_getfield(gL, 1, ((skin_t *)tails->skin)->name);
-	if (lua_isnil(gL, -1)) {
-		lua_pop(gL, 2);
-		return false;
-	}
-	lua_remove(gL, 1); // pop the hook table
-
-	// Takes sonic, tails
-	// Returns forward, backward, left, right, jump, spin
-	LUA_PushUserdata(gL, sonic, META_MOBJ);
-	LUA_PushUserdata(gL, tails, META_MOBJ);
-	if (lua_pcall(gL, 2, 8, 0)) {
-		CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1));
-		lua_pop(gL,-1);
+	hook_p hookp;
+	boolean hooked = false;
+	if (!gL || !(hooksAvailable[hook_BotAI/8] & (1<<(hook_BotAI%8))))
 		return false;
-	}
 
-	// This turns forward, backward, left, right, jump, and spin into a proper ticcmd for tails.
-	if (lua_istable(gL, 1)) {
-		boolean forward=false, backward=false, left=false, right=false, strafeleft=false, straferight=false, jump=false, spin=false;
+	lua_settop(gL, 0);
 
+	for (hookp = roothook; hookp; hookp = hookp->next)
+		if (hookp->type == hook_BotAI
+		&& (hookp->s.skinname == NULL || !strcmp(hookp->s.skinname, ((skin_t*)tails->skin)->name)))
+		{
+			if (lua_gettop(gL) == 0)
+			{
+				LUA_PushUserdata(gL, sonic, META_MOBJ);
+				LUA_PushUserdata(gL, tails, META_MOBJ);
+			}
+			lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+			lua_gettable(gL, LUA_REGISTRYINDEX);
+			lua_pushvalue(gL, -3);
+			lua_pushvalue(gL, -3);
+			if (lua_pcall(gL, 2, 8, 0)) {
+				if (!hookp->error || cv_debug & DBG_LUA)
+					CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+				lua_pop(gL, 1);
+				hookp->error = true;
+				continue;
+			}
+
+			// This turns forward, backward, left, right, jump, and spin into a proper ticcmd for tails.
+			if (lua_istable(gL, 2+1)) {
+				boolean forward=false, backward=false, left=false, right=false, strafeleft=false, straferight=false, jump=false, spin=false;
 #define CHECKFIELD(field) \
-		lua_getfield(gL, 1, #field);\
-		if (lua_toboolean(gL, -1))\
-			field = true;\
-		lua_pop(gL, 1);
-
-		CHECKFIELD(forward)
-		CHECKFIELD(backward)
-		CHECKFIELD(left)
-		CHECKFIELD(right)
-		CHECKFIELD(strafeleft)
-		CHECKFIELD(straferight)
-		CHECKFIELD(jump)
-		CHECKFIELD(spin)
-
+				lua_getfield(gL, 2+1, #field);\
+				if (lua_toboolean(gL, -1))\
+					field = true;\
+				lua_pop(gL, 1);
+
+				CHECKFIELD(forward)
+				CHECKFIELD(backward)
+				CHECKFIELD(left)
+				CHECKFIELD(right)
+				CHECKFIELD(strafeleft)
+				CHECKFIELD(straferight)
+				CHECKFIELD(jump)
+				CHECKFIELD(spin)
 #undef CHECKFIELD
+				B_KeysToTiccmd(tails, cmd, forward, backward, left, right, strafeleft, straferight, jump, spin);
+			} else
+				B_KeysToTiccmd(tails, cmd, lua_toboolean(gL, 2+1), lua_toboolean(gL, 2+2), lua_toboolean(gL, 2+3), lua_toboolean(gL, 2+4), lua_toboolean(gL, 2+5), lua_toboolean(gL, 2+6), lua_toboolean(gL, 2+7), lua_toboolean(gL, 2+8));
 
-		B_KeysToTiccmd(tails, cmd, forward, backward, left, right, strafeleft, straferight, jump, spin);
-	} else
-		B_KeysToTiccmd(tails, cmd, lua_toboolean(gL, 1), lua_toboolean(gL, 2), lua_toboolean(gL, 3), lua_toboolean(gL, 4), lua_toboolean(gL, 5), lua_toboolean(gL, 6), lua_toboolean(gL, 7), lua_toboolean(gL, 8));
+			lua_pop(gL, 8);
+			hooked = true;
+		}
 
-	lua_pop(gL, -1);
-	lua_gc(gL, LUA_GCSTEP, 1);
-	return true;
+	lua_settop(gL, 0);
+	return hooked;
 }
 
 // Hook for linedef executors
 boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector)
 {
+	hook_p hookp;
+	boolean hooked = false;
 	if (!gL || !(hooksAvailable[hook_LinedefExecute/8] & (1<<(hook_LinedefExecute%8))))
-		return false;
-
-	// clear the stack
-	lua_pop(gL, -1);
-
-	// get hook table
-	lua_getfield(gL, LUA_REGISTRYINDEX, "hook");
-	I_Assert(lua_istable(gL, -1));
-	lua_rawgeti(gL, -1, hook_LinedefExecute);
-	lua_remove(gL, -2);
-	I_Assert(lua_istable(gL, -1));
+		return 0;
 
-	// get function by line text
-	lua_getfield(gL, 1, line->text);
-	if (lua_isnil(gL, -1)) {
-		lua_pop(gL, 2);
-		return false;
-	}
-	lua_remove(gL, 1); // pop hook table off the stack
+	lua_settop(gL, 0);
 
-	LUA_PushUserdata(gL, line, META_LINE);
-	LUA_PushUserdata(gL, mo, META_MOBJ);
-	LUA_PushUserdata(gL, sector, META_SECTOR);
-	LUA_Call(gL, 3); // pops hook function, line, mo, sector
+	for (hookp = roothook; hookp; hookp = hookp->next)
+		if (hookp->type == hook_LinedefExecute
+		&& !strcmp(hookp->s.funcname, line->text))
+		{
+			if (lua_gettop(gL) == 0)
+			{
+				LUA_PushUserdata(gL, line, META_LINE);
+				LUA_PushUserdata(gL, mo, META_MOBJ);
+				LUA_PushUserdata(gL, sector, META_SECTOR);
+			}
+			lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+			lua_gettable(gL, LUA_REGISTRYINDEX);
+			lua_pushvalue(gL, -4);
+			lua_pushvalue(gL, -4);
+			lua_pushvalue(gL, -4);
+			LUA_Call(gL, 3);
+			hooked = true;
+		}
 
-	lua_pop(gL, -1);
-	lua_gc(gL, LUA_GCSTEP, 1);
-	return true;
+	lua_settop(gL, 0);
+	return hooked;
 }
 
-// Hook for PlayerMsg -Red
+// Hook for player chat
 boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg)
 {
-	boolean handled = false;
-
+	hook_p hookp;
+	boolean hooked = false;
 	if (!gL || !(hooksAvailable[hook_PlayerMsg/8] & (1<<(hook_PlayerMsg%8))))
 		return false;
 
-	lua_getfield(gL, LUA_REGISTRYINDEX, "hook");
-	I_Assert(lua_istable(gL, -1));
-	lua_rawgeti(gL, -1, hook_PlayerMsg);
-	lua_remove(gL, -2);
-	I_Assert(lua_istable(gL, -1));
-
-	LUA_PushUserdata(gL, &players[source], META_PLAYER); // Source player
-
-	if (flags & 2 /*HU_CSAY*/) { // csay TODO: make HU_CSAY accessible outside hu_stuff.c
-		lua_pushinteger(gL, 3); // type
-		lua_pushnil(gL); // target
-	} else if (target == -1) { // sayteam
-		lua_pushinteger(gL, 1); // type
-		lua_pushnil(gL); // target
-	} else if (target == 0) { // say
-		lua_pushinteger(gL, 0); // type
-		lua_pushnil(gL); // target
-	} else { // sayto
-		lua_pushinteger(gL, 2); // type
-		LUA_PushUserdata(gL, &players[target-1], META_PLAYER); // target
-	}
-
-	lua_pushstring(gL, msg); // msg
+	lua_settop(gL, 0);
 
-	lua_pushnil(gL);
-
-	while (lua_next(gL, -6)) {
-		lua_pushvalue(gL, -6); // source
-		lua_pushvalue(gL, -6); // type
-		lua_pushvalue(gL, -6); // target
-		lua_pushvalue(gL, -6); // msg
-		if (lua_pcall(gL, 4, 1, 0)) {
-			CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1));
+	for (hookp = roothook; hookp; hookp = hookp->next)
+		if (hookp->type == hook_PlayerMsg)
+		{
+			if (lua_gettop(gL) == 0)
+			{
+				LUA_PushUserdata(gL, &players[source], META_PLAYER); // Source player
+				if (flags & 2 /*HU_CSAY*/) { // csay TODO: make HU_CSAY accessible outside hu_stuff.c
+					lua_pushinteger(gL, 3); // type
+					lua_pushnil(gL); // target
+				} else if (target == -1) { // sayteam
+					lua_pushinteger(gL, 1); // type
+					lua_pushnil(gL); // target
+				} else if (target == 0) { // say
+					lua_pushinteger(gL, 0); // type
+					lua_pushnil(gL); // target
+				} else { // sayto
+					lua_pushinteger(gL, 2); // type
+					LUA_PushUserdata(gL, &players[target-1], META_PLAYER); // target
+				}
+				lua_pushstring(gL, msg); // msg
+			}
+			lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+			lua_gettable(gL, LUA_REGISTRYINDEX);
+			lua_pushvalue(gL, -5);
+			lua_pushvalue(gL, -5);
+			lua_pushvalue(gL, -5);
+			lua_pushvalue(gL, -5);
+			if (lua_pcall(gL, 4, 1, 0)) {
+				if (!hookp->error || cv_debug & DBG_LUA)
+					CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+				lua_pop(gL, 1);
+				hookp->error = true;
+				continue;
+			}
+			if (lua_toboolean(gL, -1))
+				hooked = true;
 			lua_pop(gL, 1);
-			continue;
 		}
-		if (lua_toboolean(gL, -1))
-			handled = true;
-		lua_pop(gL, 1); // pop return value
-	}
-	lua_pop(gL, 4); // pop arguments and mobjtype table
 
-	lua_gc(gL, LUA_GCSTEP, 1);
-	return handled;
+	lua_settop(gL, 0);
+	return hooked;
 }
 
-// Hook for hurt messages -Red
-// The internal name is DeathMsg, but the API name is "HurtMsg". Keep that in mind. (Should this be fixed at some point?)
-// @TODO This hook should be fixed to take mobj type at the addHook parameter to compare to inflictor. (I couldn't get this to work without crashing)
-boolean LUAh_DeathMsg(player_t *player, mobj_t *inflictor, mobj_t *source)
+// Hook for hurt messages
+boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source)
 {
-	boolean handled = false;
-
-	if (!gL || !(hooksAvailable[hook_DeathMsg/8] & (1<<(hook_DeathMsg%8))))
+	hook_p hookp;
+	boolean hooked = false;
+	if (!gL || !(hooksAvailable[hook_HurtMsg/8] & (1<<(hook_HurtMsg%8))))
 		return false;
 
-	lua_getfield(gL, LUA_REGISTRYINDEX, "hook");
-	I_Assert(lua_istable(gL, -1));
-	lua_rawgeti(gL, -1, hook_DeathMsg);
-	lua_remove(gL, -2);
-	I_Assert(lua_istable(gL, -1));
-
-	LUA_PushUserdata(gL, player, META_PLAYER); // Player
-	LUA_PushUserdata(gL, inflictor, META_MOBJ); // Inflictor
-	LUA_PushUserdata(gL, source, META_MOBJ); // Source
-
-	lua_pushnil(gL);
+	lua_settop(gL, 0);
 
-	while (lua_next(gL, -5)) {
-		lua_pushvalue(gL, -5); // player
-		lua_pushvalue(gL, -5); // inflictor
-		lua_pushvalue(gL, -5); // source
-		if (lua_pcall(gL, 3, 1, 0)) {
-			CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1));
+	for (hookp = roothook; hookp; hookp = hookp->next)
+		if (hookp->type == hook_HurtMsg
+		&& (hookp->s.mt == MT_NULL || (inflictor && hookp->s.mt == inflictor->type)))
+		{
+			if (lua_gettop(gL) == 0)
+			{
+				LUA_PushUserdata(gL, player, META_PLAYER);
+				LUA_PushUserdata(gL, inflictor, META_MOBJ);
+				LUA_PushUserdata(gL, source, META_MOBJ);
+			}
+			lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+			lua_gettable(gL, LUA_REGISTRYINDEX);
+			lua_pushvalue(gL, -4);
+			lua_pushvalue(gL, -4);
+			lua_pushvalue(gL, -4);
+			if (lua_pcall(gL, 3, 1, 0)) {
+				if (!hookp->error || cv_debug & DBG_LUA)
+					CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+				lua_pop(gL, 1);
+				hookp->error = true;
+				continue;
+			}
+			if (lua_toboolean(gL, -1))
+				hooked = true;
 			lua_pop(gL, 1);
-			continue;
 		}
-		if (lua_toboolean(gL, -1))
-			handled = true;
-		lua_pop(gL, 1); // pop return value
-	}
-	lua_pop(gL, 3); // pop arguments and mobjtype table
 
-	lua_gc(gL, LUA_GCSTEP, 1);
-	return handled;
+	lua_settop(gL, 0);
+	return hooked;
 }
 
 #endif
diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c
index 86ff11337a6fcd02e763da75ee612eb5ee789d1d..5a83d95b56a6a3a39cf7d0364c39a2866964dd26 100644
--- a/src/lua_hudlib.c
+++ b/src/lua_hudlib.c
@@ -674,8 +674,6 @@ void LUAh_GameHUD(player_t *stplayr)
 		LUA_Call(gL, 3);
 	}
 	lua_pop(gL, -1);
-	lua_gc(gL, LUA_GCCOLLECT, 0);
-
 	hud_running = false;
 }
 
@@ -701,8 +699,6 @@ void LUAh_ScoresHUD(void)
 		LUA_Call(gL, 1);
 	}
 	lua_pop(gL, -1);
-	lua_gc(gL, LUA_GCCOLLECT, 0);
-
 	hud_running = false;
 }
 
diff --git a/src/lua_infolib.c b/src/lua_infolib.c
index 2c968218c6e0af332e1c194e0f42b9e1de64e913..0fddebabae628703c87f4efec7330489bfffc7cf 100644
--- a/src/lua_infolib.c
+++ b/src/lua_infolib.c
@@ -137,8 +137,6 @@ static void A_Lua(mobj_t *actor)
 		--superstack;
 		superactions[superstack] = NULL;
 	}
-
-	lua_gc(gL, LUA_GCSTEP, 1);
 }
 
 // Arbitrary states[] table index -> state_t *
@@ -510,11 +508,11 @@ static int lib_setMobjInfo(lua_State *L)
 		else if (i == 15 || (str && fastcmp(str,"deathsound")))
 			info->deathsound = luaL_checkinteger(L, 3);
 		else if (i == 16 || (str && fastcmp(str,"speed")))
-			info->speed = (fixed_t)luaL_checkinteger(L, 3);
+			info->speed = luaL_checkfixed(L, 3);
 		else if (i == 17 || (str && fastcmp(str,"radius")))
-			info->radius = (fixed_t)luaL_checkinteger(L, 3);
+			info->radius = luaL_checkfixed(L, 3);
 		else if (i == 18 || (str && fastcmp(str,"height")))
-			info->height = (fixed_t)luaL_checkinteger(L, 3);
+			info->height = luaL_checkfixed(L, 3);
 		else if (i == 19 || (str && fastcmp(str,"dispoffset")))
 			info->dispoffset = (INT32)luaL_checkinteger(L, 3);
 		else if (i == 20 || (str && fastcmp(str,"mass")))
@@ -580,11 +578,11 @@ static int mobjinfo_get(lua_State *L)
 	else if (fastcmp(field,"deathsound"))
 		lua_pushinteger(L, info->deathsound);
 	else if (fastcmp(field,"speed"))
-		lua_pushinteger(L, info->speed);
+		lua_pushinteger(L, info->speed); // sometimes it's fixed_t, sometimes it's not...
 	else if (fastcmp(field,"radius"))
-		lua_pushinteger(L, info->radius);
+		lua_pushfixed(L, info->radius);
 	else if (fastcmp(field,"height"))
-		lua_pushinteger(L, info->height);
+		lua_pushfixed(L, info->height);
 	else if (fastcmp(field,"dispoffset"))
 		lua_pushinteger(L, info->dispoffset);
 	else if (fastcmp(field,"mass"))
@@ -656,11 +654,11 @@ static int mobjinfo_set(lua_State *L)
 	else if (fastcmp(field,"deathsound"))
 		info->deathsound = luaL_checkinteger(L, 3);
 	else if (fastcmp(field,"speed"))
-		info->speed = (fixed_t)luaL_checkinteger(L, 3);
+		info->speed = luaL_checkfixed(L, 3);
 	else if (fastcmp(field,"radius"))
-		info->radius = (fixed_t)luaL_checkinteger(L, 3);
+		info->radius = luaL_checkfixed(L, 3);
 	else if (fastcmp(field,"height"))
-		info->height = (fixed_t)luaL_checkinteger(L, 3);
+		info->height = luaL_checkfixed(L, 3);
 	else if (fastcmp(field,"dispoffset"))
 		info->dispoffset = (INT32)luaL_checkinteger(L, 3);
 	else if (fastcmp(field,"mass"))
diff --git a/src/lua_maplib.c b/src/lua_maplib.c
index e5cc30c12571a3ce8f047f257add6fb0bf062841..0a12478cae32a289b3f4c9dda204bbf0d253f610 100644
--- a/src/lua_maplib.c
+++ b/src/lua_maplib.c
@@ -280,10 +280,10 @@ static int sector_get(lua_State *L)
 		lua_pushboolean(L, 1);
 		return 1;
 	case sector_floorheight:
-		lua_pushinteger(L, sector->floorheight);
+		lua_pushfixed(L, sector->floorheight);
 		return 1;
 	case sector_ceilingheight:
-		lua_pushinteger(L, sector->ceilingheight);
+		lua_pushfixed(L, sector->ceilingheight);
 		return 1;
 	case sector_floorpic: { // floorpic
 		levelflat_t *levelflat;
@@ -396,26 +396,30 @@ static int sector_set(lua_State *L)
 		return luaL_error(L, "sector_t field " LUA_QS " cannot be set.", sector_opt[field]);
 	case sector_floorheight: { // floorheight
 		boolean flag;
+		mobj_t *ptmthing = tmthing;
 		fixed_t lastpos = sector->floorheight;
-		sector->floorheight = (fixed_t)luaL_checkinteger(L, 3);
+		sector->floorheight = luaL_checkfixed(L, 3);
 		flag = P_CheckSector(sector, true);
 		if (flag && sector->numattached)
 		{
 			sector->floorheight = lastpos;
 			P_CheckSector(sector, true);
 		}
+		P_SetTarget(&tmthing, ptmthing);
 		break;
 	}
 	case sector_ceilingheight: { // ceilingheight
 		boolean flag;
+		mobj_t *ptmthing = tmthing;
 		fixed_t lastpos = sector->ceilingheight;
-		sector->ceilingheight = (fixed_t)luaL_checkinteger(L, 3);
+		sector->ceilingheight = luaL_checkfixed(L, 3);
 		flag = P_CheckSector(sector, true);
 		if (flag && sector->numattached)
 		{
 			sector->ceilingheight = lastpos;
 			P_CheckSector(sector, true);
 		}
+		P_SetTarget(&tmthing, ptmthing);
 		break;
 	}
 	case sector_floorpic:
@@ -509,10 +513,10 @@ static int line_get(lua_State *L)
 		LUA_PushUserdata(L, line->v2, META_VERTEX);
 		return 1;
 	case line_dx:
-		lua_pushinteger(L, line->dx);
+		lua_pushfixed(L, line->dx);
 		return 1;
 	case line_dy:
-		lua_pushinteger(L, line->dy);
+		lua_pushfixed(L, line->dy);
 		return 1;
 	case line_flags:
 		lua_pushinteger(L, line->flags);
@@ -628,10 +632,10 @@ static int side_get(lua_State *L)
 		lua_pushboolean(L, 1);
 		return 1;
 	case side_textureoffset:
-		lua_pushinteger(L, side->textureoffset);
+		lua_pushfixed(L, side->textureoffset);
 		return 1;
 	case side_rowoffset:
-		lua_pushinteger(L, side->rowoffset);
+		lua_pushfixed(L, side->rowoffset);
 		return 1;
 	case side_toptexture:
 		lua_pushinteger(L, side->toptexture);
@@ -658,6 +662,50 @@ static int side_get(lua_State *L)
 	return 0;
 }
 
+static int side_set(lua_State *L)
+{
+	side_t *side = *((side_t **)luaL_checkudata(L, 1, META_SIDE));
+	enum side_e field = luaL_checkoption(L, 2, side_opt[0], side_opt);
+
+	if (!side)
+	{
+		if (field == side_valid) {
+			lua_pushboolean(L, 0);
+			return 1;
+		}
+		return luaL_error(L, "accessed side_t doesn't exist anymore.");
+	}
+
+	switch(field)
+	{
+	case side_valid: // valid
+	case side_sector:
+	case side_special:
+	case side_text:
+	default:
+		return luaL_error(L, "side_t field " LUA_QS " cannot be set.", side_opt[field]);
+	case side_textureoffset:
+		side->textureoffset = luaL_checkfixed(L, 3);
+		break;
+	case side_rowoffset:
+		side->rowoffset = luaL_checkfixed(L, 3);
+		break;
+	case side_toptexture:
+        side->toptexture = luaL_checkinteger(L, 3);
+		break;
+	case side_bottomtexture:
+        side->bottomtexture = luaL_checkinteger(L, 3);
+		break;
+	case side_midtexture:
+        side->midtexture = luaL_checkinteger(L, 3);
+		break;
+	case side_repeatcnt:
+        side->repeatcnt = luaL_checkinteger(L, 3);
+		break;
+	}
+	return 0;
+}
+
 static int side_num(lua_State *L)
 {
 	side_t *side = *((side_t **)luaL_checkudata(L, 1, META_SIDE));
@@ -685,13 +733,13 @@ static int vertex_get(lua_State *L)
 		lua_pushboolean(L, 1);
 		return 1;
 	case vertex_x:
-		lua_pushinteger(L, vertex->x);
+		lua_pushfixed(L, vertex->x);
 		return 1;
 	case vertex_y:
-		lua_pushinteger(L, vertex->y);
+		lua_pushfixed(L, vertex->y);
 		return 1;
 	case vertex_z:
-		lua_pushinteger(L, vertex->z);
+		lua_pushfixed(L, vertex->z);
 		return 1;
 	}
 	return 0;
@@ -954,7 +1002,7 @@ static int ffloor_get(lua_State *L)
 		lua_pushboolean(L, 1);
 		return 1;
 	case ffloor_topheight:
-		lua_pushinteger(L, *ffloor->topheight);
+		lua_pushfixed(L, *ffloor->topheight);
 		return 1;
 	case ffloor_toppic: { // toppic
 		levelflat_t *levelflat;
@@ -968,7 +1016,7 @@ static int ffloor_get(lua_State *L)
 		lua_pushinteger(L, *ffloor->toplightlevel);
 		return 1;
 	case ffloor_bottomheight:
-		lua_pushinteger(L, *ffloor->bottomheight);
+		lua_pushfixed(L, *ffloor->bottomheight);
 		return 1;
 	case ffloor_bottompic: { // bottompic
 		levelflat_t *levelflat;
@@ -1027,14 +1075,16 @@ static int ffloor_set(lua_State *L)
 	case ffloor_topheight: { // topheight
 		boolean flag;
 		fixed_t lastpos = *ffloor->topheight;
+		mobj_t *ptmthing = tmthing;
 		sector_t *sector = &sectors[ffloor->secnum];
-		sector->ceilingheight = (fixed_t)luaL_checkinteger(L, 3);
+		sector->ceilingheight = luaL_checkfixed(L, 3);
 		flag = P_CheckSector(sector, true);
 		if (flag && sector->numattached)
 		{
 			*ffloor->topheight = lastpos;
 			P_CheckSector(sector, true);
 		}
+		P_SetTarget(&tmthing, ptmthing);
 		break;
 	}
 	case ffloor_toppic:
@@ -1046,14 +1096,16 @@ static int ffloor_set(lua_State *L)
 	case ffloor_bottomheight: { // bottomheight
 		boolean flag;
 		fixed_t lastpos = *ffloor->bottomheight;
+		mobj_t *ptmthing = tmthing;
 		sector_t *sector = &sectors[ffloor->secnum];
-		sector->floorheight = (fixed_t)luaL_checkinteger(L, 3);
+		sector->floorheight = luaL_checkfixed(L, 3);
 		flag = P_CheckSector(sector, true);
 		if (flag && sector->numattached)
 		{
 			*ffloor->bottomheight = lastpos;
 			P_CheckSector(sector, true);
 		}
+		P_SetTarget(&tmthing, ptmthing);
 		break;
 	}
 	case ffloor_bottompic:
@@ -1214,6 +1266,9 @@ int LUA_MapLib(lua_State *L)
 		lua_pushcfunction(L, side_get);
 		lua_setfield(L, -2, "__index");
 
+		lua_pushcfunction(L, side_set);
+		lua_setfield(L, -2, "__newindex");
+
 		lua_pushcfunction(L, side_num);
 		lua_setfield(L, -2, "__len");
 	lua_pop(L, 1);
diff --git a/src/lua_mathlib.c b/src/lua_mathlib.c
index f8b33ffd2ad08bfc10de72dc7e2195e91a2bd9c6..8ca2e17af8283bfc9fcdd2eab28a6d8131bfa6b6 100644
--- a/src/lua_mathlib.c
+++ b/src/lua_mathlib.c
@@ -47,37 +47,37 @@ static int lib_max(lua_State *L)
 
 static int lib_fixedangle(lua_State *L)
 {
-	lua_pushinteger(L, FixedAngle((fixed_t)luaL_checkinteger(L, 1)));
+	lua_pushangle(L, FixedAngle(luaL_checkfixed(L, 1)));
 	return 1;
 }
 
 static int lib_anglefixed(lua_State *L)
 {
-	lua_pushinteger(L, AngleFixed((angle_t)luaL_checkinteger(L, 1)));
+	lua_pushfixed(L, AngleFixed(luaL_checkangle(L, 1)));
 	return 1;
 }
 
 static int lib_invangle(lua_State *L)
 {
-	lua_pushinteger(L, InvAngle((angle_t)luaL_checkinteger(L, 1)));
+	lua_pushangle(L, InvAngle(luaL_checkangle(L, 1)));
 	return 1;
 }
 
 static int lib_finesine(lua_State *L)
 {
-	lua_pushinteger(L, FINESINE((luaL_checkinteger(L, 1)>>ANGLETOFINESHIFT) & FINEMASK));
+	lua_pushfixed(L, FINESINE((luaL_checkangle(L, 1)>>ANGLETOFINESHIFT) & FINEMASK));
 	return 1;
 }
 
 static int lib_finecosine(lua_State *L)
 {
-	lua_pushinteger(L, FINECOSINE((luaL_checkinteger(L, 1)>>ANGLETOFINESHIFT) & FINEMASK));
+	lua_pushfixed(L, FINECOSINE((luaL_checkangle(L, 1)>>ANGLETOFINESHIFT) & FINEMASK));
 	return 1;
 }
 
 static int lib_finetangent(lua_State *L)
 {
-	lua_pushinteger(L, FINETANGENT((luaL_checkinteger(L, 1)>>ANGLETOFINESHIFT) & FINEMASK));
+	lua_pushfixed(L, FINETANGENT((luaL_checkangle(L, 1)>>ANGLETOFINESHIFT) & FINEMASK));
 	return 1;
 }
 
@@ -86,61 +86,61 @@ static int lib_finetangent(lua_State *L)
 
 static int lib_fixedmul(lua_State *L)
 {
-	lua_pushinteger(L, FixedMul((fixed_t)luaL_checkinteger(L, 1), (fixed_t)luaL_checkinteger(L, 2)));
+	lua_pushfixed(L, FixedMul(luaL_checkfixed(L, 1), luaL_checkfixed(L, 2)));
 	return 1;
 }
 
 static int lib_fixedint(lua_State *L)
 {
-	lua_pushinteger(L, FixedInt((fixed_t)luaL_checkinteger(L, 1)));
+	lua_pushinteger(L, FixedInt(luaL_checkfixed(L, 1)));
 	return 1;
 }
 
 static int lib_fixeddiv(lua_State *L)
 {
-	lua_pushinteger(L, FixedDiv((fixed_t)luaL_checkinteger(L, 1), (fixed_t)luaL_checkinteger(L, 2)));
+	lua_pushfixed(L, FixedDiv(luaL_checkfixed(L, 1), luaL_checkfixed(L, 2)));
 	return 1;
 }
 
 static int lib_fixedrem(lua_State *L)
 {
-	lua_pushinteger(L, FixedRem((fixed_t)luaL_checkinteger(L, 1), (fixed_t)luaL_checkinteger(L, 2)));
+	lua_pushfixed(L, FixedRem(luaL_checkfixed(L, 1), luaL_checkfixed(L, 2)));
 	return 1;
 }
 
 static int lib_fixedsqrt(lua_State *L)
 {
-	lua_pushinteger(L, FixedSqrt((fixed_t)luaL_checkinteger(L, 1)));
+	lua_pushfixed(L, FixedSqrt(luaL_checkfixed(L, 1)));
 	return 1;
 }
 
 static int lib_fixedhypot(lua_State *L)
 {
-	lua_pushinteger(L, FixedHypot((fixed_t)luaL_checkinteger(L, 1), (fixed_t)luaL_checkinteger(L, 2)));
+	lua_pushfixed(L, FixedHypot(luaL_checkfixed(L, 1), luaL_checkfixed(L, 2)));
 	return 1;
 }
 
 static int lib_fixedfloor(lua_State *L)
 {
-	lua_pushinteger(L, FixedFloor((fixed_t)luaL_checkinteger(L, 1)));
+	lua_pushfixed(L, FixedFloor(luaL_checkfixed(L, 1)));
 	return 1;
 }
 
 static int lib_fixedtrunc(lua_State *L)
 {
-	lua_pushinteger(L, FixedTrunc((fixed_t)luaL_checkinteger(L, 1)));
+	lua_pushfixed(L, FixedTrunc(luaL_checkfixed(L, 1)));
 	return 1;
 }
 
 static int lib_fixedceil(lua_State *L)
 {
-	lua_pushinteger(L, FixedCeil((fixed_t)luaL_checkinteger(L, 1)));
+	lua_pushfixed(L, FixedCeil(luaL_checkfixed(L, 1)));
 	return 1;
 }
 
 static int lib_fixedround(lua_State *L)
 {
-	lua_pushinteger(L, FixedRound((fixed_t)luaL_checkinteger(L, 1)));
+	lua_pushfixed(L, FixedRound(luaL_checkfixed(L, 1)));
 	return 1;
 }
 
@@ -156,7 +156,7 @@ static int lib_getsecspecial(lua_State *L)
 
 static int lib_all7emeralds(lua_State *L)
 {
-	lua_pushinteger(L, ALL7EMERALDS(luaL_checkinteger(L, 1)));
+	lua_pushboolean(L, ALL7EMERALDS(luaL_checkinteger(L, 1)));
 	return 1;
 }
 
diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c
index 31496ed9c01b651c733b5034b8c95c4f9d044c94..83e7039e4bbacb68079f78d62020bdb388a1f3ac 100644
--- a/src/lua_mobjlib.c
+++ b/src/lua_mobjlib.c
@@ -162,13 +162,13 @@ static int mobj_get(lua_State *L)
 		lua_pushboolean(L, 1);
 		break;
 	case mobj_x:
-		lua_pushinteger(L, mo->x);
+		lua_pushfixed(L, mo->x);
 		break;
 	case mobj_y:
-		lua_pushinteger(L, mo->y);
+		lua_pushfixed(L, mo->y);
 		break;
 	case mobj_z:
-		lua_pushinteger(L, mo->z);
+		lua_pushfixed(L, mo->z);
 		break;
 	case mobj_snext:
 		LUA_PushUserdata(L, mo->snext, META_MOBJ);
@@ -179,7 +179,7 @@ static int mobj_get(lua_State *L)
 		// i.e. it will always ultimately point to THIS mobj -- so that's actually not useful to Lua and won't be included.
 		return UNIMPLEMENTED;
 	case mobj_angle:
-		lua_pushinteger(L, mo->angle);
+		lua_pushangle(L, mo->angle);
 		break;
 	case mobj_sprite:
 		lua_pushinteger(L, mo->sprite);
@@ -193,28 +193,28 @@ static int mobj_get(lua_State *L)
 		LUA_PushUserdata(L, mo->subsector, META_SUBSECTOR);
 		break;
 	case mobj_floorz:
-		lua_pushinteger(L, mo->floorz);
+		lua_pushfixed(L, mo->floorz);
 		break;
 	case mobj_ceilingz:
-		lua_pushinteger(L, mo->ceilingz);
+		lua_pushfixed(L, mo->ceilingz);
 		break;
 	case mobj_radius:
-		lua_pushinteger(L, mo->radius);
+		lua_pushfixed(L, mo->radius);
 		break;
 	case mobj_height:
-		lua_pushinteger(L, mo->height);
+		lua_pushfixed(L, mo->height);
 		break;
 	case mobj_momx:
-		lua_pushinteger(L, mo->momx);
+		lua_pushfixed(L, mo->momx);
 		break;
 	case mobj_momy:
-		lua_pushinteger(L, mo->momy);
+		lua_pushfixed(L, mo->momy);
 		break;
 	case mobj_momz:
-		lua_pushinteger(L, mo->momz);
+		lua_pushfixed(L, mo->momz);
 		break;
 	case mobj_pmomz:
-		lua_pushinteger(L, mo->pmomz);
+		lua_pushfixed(L, mo->pmomz);
 		break;
 	case mobj_tics:
 		lua_pushinteger(L, mo->tics);
@@ -299,32 +299,32 @@ static int mobj_get(lua_State *L)
 		LUA_PushUserdata(L, mo->tracer, META_MOBJ);
 		break;
 	case mobj_friction:
-		lua_pushinteger(L, mo->friction);
+		lua_pushfixed(L, mo->friction);
 		break;
 	case mobj_movefactor:
-		lua_pushinteger(L, mo->movefactor);
+		lua_pushfixed(L, mo->movefactor);
 		break;
 	case mobj_fuse:
 		lua_pushinteger(L, mo->fuse);
 		break;
 	case mobj_watertop:
-		lua_pushinteger(L, mo->watertop);
+		lua_pushfixed(L, mo->watertop);
 		break;
 	case mobj_waterbottom:
-		lua_pushinteger(L, mo->waterbottom);
+		lua_pushfixed(L, mo->waterbottom);
 		break;
 	case mobj_mobjnum:
 		// mobjnum is a networking thing generated for $$$.sav
 		// and therefore shouldn't be used by Lua.
 		return UNIMPLEMENTED;
 	case mobj_scale:
-		lua_pushinteger(L, mo->scale);
+		lua_pushfixed(L, mo->scale);
 		break;
 	case mobj_destscale:
-		lua_pushinteger(L, mo->destscale);
+		lua_pushfixed(L, mo->destscale);
 		break;
 	case mobj_scalespeed:
-		lua_pushinteger(L, mo->scalespeed);
+		lua_pushfixed(L, mo->scalespeed);
 		break;
 	case mobj_extravalue1:
 		lua_pushinteger(L, mo->extravalue1);
@@ -382,7 +382,7 @@ static int mobj_set(lua_State *L)
 	{
 		// z doesn't cross sector bounds so it's okay.
 		mobj_t *ptmthing = tmthing;
-		mo->z = (fixed_t)luaL_checkinteger(L, 3);
+		mo->z = luaL_checkfixed(L, 3);
 		P_CheckPosition(mo, mo->x, mo->y);
 		mo->floorz = tmfloorz;
 		mo->ceilingz = tmceilingz;
@@ -394,7 +394,7 @@ static int mobj_set(lua_State *L)
 	case mobj_sprev:
 		return UNIMPLEMENTED;
 	case mobj_angle:
-		mo->angle = (angle_t)luaL_checkinteger(L, 3);
+		mo->angle = luaL_checkangle(L, 3);
 		if (mo->player == &players[consoleplayer])
 			localangle = mo->angle;
 		else if (mo->player == &players[secondarydisplayplayer])
@@ -417,7 +417,7 @@ static int mobj_set(lua_State *L)
 	case mobj_radius:
 	{
 		mobj_t *ptmthing = tmthing;
-		mo->radius = (fixed_t)luaL_checkinteger(L, 3);
+		mo->radius = luaL_checkfixed(L, 3);
 		if (mo->radius < 0)
 			mo->radius = 0;
 		P_CheckPosition(mo, mo->x, mo->y);
@@ -429,7 +429,7 @@ static int mobj_set(lua_State *L)
 	case mobj_height:
 	{
 		mobj_t *ptmthing = tmthing;
-		mo->height = (fixed_t)luaL_checkinteger(L, 3);
+		mo->height = luaL_checkfixed(L, 3);
 		if (mo->height < 0)
 			mo->height = 0;
 		P_CheckPosition(mo, mo->x, mo->y);
@@ -439,16 +439,16 @@ static int mobj_set(lua_State *L)
 		break;
 	}
 	case mobj_momx:
-		mo->momx = (fixed_t)luaL_checkinteger(L, 3);
+		mo->momx = luaL_checkfixed(L, 3);
 		break;
 	case mobj_momy:
-		mo->momy = (fixed_t)luaL_checkinteger(L, 3);
+		mo->momy = luaL_checkfixed(L, 3);
 		break;
 	case mobj_momz:
-		mo->momz = (fixed_t)luaL_checkinteger(L, 3);
+		mo->momz = luaL_checkfixed(L, 3);
 		break;
 	case mobj_pmomz:
-		mo->pmomz = (fixed_t)luaL_checkinteger(L, 3);
+		mo->pmomz = luaL_checkfixed(L, 3);
 		mo->eflags |= MFE_APPLYPMOMZ;
 		break;
 	case mobj_tics:
@@ -573,25 +573,25 @@ static int mobj_set(lua_State *L)
 		}
 		break;
 	case mobj_friction:
-		mo->friction = (fixed_t)luaL_checkinteger(L, 3);
+		mo->friction = luaL_checkfixed(L, 3);
 		break;
 	case mobj_movefactor:
-		mo->movefactor = (fixed_t)luaL_checkinteger(L, 3);
+		mo->movefactor = luaL_checkfixed(L, 3);
 		break;
 	case mobj_fuse:
 		mo->fuse = luaL_checkinteger(L, 3);
 		break;
 	case mobj_watertop:
-		mo->watertop = (fixed_t)luaL_checkinteger(L, 3);
+		mo->watertop = luaL_checkfixed(L, 3);
 		break;
 	case mobj_waterbottom:
-		mo->waterbottom = (fixed_t)luaL_checkinteger(L, 3);
+		mo->waterbottom = luaL_checkfixed(L, 3);
 		break;
 	case mobj_mobjnum:
 		return UNIMPLEMENTED;
 	case mobj_scale:
 	{
-		fixed_t scale = (fixed_t)luaL_checkinteger(L, 3);
+		fixed_t scale = luaL_checkfixed(L, 3);
 		if (scale < FRACUNIT/100)
 			scale = FRACUNIT/100;
 		mo->destscale = scale;
@@ -600,14 +600,14 @@ static int mobj_set(lua_State *L)
 	}
 	case mobj_destscale:
 	{
-		fixed_t scale = (fixed_t)luaL_checkinteger(L, 3);
+		fixed_t scale = luaL_checkfixed(L, 3);
 		if (scale < FRACUNIT/100)
 			scale = FRACUNIT/100;
 		mo->destscale = scale;
 		break;
 	}
 	case mobj_scalespeed:
-		mo->scalespeed = (fixed_t)luaL_checkinteger(L, 3);
+		mo->scalespeed = luaL_checkfixed(L, 3);
 		break;
 	case mobj_extravalue1:
 		mo->extravalue1 = luaL_checkinteger(L, 3);
diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c
index 7f64fff626e1fcec551daee0a20ded1b5c220917..64513ab9728e6a2e4c7723e3a80ef36ceb9bee59 100644
--- a/src/lua_playerlib.c
+++ b/src/lua_playerlib.c
@@ -109,15 +109,15 @@ static int player_get(lua_State *L)
 	else if (fastcmp(field,"playerstate"))
 		lua_pushinteger(L, plr->playerstate);
 	else if (fastcmp(field,"viewz"))
-		lua_pushinteger(L, plr->viewz);
+		lua_pushfixed(L, plr->viewz);
 	else if (fastcmp(field,"viewheight"))
-		lua_pushinteger(L, plr->viewheight);
+		lua_pushfixed(L, plr->viewheight);
 	else if (fastcmp(field,"deltaviewheight"))
-		lua_pushinteger(L, plr->deltaviewheight);
+		lua_pushfixed(L, plr->deltaviewheight);
 	else if (fastcmp(field,"bob"))
-		lua_pushinteger(L, plr->bob);
+		lua_pushfixed(L, plr->bob);
 	else if (fastcmp(field,"aiming"))
-		lua_pushinteger(L, plr->aiming);
+		lua_pushangle(L, plr->aiming);
 	else if (fastcmp(field,"health"))
 		lua_pushinteger(L, plr->health);
 	else if (fastcmp(field,"pity"))
@@ -141,13 +141,13 @@ static int player_get(lua_State *L)
 	else if (fastcmp(field,"score"))
 		lua_pushinteger(L, plr->score);
 	else if (fastcmp(field,"dashspeed"))
-		lua_pushinteger(L, plr->dashspeed);
+		lua_pushfixed(L, plr->dashspeed);
 	else if (fastcmp(field,"dashtime"))
 		lua_pushinteger(L, plr->dashtime);
 	else if (fastcmp(field,"normalspeed"))
-		lua_pushinteger(L, plr->normalspeed);
+		lua_pushfixed(L, plr->normalspeed);
 	else if (fastcmp(field,"runspeed"))
-		lua_pushinteger(L, plr->runspeed);
+		lua_pushfixed(L, plr->runspeed);
 	else if (fastcmp(field,"thrustfactor"))
 		lua_pushinteger(L, plr->thrustfactor);
 	else if (fastcmp(field,"accelstart"))
@@ -167,13 +167,13 @@ static int player_get(lua_State *L)
 	else if (fastcmp(field,"revitem"))
 		lua_pushinteger(L, plr->revitem);
 	else if (fastcmp(field,"actionspd"))
-		lua_pushinteger(L, plr->actionspd);
+		lua_pushfixed(L, plr->actionspd);
 	else if (fastcmp(field,"mindash"))
-		lua_pushinteger(L, plr->mindash);
+		lua_pushfixed(L, plr->mindash);
 	else if (fastcmp(field,"maxdash"))
-		lua_pushinteger(L, plr->maxdash);
+		lua_pushfixed(L, plr->maxdash);
 	else if (fastcmp(field,"jumpfactor"))
-		lua_pushinteger(L, plr->jumpfactor);
+		lua_pushfixed(L, plr->jumpfactor);
 	else if (fastcmp(field,"lives"))
 		lua_pushinteger(L, plr->lives);
 	else if (fastcmp(field,"continues"))
@@ -183,7 +183,7 @@ static int player_get(lua_State *L)
 	else if (fastcmp(field,"gotcontinue"))
 		lua_pushinteger(L, plr->gotcontinue);
 	else if (fastcmp(field,"speed"))
-		lua_pushinteger(L, plr->speed);
+		lua_pushfixed(L, plr->speed);
 	else if (fastcmp(field,"jumping"))
 		lua_pushboolean(L, plr->jumping);
 	else if (fastcmp(field,"secondjump"))
@@ -205,13 +205,13 @@ static int player_get(lua_State *L)
 	else if (fastcmp(field,"skidtime"))
 		lua_pushinteger(L, plr->skidtime);
 	else if (fastcmp(field,"cmomx"))
-		lua_pushinteger(L, plr->cmomx);
+		lua_pushfixed(L, plr->cmomx);
 	else if (fastcmp(field,"cmomy"))
-		lua_pushinteger(L, plr->cmomy);
+		lua_pushfixed(L, plr->cmomy);
 	else if (fastcmp(field,"rmomx"))
-		lua_pushinteger(L, plr->rmomx);
+		lua_pushfixed(L, plr->rmomx);
 	else if (fastcmp(field,"rmomy"))
-		lua_pushinteger(L, plr->rmomy);
+		lua_pushfixed(L, plr->rmomy);
 	else if (fastcmp(field,"numboxes"))
 		lua_pushinteger(L, plr->numboxes);
 	else if (fastcmp(field,"totalring"))
@@ -239,11 +239,11 @@ static int player_get(lua_State *L)
 	else if (fastcmp(field,"starposttime"))
 		lua_pushinteger(L, plr->starposttime);
 	else if (fastcmp(field,"starpostangle"))
-		lua_pushinteger(L, plr->starpostangle);
+		lua_pushangle(L, plr->starpostangle);
 	else if (fastcmp(field,"angle_pos"))
-		lua_pushinteger(L, plr->angle_pos);
+		lua_pushangle(L, plr->angle_pos);
 	else if (fastcmp(field,"old_angle_pos"))
-		lua_pushinteger(L, plr->old_angle_pos);
+		lua_pushangle(L, plr->old_angle_pos);
 	else if (fastcmp(field,"axis1"))
 		LUA_PushUserdata(L, plr->axis1, META_MOBJ);
 	else if (fastcmp(field,"axis2"))
@@ -305,16 +305,16 @@ static int player_get(lua_State *L)
 	else if (fastcmp(field,"awayviewtics"))
 		lua_pushinteger(L, plr->awayviewtics);
 	else if (fastcmp(field,"awayviewaiming"))
-		lua_pushinteger(L, plr->awayviewaiming);
+		lua_pushangle(L, plr->awayviewaiming);
 	else if (fastcmp(field,"spectator"))
-		lua_pushinteger(L, plr->spectator);
+		lua_pushboolean(L, plr->spectator);
 	else if (fastcmp(field,"bot"))
 		lua_pushinteger(L, plr->bot);
 	else if (fastcmp(field,"jointime"))
 		lua_pushinteger(L, plr->jointime);
 #ifdef HWRENDER
 	else if (fastcmp(field,"fovadd"))
-		lua_pushinteger(L, plr->fovadd);
+		lua_pushfixed(L, plr->fovadd);
 #endif
 	else {
 		lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
@@ -354,15 +354,15 @@ static int player_set(lua_State *L)
 	else if (fastcmp(field,"playerstate"))
 		plr->playerstate = luaL_checkinteger(L, 3);
 	else if (fastcmp(field,"viewz"))
-		plr->viewz = (fixed_t)luaL_checkinteger(L, 3);
+		plr->viewz = luaL_checkfixed(L, 3);
 	else if (fastcmp(field,"viewheight"))
-		plr->viewheight = (fixed_t)luaL_checkinteger(L, 3);
+		plr->viewheight = luaL_checkfixed(L, 3);
 	else if (fastcmp(field,"deltaviewheight"))
-		plr->deltaviewheight = (fixed_t)luaL_checkinteger(L, 3);
+		plr->deltaviewheight = luaL_checkfixed(L, 3);
 	else if (fastcmp(field,"bob"))
-		plr->bob = (fixed_t)luaL_checkinteger(L, 3);
+		plr->bob = luaL_checkfixed(L, 3);
 	else if (fastcmp(field,"aiming")) {
-		plr->aiming = (angle_t)luaL_checkinteger(L, 3);
+		plr->aiming = luaL_checkangle(L, 3);
 		if (plr == &players[consoleplayer])
 			localaiming = plr->aiming;
 		else if (plr == &players[secondarydisplayplayer])
@@ -391,13 +391,13 @@ static int player_set(lua_State *L)
 	else if (fastcmp(field,"score"))
 		plr->score = (UINT32)luaL_checkinteger(L, 3);
 	else if (fastcmp(field,"dashspeed"))
-		plr->dashspeed = (fixed_t)luaL_checkinteger(L, 3);
+		plr->dashspeed = luaL_checkfixed(L, 3);
 	else if (fastcmp(field,"dashtime"))
 		plr->dashtime = (INT32)luaL_checkinteger(L, 3);
 	else if (fastcmp(field,"normalspeed"))
-		plr->normalspeed = (fixed_t)luaL_checkinteger(L, 3);
+		plr->normalspeed = luaL_checkfixed(L, 3);
 	else if (fastcmp(field,"runspeed"))
-		plr->runspeed = (fixed_t)luaL_checkinteger(L, 3);
+		plr->runspeed = luaL_checkfixed(L, 3);
 	else if (fastcmp(field,"thrustfactor"))
 		plr->thrustfactor = (UINT8)luaL_checkinteger(L, 3);
 	else if (fastcmp(field,"accelstart"))
@@ -433,7 +433,7 @@ static int player_set(lua_State *L)
 	else if (fastcmp(field,"gotcontinue"))
 		plr->gotcontinue = (UINT8)luaL_checkinteger(L, 3);
 	else if (fastcmp(field,"speed"))
-		plr->speed = (fixed_t)luaL_checkinteger(L, 3);
+		plr->speed = luaL_checkfixed(L, 3);
 	else if (fastcmp(field,"jumping"))
 		plr->jumping = luaL_checkboolean(L, 3);
 	else if (fastcmp(field,"secondjump"))
@@ -455,13 +455,13 @@ static int player_set(lua_State *L)
 	else if (fastcmp(field,"skidtime"))
 		plr->skidtime = (tic_t)luaL_checkinteger(L, 3);
 	else if (fastcmp(field,"cmomx"))
-		plr->cmomx = (fixed_t)luaL_checkinteger(L, 3);
+		plr->cmomx = luaL_checkfixed(L, 3);
 	else if (fastcmp(field,"cmomy"))
-		plr->cmomy = (fixed_t)luaL_checkinteger(L, 3);
+		plr->cmomy = luaL_checkfixed(L, 3);
 	else if (fastcmp(field,"rmomx"))
-		plr->rmomx = (fixed_t)luaL_checkinteger(L, 3);
+		plr->rmomx = luaL_checkfixed(L, 3);
 	else if (fastcmp(field,"rmomy"))
-		plr->rmomy = (fixed_t)luaL_checkinteger(L, 3);
+		plr->rmomy = luaL_checkfixed(L, 3);
 	else if (fastcmp(field,"numboxes"))
 		plr->numboxes = (INT16)luaL_checkinteger(L, 3);
 	else if (fastcmp(field,"totalring"))
@@ -489,11 +489,11 @@ static int player_set(lua_State *L)
 	else if (fastcmp(field,"starposttime"))
 		plr->starposttime = (tic_t)luaL_checkinteger(L, 3);
 	else if (fastcmp(field,"starpostangle"))
-		plr->starpostangle = (angle_t)luaL_checkinteger(L, 3);
+		plr->starpostangle = luaL_checkangle(L, 3);
 	else if (fastcmp(field,"angle_pos"))
-		plr->angle_pos = (angle_t)luaL_checkinteger(L, 3);
+		plr->angle_pos = luaL_checkangle(L, 3);
 	else if (fastcmp(field,"old_angle_pos"))
-		plr->old_angle_pos = (angle_t)luaL_checkinteger(L, 3);
+		plr->old_angle_pos = luaL_checkangle(L, 3);
 	else if (fastcmp(field,"axis1"))
 		P_SetTarget(&plr->axis1, *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)));
 	else if (fastcmp(field,"axis2"))
@@ -569,7 +569,7 @@ static int player_set(lua_State *L)
 			P_SetTarget(&plr->awayviewmobj, plr->mo); // but since the script might set awayviewmobj immediately AFTER setting awayviewtics, use player mobj as filler for now.
 	}
 	else if (fastcmp(field,"awayviewaiming"))
-		plr->awayviewaiming = (angle_t)luaL_checkinteger(L, 3);
+		plr->awayviewaiming = luaL_checkangle(L, 3);
 	else if (fastcmp(field,"spectator"))
 		plr->spectator = lua_toboolean(L, 3);
 	else if (fastcmp(field,"bot"))
@@ -578,7 +578,7 @@ static int player_set(lua_State *L)
 		plr->jointime = (tic_t)luaL_checkinteger(L, 3);
 #ifdef HWRENDER
 	else if (fastcmp(field,"fovadd"))
-		plr->fovadd = (fixed_t)luaL_checkinteger(L, 3);
+		plr->fovadd = luaL_checkfixed(L, 3);
 #endif
 	else {
 		lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
diff --git a/src/lua_script.c b/src/lua_script.c
index 8b40d9f00b5ab9aed332ec84ae67fd1c4fa4dbe1..145104d9aac8c0c147bde29259377f8848512d81 100644
--- a/src/lua_script.c
+++ b/src/lua_script.c
@@ -442,7 +442,6 @@ enum
 	ARCH_NULL=0,
 	ARCH_BOOLEAN,
 	ARCH_SIGNED,
-	ARCH_UNSIGNED,
 	ARCH_STRING,
 	ARCH_TABLE,
 
@@ -522,13 +521,8 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
 	case LUA_TNUMBER:
 	{
 		lua_Integer number = lua_tointeger(gL, myindex);
-		if (number < 0) {
-			WRITEUINT8(save_p, ARCH_SIGNED);
-			WRITEFIXED(save_p, number);
-		} else {
-			WRITEUINT8(save_p, ARCH_UNSIGNED);
-			WRITEANGLE(save_p, number);
-		}
+        WRITEUINT8(save_p, ARCH_SIGNED);
+        WRITEFIXED(save_p, number);
 		break;
 	}
 	case LUA_TSTRING:
@@ -797,9 +791,6 @@ static UINT8 UnArchiveValue(int TABLESINDEX)
 	case ARCH_SIGNED:
 		lua_pushinteger(gL, READFIXED(save_p));
 		break;
-	case ARCH_UNSIGNED:
-		lua_pushinteger(gL, READANGLE(save_p));
-		break;
 	case ARCH_STRING:
 	{
 		char value[1024];
@@ -948,6 +939,14 @@ static void NetArchiveHook(lua_CFunction archFunc)
 	lua_pop(gL, 2);
 }
 
+void LUA_Step(void)
+{
+	if (!gL)
+		return;
+	lua_settop(gL, 0);
+	lua_gc(gL, LUA_GCSTEP, 1);
+}
+
 void LUA_Archive(void)
 {
 	INT32 i;
diff --git a/src/lua_script.h b/src/lua_script.h
index eaef13d1e635fce209fb1e4bc2f694dfb24b3ea8..292160a0b5356e2494d6557207dfe20c2167d993 100644
--- a/src/lua_script.h
+++ b/src/lua_script.h
@@ -19,9 +19,21 @@
 #include "blua/lua.h"
 #include "blua/lualib.h"
 #include "blua/lauxlib.h"
+
 #define lua_optboolean(L, i) (!lua_isnoneornil(L, i) && lua_toboolean(L, i))
 #define lua_opttrueboolean(L, i) (lua_isnoneornil(L, i) || lua_toboolean(L, i))
 
+// fixed_t casting
+// TODO add some distinction between fixed numbers and integer numbers
+// for at least the purpose of printing and maybe math.
+#define luaL_checkfixed(L, i) luaL_checkinteger(L, i)
+#define lua_pushfixed(L, f) lua_pushinteger(L, f)
+
+// angle_t casting
+// we reduce the angle to a fixed point between 0.0 and 1.0
+#define luaL_checkangle(L, i) (((angle_t)(luaL_checkfixed(L, i)&0xFFFF))<<16)
+#define lua_pushangle(L, a) lua_pushfixed(L, a>>16)
+
 #ifdef _DEBUG
 void LUA_ClearExtVars(void);
 #endif
@@ -36,6 +48,7 @@ void LUA_InvalidateUserdata(void *data);
 void LUA_InvalidateLevel(void);
 void LUA_InvalidateMapthings(void);
 void LUA_InvalidatePlayer(player_t *player);
+void LUA_Step(void);
 void LUA_Archive(void);
 void LUA_UnArchive(void);
 void Got_Luacmd(UINT8 **cp, INT32 playernum); // lua_consolelib.c
diff --git a/src/lua_skinlib.c b/src/lua_skinlib.c
index f797f30d6cc05a353921d6378692ff4a9fd87868..f07b4564c15d553c9b5640d03d6151fd0e69d87b 100644
--- a/src/lua_skinlib.c
+++ b/src/lua_skinlib.c
@@ -147,19 +147,19 @@ static int skin_get(lua_State *L)
 		lua_pushinteger(L, skin->revitem);
 		break;
 	case skin_actionspd:
-		lua_pushinteger(L, skin->actionspd);
+		lua_pushfixed(L, skin->actionspd);
 		break;
 	case skin_mindash:
-		lua_pushinteger(L, skin->mindash);
+		lua_pushfixed(L, skin->mindash);
 		break;
 	case skin_maxdash:
-		lua_pushinteger(L, skin->maxdash);
+		lua_pushfixed(L, skin->maxdash);
 		break;
 	case skin_normalspeed:
-		lua_pushinteger(L, skin->normalspeed);
+		lua_pushfixed(L, skin->normalspeed);
 		break;
 	case skin_runspeed:
-		lua_pushinteger(L, skin->runspeed);
+		lua_pushfixed(L, skin->runspeed);
 		break;
 	case skin_thrustfactor:
 		lua_pushinteger(L, skin->thrustfactor);
@@ -171,7 +171,7 @@ static int skin_get(lua_State *L)
 		lua_pushinteger(L, skin->acceleration);
 		break;
 	case skin_jumpfactor:
-		lua_pushinteger(L, skin->jumpfactor);
+		lua_pushfixed(L, skin->jumpfactor);
 		break;
 	case skin_starttranscolor:
 		lua_pushinteger(L, skin->starttranscolor);
diff --git a/src/p_inter.c b/src/p_inter.c
index 8eaa4765a87f7d7d8d828fc1b32a01e2370a302b..478bd459cbc1fde6fb7a8e9823052e33988e79fc 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -1478,7 +1478,7 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour
 		return; // Presumably it's obvious what's happening in splitscreen.
 
 #ifdef HAVE_BLUA
-	if (LUAh_DeathMsg(player, inflictor, source))
+	if (LUAh_HurtMsg(player, inflictor, source))
 		return;
 #endif