diff --git a/polymer/eduke32/source/game.c b/polymer/eduke32/source/game.c
index f9848730e..efb66f946 100644
--- a/polymer/eduke32/source/game.c
+++ b/polymer/eduke32/source/game.c
@@ -8725,6 +8725,7 @@ static int32_t loaddefinitions_game(const char *fn, int32_t preload)
 
 #ifdef LUNATIC
 const char **g_argv;
+const char **g_elModules;
 #endif
 
 #ifdef __APPLE__
@@ -8745,6 +8746,8 @@ static void G_CheckCommandLine(int32_t argc, const char **argv)
 
 #ifdef LUNATIC
     g_argv = argv;
+    g_elModules = Bcalloc(argc+1, sizeof(char *));
+    Bassert(g_elModules);
 #endif
     ud.fta_on = 1;
     ud.god = 0;
@@ -8780,6 +8783,9 @@ static void G_CheckCommandLine(int32_t argc, const char **argv)
 
     if (argc > 1)
     {
+#ifdef LUNATIC
+        int32_t numlmods = 0;
+#endif
         initprintf("Application parameters: ");
         while (i < argc)
             initprintf("%s ",argv[i++]);
@@ -9074,15 +9080,6 @@ static void G_CheckCommandLine(int32_t argc, const char **argv)
                     i++;
                     continue;
                 }
-                if (!Bstrcasecmp(c+1,"testlua"))
-                {
-#ifdef LUNATIC
-                    extern int32_t g_testLua;
-                    g_testLua = 1;
-#endif
-                    i++;
-                    continue;
-                }
 #if !defined(_WIN32)
                 if (!Bstrcasecmp(c+1,"usecwd"))
                 {
@@ -9403,6 +9400,13 @@ static void G_CheckCommandLine(int32_t argc, const char **argv)
                         initprintf("Using RTS file \"%s\".\n", ud.rtsname);
                         continue;
                     }
+#ifdef LUNATIC
+                    if (!Bstrcmp(k,".lua"))  // NOTE: case sensitive!
+                    {
+                        g_elModules[numlmods++] = argv[i++];
+                        continue;
+                    }
+#endif
                 }
             }
 
diff --git a/polymer/eduke32/source/lunatic/defs.ilua b/polymer/eduke32/source/lunatic/defs.ilua
index f3f86a9eb..eaf44d25e 100644
--- a/polymer/eduke32/source/lunatic/defs.ilua
+++ b/polymer/eduke32/source/lunatic/defs.ilua
@@ -575,6 +575,7 @@ const char *g_sizes_of_what[];
 int32_t g_sizes_of[];
 int32_t g_elCallDepth;
 const char **g_argv;
+const char **g_elModules;
 char g_modDir[];
 actor_t actor[MAXSPRITES];
 camera_t g_camera;
@@ -1318,8 +1319,8 @@ local function our_require(modname, ...)
 
     -- Check module name is valid first.
     -- TODO: restrict valid names?
