From fa2ac57674eaea30d8432ce19b5be948b66499b0 Mon Sep 17 00:00:00 2001 From: helixhorned Date: Tue, 25 Dec 2012 16:13:45 +0000 Subject: [PATCH] Lunatic: event chaining. git-svn-id: https://svn.eduke32.com/eduke32@3320 1a8010ca-5511-0410-912e-c29ae57300e0 --- polymer/eduke32/source/lunatic/con_lang.lua | 1 + polymer/eduke32/source/lunatic/defs.ilua | 60 +++++++++++++++++-- .../eduke32/source/lunatic/defs_common.lua | 2 + polymer/eduke32/source/lunatic/dynsymlist | 1 + polymer/eduke32/source/lunatic/lunatic_game.c | 22 ++++--- polymer/eduke32/source/lunatic/test.elua | 15 ++++- .../source/lunatic/test/event_chaining.con | 20 +++++++ 7 files changed, 106 insertions(+), 15 deletions(-) create mode 100644 polymer/eduke32/source/lunatic/test/event_chaining.con diff --git a/polymer/eduke32/source/lunatic/con_lang.lua b/polymer/eduke32/source/lunatic/con_lang.lua index 8de0705db..753b81aa3 100644 --- a/polymer/eduke32/source/lunatic/con_lang.lua +++ b/polymer/eduke32/source/lunatic/con_lang.lua @@ -17,6 +17,7 @@ MAXLEVELS = 64 MAXSKILLS = 7 +MAXEVENTS = 95 -- KEEPINSYNC with EVENT_* list MAXSOUNDS = 4096 diff --git a/polymer/eduke32/source/lunatic/defs.ilua b/polymer/eduke32/source/lunatic/defs.ilua index 2cda3abf4..dc274f5a6 100644 --- a/polymer/eduke32/source/lunatic/defs.ilua +++ b/polymer/eduke32/source/lunatic/defs.ilua @@ -24,8 +24,6 @@ local tostring = tostring local type = type ---== First, load the definitions common to the game's and editor's Lua interface. - -- The "gv" global will provide access to C global *scalars* and safe functions. -- XXX: still exposes C library functions etc. contained in ffi.C, problem? local gv_ = { @@ -53,7 +51,7 @@ function decl(str) ffi.cdef(str) end --- load the common definitions! +-- Load the definitions common to the game's and editor's Lua interface. local defs_c = require("defs_common") local cansee = defs_c.cansee local strip_const = defs_c.strip_const @@ -449,6 +447,7 @@ typedef struct { decl[[ const char *g_sizes_of_what[]; int32_t g_sizes_of[]; +int32_t g_elCallDepth; actor_t actor[MAXSPRITES]; user_defs ud; playerdata_t g_player[MAXPLAYERS]; @@ -990,6 +989,10 @@ G_._G = G_ local gameactor_internal = gameactor_internal -- included in lunatic.c -- gameactor(tilenum [, strength [, act [, mov [, movflags]]]], actor_func) local function our_gameactor(tilenum, ...) + if (ffiC.g_elCallDepth > 0) then + error("Invalid use of gameactor: must be called from top level", 2) + end + local args = {...} if (type(tilenum) ~= "number") then error("invalid argument #1 to gameactor: must be a number", 2) @@ -1000,6 +1003,9 @@ local function our_gameactor(tilenum, ...) if (#args == 0) then error("invalid call to gameactor: must have at least two arguments (tilenum, func)", 2) end + if (#args > 6) then + error("invalid call to gameactor: must have at most six arguments", 2) + end if (type(args[#args]) ~= "function") then error("invalid last argument to gameactor: must be a function", 2) end @@ -1035,8 +1041,52 @@ local function our_gameactor(tilenum, ...) gameactor_internal(tilenum, strength, act, mov, movflags, args[#args]) end +-- Event functions, saved for event chaining +local event_funcs = {} + +local gameevent_internal = gameevent_internal -- included in lunatic.c +-- gameevent(, ) +local function our_gameevent(event, func) + if (ffiC.g_elCallDepth > 0) then + error("Invalid use of gameevent: must be called from top level", 2) + end + if (type(event) == "string") then + if (event:sub(1,6) ~= "EVENT_") then + event = "EVENT_"..event + end + local eventidx = con_lang.labels[3][event] -- 3: event list + if (eventidx == nil) then + errorf(2, "gameevent: invalid event label %q", event) + end + event = eventidx + end + if (type(event) ~= "number") then + error("invalid argument #1 to gameevent: must be a number", 2) + end + if (event >= con_lang.MAXEVENTS+0ULL) then + error("invalid argument #1 to gameevent: must be an event number (0 .. MAXEVENTS-1)", 2) + end + + if (type(func) ~= "function") then + error("invalid argument #2 to gameevent: must be a function", 2) + end + + local newfunc = func + local oldfunc = event_funcs[event] + -- event chaining: events defined later come first + if (oldfunc ~= nil) then + newfunc = function(aci, pli, dist) + func(aci, pli, dist) + oldfunc(aci, pli, dist) + end + end + + gameevent_internal(event, newfunc) + event_funcs[event] = newfunc +end + --- non-default data and functions -G_.gameevent = gameevent -- included in lunatic.c +G_.gameevent = our_gameevent G_.gameactor = our_gameactor G_.player = player -- from above @@ -1052,8 +1102,6 @@ local lunacon = require("lunacon") setfenv(1, G_) -- Print keys and values of a table. --- REMEMBER special position of 'tostring' (it's looked up and used as a global --- from 'print') local function printkv(label, table) print("========== Keys and values of "..label.." ("..tostring(table)..")") for k,v in pairs(table) do diff --git a/polymer/eduke32/source/lunatic/defs_common.lua b/polymer/eduke32/source/lunatic/defs_common.lua index 0bb275ef1..092e2489c 100644 --- a/polymer/eduke32/source/lunatic/defs_common.lua +++ b/polymer/eduke32/source/lunatic/defs_common.lua @@ -12,12 +12,14 @@ local string = require("string") local error = error local pairs = pairs local setmetatable = setmetatable +local tostring = tostring local decl = decl local getfenv = getfenv decl "void OSD_Printf(const char *fmt, ...);" print = function(str) + -- our "print" doesn't use the global "tostring", but the initial one str = tostring(str) if (type(str) ~= "string") then error("invalid argument to print: must be convertible to a string") diff --git a/polymer/eduke32/source/lunatic/dynsymlist b/polymer/eduke32/source/lunatic/dynsymlist index d6e980b3e..747ec660c 100644 --- a/polymer/eduke32/source/lunatic/dynsymlist +++ b/polymer/eduke32/source/lunatic/dynsymlist @@ -50,6 +50,7 @@ OSD_Printf; g_sizes_of_what; g_sizes_of; +g_elCallDepth; kopen4loadfrommod; kfilelength; diff --git a/polymer/eduke32/source/lunatic/lunatic_game.c b/polymer/eduke32/source/lunatic/lunatic_game.c index a3db9a64c..b918993c5 100644 --- a/polymer/eduke32/source/lunatic/lunatic_game.c +++ b/polymer/eduke32/source/lunatic/lunatic_game.c @@ -23,6 +23,8 @@ uint8_t g_elEvents[MAXEVENTS]; // same thing for actors: el_actor_t g_elActors[MAXTILES]; +int32_t g_elCallDepth = 0; + // for timing events and actors uint32_t g_eventCalls[MAXEVENTS], g_actorCalls[MAXTILES]; double g_eventTotalMs[MAXEVENTS], g_actorTotalMs[MAXTILES]; @@ -104,7 +106,7 @@ void El_PrintTimes(void) } ////////// ERROR REPORTING ////////// -#define EL_MAXERRORS 2 +#define EL_MAXERRORS 20 static int32_t el_numErrors=0, el_tooMuchErrors; static char *el_errorMsgs[EL_MAXERRORS]; @@ -202,7 +204,7 @@ static void El_StateSetup(lua_State *L) // create misc. global functions in the Lua state lua_pushcfunction(L, SetEvent_luacf); - lua_setglobal(L, "gameevent"); + lua_setglobal(L, "gameevent_internal"); lua_pushcfunction(L, SetActor_luacf); lua_setglobal(L, "gameactor_internal"); @@ -230,12 +232,10 @@ static int32_t SetEvent_luacf(lua_State *L) { int32_t eventidx; - if (lua_gettop(L) != 2) - luaL_error(L, "gameevent: must pass exactly two arguments"); - + Bassert(lua_gettop(L) == 2); eventidx = luaL_checkint(L, 1); + Bassert((unsigned)eventidx < MAXEVENTS); - luaL_argcheck(L, (unsigned)eventidx < MAXEVENTS, 1, "must be an event number (0 .. MAXEVENTS-1)"); L_CheckAndRegisterFunction(L, &g_elEvents[eventidx]); g_elEvents[eventidx] = 1; @@ -308,8 +308,11 @@ int32_t El_CallEvent(L_State *estate, int32_t eventidx, int32_t iActor, int32_t // make a global? lua_State *const L = estate->L; + int32_t i; - int32_t i = call_regd_function3(L, &g_elEvents[eventidx], iActor, iPlayer, lDist); + g_elCallDepth++; + i = call_regd_function3(L, &g_elEvents[eventidx], iActor, iPlayer, lDist); + g_elCallDepth--; if (i == LUA_ERRRUN) { @@ -337,8 +340,11 @@ int32_t El_CallEvent(L_State *estate, int32_t eventidx, int32_t iActor, int32_t int32_t El_CallActor(L_State *estate, int32_t actortile, int32_t iActor, int32_t iPlayer, int32_t lDist) { lua_State *const L = estate->L; + int32_t i; - int32_t i = call_regd_function3(L, &g_elActors[actortile], iActor, iPlayer, lDist); + g_elCallDepth++; + i = call_regd_function3(L, &g_elActors[actortile], iActor, iPlayer, lDist); + g_elCallDepth--; if (i == LUA_ERRRUN) { diff --git a/polymer/eduke32/source/lunatic/test.elua b/polymer/eduke32/source/lunatic/test.elua index 8b0a53192..3aa0b6241 100644 --- a/polymer/eduke32/source/lunatic/test.elua +++ b/polymer/eduke32/source/lunatic/test.elua @@ -7,6 +7,9 @@ local string = require("string") local bit = require("bit") local math = require("math") +local pcall = pcall +local DBG_ = DBG_ + print('---=== ELua Test script ===---') local function printf(fmt, ...) @@ -183,7 +186,7 @@ checkfail("do local bt=require'bittest'; bt.QWE=1; end", "modifying module table -- the cdata returned by player[] can't be made into a pointer! checkfail("do local pl=player[0]; i=pl[1]; end") checkfail("do local ud=gv.ud.camera; end", "dummy variable: read access forbidden") -- test for proper decl() -checkfail("sprite[0]:set_picnum(-10)", "attempt to set invalid picnums") +checkfail("sprite[0]:set_picnum(-10)", "attempt to set invalid picnum") printf('ceilingbunch of sector 0: %d', getbunch(0, gv.CEILING)) @@ -194,6 +197,13 @@ gameevent(gv.EVENT_JUMP, end ) +-- test event chaining +gameevent("JUMP", + function(actori, playeri, dist) + print("I'm first!") + end + ) + gameevent(gv.EVENT_ENTERLEVEL, function() -- NOTE: times are for helixhorned (Core2Duo 3GHz) @@ -230,6 +240,9 @@ gameevent(gv.EVENT_ENTERLEVEL, printf("sqrt(0xffffffff) = %f(ksqrt) %f(math.sqrt)", gv.ksqrt(0xffffffff), math.sqrt(0xffffffff)) + + checkfail("gameevent('GAME', function() print('qwe') end)", + "must be called from top level") end ) diff --git a/polymer/eduke32/source/lunatic/test/event_chaining.con b/polymer/eduke32/source/lunatic/test/event_chaining.con new file mode 100644 index 000000000..9f770f7f8 --- /dev/null +++ b/polymer/eduke32/source/lunatic/test/event_chaining.con @@ -0,0 +1,20 @@ +definequote 125 FIRST +definequote 126 SECOND +definequote 127 THIRD + +onevent EVENT_INIT + echo 125 +endevent + +onevent EVENT_INIT + echo 126 +endevent + +onevent EVENT_INIT + echo 127 +endevent + +// output: +// THIRD +// SECOND +// FIRST