Lunatic: event chaining.

git-svn-id: https://svn.eduke32.com/eduke32@3320 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
helixhorned 2012-12-25 16:13:45 +00:00
parent 41bfa1b841
commit fa2ac57674
7 changed files with 106 additions and 15 deletions

View file

@ -17,6 +17,7 @@ MAXLEVELS = 64
MAXSKILLS = 7 MAXSKILLS = 7
MAXEVENTS = 95 -- KEEPINSYNC with EVENT_* list
MAXSOUNDS = 4096 MAXSOUNDS = 4096

View file

@ -24,8 +24,6 @@ local tostring = tostring
local type = type 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. -- 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? -- XXX: still exposes C library functions etc. contained in ffi.C, problem?
local gv_ = { local gv_ = {
@ -53,7 +51,7 @@ function decl(str)
ffi.cdef(str) ffi.cdef(str)
end 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 defs_c = require("defs_common")
local cansee = defs_c.cansee local cansee = defs_c.cansee
local strip_const = defs_c.strip_const local strip_const = defs_c.strip_const
@ -449,6 +447,7 @@ typedef struct {
decl[[ decl[[
const char *g_sizes_of_what[]; const char *g_sizes_of_what[];
int32_t g_sizes_of[]; int32_t g_sizes_of[];
int32_t g_elCallDepth;
actor_t actor[MAXSPRITES]; actor_t actor[MAXSPRITES];
user_defs ud; user_defs ud;
playerdata_t g_player[MAXPLAYERS]; playerdata_t g_player[MAXPLAYERS];
@ -990,6 +989,10 @@ G_._G = G_
local gameactor_internal = gameactor_internal -- included in lunatic.c local gameactor_internal = gameactor_internal -- included in lunatic.c
-- gameactor(tilenum [, strength [, act [, mov [, movflags]]]], actor_func) -- gameactor(tilenum [, strength [, act [, mov [, movflags]]]], actor_func)
local function our_gameactor(tilenum, ...) 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 = {...} local args = {...}
if (type(tilenum) ~= "number") then if (type(tilenum) ~= "number") then
error("invalid argument #1 to gameactor: must be a number", 2) error("invalid argument #1 to gameactor: must be a number", 2)
@ -1000,6 +1003,9 @@ local function our_gameactor(tilenum, ...)
if (#args == 0) then if (#args == 0) then
error("invalid call to gameactor: must have at least two arguments (tilenum, func)", 2) error("invalid call to gameactor: must have at least two arguments (tilenum, func)", 2)
end end
if (#args > 6) then
error("invalid call to gameactor: must have at most six arguments", 2)
end
if (type(args[#args]) ~= "function") then if (type(args[#args]) ~= "function") then
error("invalid last argument to gameactor: must be a function", 2) error("invalid last argument to gameactor: must be a function", 2)
end end
@ -1035,8 +1041,52 @@ local function our_gameactor(tilenum, ...)
gameactor_internal(tilenum, strength, act, mov, movflags, args[#args]) gameactor_internal(tilenum, strength, act, mov, movflags, args[#args])
end end
-- Event functions, saved for event chaining
local event_funcs = {}
local gameevent_internal = gameevent_internal -- included in lunatic.c
-- gameevent(<event idx or string>, <event function>)
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 --- non-default data and functions
G_.gameevent = gameevent -- included in lunatic.c G_.gameevent = our_gameevent
G_.gameactor = our_gameactor G_.gameactor = our_gameactor
G_.player = player -- from above G_.player = player -- from above
@ -1052,8 +1102,6 @@ local lunacon = require("lunacon")
setfenv(1, G_) setfenv(1, G_)
-- Print keys and values of a table. -- 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) local function printkv(label, table)
print("========== Keys and values of "..label.." ("..tostring(table)..")") print("========== Keys and values of "..label.." ("..tostring(table)..")")
for k,v in pairs(table) do for k,v in pairs(table) do

View file

@ -12,12 +12,14 @@ local string = require("string")
local error = error local error = error
local pairs = pairs local pairs = pairs
local setmetatable = setmetatable local setmetatable = setmetatable
local tostring = tostring
local decl = decl local decl = decl
local getfenv = getfenv local getfenv = getfenv
decl "void OSD_Printf(const char *fmt, ...);" decl "void OSD_Printf(const char *fmt, ...);"
print = function(str) print = function(str)
-- our "print" doesn't use the global "tostring", but the initial one
str = tostring(str) str = tostring(str)
if (type(str) ~= "string") then if (type(str) ~= "string") then
error("invalid argument to print: must be convertible to a string") error("invalid argument to print: must be convertible to a string")

View file

@ -50,6 +50,7 @@ OSD_Printf;
g_sizes_of_what; g_sizes_of_what;
g_sizes_of; g_sizes_of;
g_elCallDepth;
kopen4loadfrommod; kopen4loadfrommod;
kfilelength; kfilelength;

View file

@ -23,6 +23,8 @@ uint8_t g_elEvents[MAXEVENTS];
// same thing for actors: // same thing for actors:
el_actor_t g_elActors[MAXTILES]; el_actor_t g_elActors[MAXTILES];
int32_t g_elCallDepth = 0;
// for timing events and actors // for timing events and actors
uint32_t g_eventCalls[MAXEVENTS], g_actorCalls[MAXTILES]; uint32_t g_eventCalls[MAXEVENTS], g_actorCalls[MAXTILES];
double g_eventTotalMs[MAXEVENTS], g_actorTotalMs[MAXTILES]; double g_eventTotalMs[MAXEVENTS], g_actorTotalMs[MAXTILES];
@ -104,7 +106,7 @@ void El_PrintTimes(void)
} }
////////// ERROR REPORTING ////////// ////////// ERROR REPORTING //////////
#define EL_MAXERRORS 2 #define EL_MAXERRORS 20
static int32_t el_numErrors=0, el_tooMuchErrors; static int32_t el_numErrors=0, el_tooMuchErrors;
static char *el_errorMsgs[EL_MAXERRORS]; 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 // create misc. global functions in the Lua state
lua_pushcfunction(L, SetEvent_luacf); lua_pushcfunction(L, SetEvent_luacf);
lua_setglobal(L, "gameevent"); lua_setglobal(L, "gameevent_internal");
lua_pushcfunction(L, SetActor_luacf); lua_pushcfunction(L, SetActor_luacf);
lua_setglobal(L, "gameactor_internal"); lua_setglobal(L, "gameactor_internal");
@ -230,12 +232,10 @@ static int32_t SetEvent_luacf(lua_State *L)
{ {
int32_t eventidx; int32_t eventidx;
if (lua_gettop(L) != 2) Bassert(lua_gettop(L) == 2);
luaL_error(L, "gameevent: must pass exactly two arguments");
eventidx = luaL_checkint(L, 1); 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]); L_CheckAndRegisterFunction(L, &g_elEvents[eventidx]);
g_elEvents[eventidx] = 1; 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? // make a global?
lua_State *const L = estate->L; 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) 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) 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; 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) if (i == LUA_ERRRUN)
{ {

View file

@ -7,6 +7,9 @@ local string = require("string")
local bit = require("bit") local bit = require("bit")
local math = require("math") local math = require("math")
local pcall = pcall
local DBG_ = DBG_
print('---=== ELua Test script ===---') print('---=== ELua Test script ===---')
local function printf(fmt, ...) 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! -- 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 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("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)) printf('ceilingbunch of sector 0: %d', getbunch(0, gv.CEILING))
@ -194,6 +197,13 @@ gameevent(gv.EVENT_JUMP,
end end
) )
-- test event chaining
gameevent("JUMP",
function(actori, playeri, dist)
print("I'm first!")
end
)
gameevent(gv.EVENT_ENTERLEVEL, gameevent(gv.EVENT_ENTERLEVEL,
function() function()
-- NOTE: times are for helixhorned (Core2Duo 3GHz) -- NOTE: times are for helixhorned (Core2Duo 3GHz)
@ -230,6 +240,9 @@ gameevent(gv.EVENT_ENTERLEVEL,
printf("sqrt(0xffffffff) = %f(ksqrt) %f(math.sqrt)", printf("sqrt(0xffffffff) = %f(ksqrt) %f(math.sqrt)",
gv.ksqrt(0xffffffff), math.sqrt(0xffffffff)) gv.ksqrt(0xffffffff), math.sqrt(0xffffffff))
checkfail("gameevent('GAME', function() print('qwe') end)",
"must be called from top level")
end end
) )

View file

@ -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