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
MAXEVENTS = 95 -- KEEPINSYNC with EVENT_* list
MAXSOUNDS = 4096

View file

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

View file

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

View file

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

View file

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

View file

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

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