-    if (type(modname) ~= "string") then
-        error("module name must be a string", 2)
+    if (type(modname) ~= "string" or #modname==0) then
+        error("module name must be a nonempty string", 2)
     end
 
     -- Handle the section between module() and require("end_gamevars").
@@ -1663,9 +1664,10 @@ G_.g_tile = g_tile
 ---=== Lunatic interpreter setup ===---
 
 local concode
+local g_firstRun = (ffiC.g_elCONSize == 0)
 
 --- Get Lua code for CON (+ mutator) code.
-if (ffiC.g_elCONSize == 0) then
+if (g_firstRun) then
     -- Compiling CON for the first time.
     read_into_string = readintostr_mod  -- for lunacon
     local lunacon = require("lunacon")
@@ -1823,7 +1825,7 @@ setmetatable(
 -- environment earlier.
 setfenv(0, _G)
 
--- Finally, run the CON code translated into Lua.
+-- Run the CON code translated into Lua.
 if (concode) then
     local confunc, conerrmsg = loadstring(concode, "CON")
     if (confunc == nil) then
@@ -1831,3 +1833,13 @@ if (concode) then
     end
     confunc()
 end
+
+-- When starting a map, load Lua modules given on the command line.
+if (not g_firstRun) then
+    local i=0
+    while (ffiC.g_elModules[i] ~= nil) do
+        local modname = ffi.string(ffiC.g_elModules[i])
+        our_require((modname:gsub("%.lua$","")))
+        i = i+1
+    end
+end
diff --git a/polymer/eduke32/source/lunatic/dynsymlist b/polymer/eduke32/source/lunatic/dynsymlist
index 00388a950..bbe5c8722 100644
--- a/polymer/eduke32/source/lunatic/dynsymlist
+++ b/polymer/eduke32/source/lunatic/dynsymlist
@@ -96,6 +96,7 @@ g_sizes_of;
 g_elCallDepth;
 g_RETURN;
 g_argv;
+g_elModules;
 g_modDir;
 
 MapInfo;
diff --git a/polymer/eduke32/source/lunatic/lunatic_game.c b/polymer/eduke32/source/lunatic/lunatic_game.c
index fed3eab06..be78e1d39 100644
--- a/polymer/eduke32/source/lunatic/lunatic_game.c
+++ b/polymer/eduke32/source/lunatic/lunatic_game.c
@@ -30,6 +30,7 @@ int32_t g_elCallDepth = 0;
 int32_t g_RETURN;
 
 // for timing events and actors
+static int32_t g_timingInited = 0;
 uint32_t g_eventCalls[MAXEVENTS], g_actorCalls[MAXTILES];
 double g_eventTotalMs[MAXEVENTS], g_actorTotalMs[MAXTILES], g_actorMinMs[MAXTILES], g_actorMaxMs[MAXTILES];
 
@@ -379,8 +380,12 @@ int32_t El_CreateState(L_State *estate, const char *name)
 {
     int32_t i;
 
-    for (i=0; i<MAXTILES; i++)
-        g_actorMinMs[i] = 1e308;
+    if (!g_timingInited)
+    {
+        g_timingInited = 1;
+        for (i=0; i<MAXTILES; i++)
+            g_actorMinMs[i] = 1e308;
+    }
 
     L_ErrorFunc = El_OnError;
     L_OutOfMemFunc = El_OnOutOfMem;
@@ -391,6 +396,10 @@ int32_t El_CreateState(L_State *estate, const char *name)
 void El_DestroyState(L_State *estate)
 {
     L_DestroyState(estate);
+
+    // XXX: It would be cleaner to also clear stuff like g_elEvents[], but
+    // currently, when the game Lua state is recreated, the array should have
+    // the same values as before, so we're skipping that for now.
 }
 
 
diff --git a/polymer/eduke32/source/lunatic/test.elua b/polymer/eduke32/source/lunatic/test.elua
index 567322b7e..7435860b1 100644
--- a/polymer/eduke32/source/lunatic/test.elua
+++ b/polymer/eduke32/source/lunatic/test.elua
@@ -522,4 +522,4 @@ spritesofsect(0)
 
 -- This will complain about wrong usage of 'error'. In particular,
 -- the nil must not propagate to C!
-error(nil)
+checkfail('error(nil)', "error using 'error': error message must be a string")
diff --git a/polymer/eduke32/source/premap.c b/polymer/eduke32/source/premap.c
index b4b3457b1..4020490a3 100644
--- a/polymer/eduke32/source/premap.c
+++ b/polymer/eduke32/source/premap.c
@@ -39,8 +39,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #ifdef LUNATIC
 # include "lunatic_game.h"
-
-int32_t g_testLua = 0;
 #endif
 
 halfdimen_t g_halfScreen;
@@ -1121,20 +1119,6 @@ static inline void prelevel(char g)
 
 #ifdef LUNATIC
     El_CreateGameState();
-
-    if (g_testLua)
-    {
-        if (L_IsInitialized(&g_ElState))
-        {
-            i = L_RunOnce(&g_ElState, "test.elua");
-            if (i)
-                OSD_Printf(OSD_ERROR "Error running the test ELua script (code %d)\n", i);
-            else
-                initprintf("ELua test script run ok!\n");
-        }
-        else
-            initprintf("ELua test script: not inited!\n");
-    }
 #endif
 
     i = headspritestat[STAT_DEFAULT];
@@ -2064,8 +2048,8 @@ int32_t G_EnterLevel(int32_t g)
 
 void G_FreeMapState(int32_t mapnum)
 {
-    int32_t j;
 #if !defined LUNATIC
+    int32_t j;
     for (j=0; j<g_gameVarCount; j++)
     {
         if (aGameVars[j].dwFlags & GAMEVAR_NORESET) continue;