mirror of
https://github.com/ZDoom/raze-gles.git
synced 2025-01-11 18:50:46 +00:00
Lunatic: chaining of actor callback functions.
For events and actors, a flag can be now passed whether to chain the new function at the beginning or end of an already existing one, or to replace it entirely. Also, for the translator, add option -fno-error-nostate, disabled by default. git-svn-id: https://svn.eduke32.com/eduke32@3629 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
parent
fe69ee5476
commit
e63874d011
5 changed files with 130 additions and 54 deletions
|
@ -220,6 +220,8 @@ SFLAG = {
|
|||
SFLAG_CACHE = -0x00010000,
|
||||
SFLAG_ROTFIXED = -0x00020000,
|
||||
SFLAG_HARDCODED_BADGUY = -0x00040000,
|
||||
-- RESERVED for actor.FLAGS.CHAIN_BEG/CHAIN_END/REPLACE:
|
||||
-- 0x20000000, 0x40000000
|
||||
}
|
||||
|
||||
STAT = {
|
||||
|
|
|
@ -710,6 +710,11 @@ do
|
|||
our_SFLAG.enemystayput = con_lang.SFLAG.SFLAG_BADGUY + con_lang.SFLAG.SFLAG_BADGUYSTAYPUT
|
||||
our_SFLAG.rotfixed = con_lang.SFLAG.SFLAG_ROTFIXED
|
||||
|
||||
-- Callback function chaining control flags.
|
||||
our_SFLAG.chain_beg = bit.tobit(0x20000000)
|
||||
our_SFLAG.chain_end = bit.tobit(0x40000000)
|
||||
our_SFLAG.replace = bit.bor(our_SFLAG.chain_beg, our_SFLAG.chain_end)
|
||||
|
||||
-- XXX: CON doesn't export BADGUYSTAYPUT or ROTFIXED SFLAGs, but they are considered
|
||||
-- external for Lunatic.
|
||||
our_SFLAG.USER_MASK = bit.bor(USER_MASK, our_SFLAG.enemystayput, our_SFLAG.rotfixed)
|
||||
|
@ -729,6 +734,7 @@ player = setmtonce({}, defs_c.GenStructMetatable("g_player_ps", "playerswhenstar
|
|||
-- needed by "control"
|
||||
actor = setmtonce({}, defs_c.GenStructMetatable("actor", "MAXSPRITES", actor_static_members))
|
||||
local BNOT_SFLAG_USER_MASK = bit.bnot(actor.FLAGS.USER_MASK)
|
||||
local BNOT_CHAIN_MASK = bit.bnot(actor.FLAGS.replace)
|
||||
|
||||
local projectile = defs_c.creategtab(ffiC.ProjectileData, ffiC.MAXTILES, "projectile[]")
|
||||
local g_tile = setmtonce({}, defs_c.GenStructMetatable("g_tile", "MAXTILES", tile_static_members))
|
||||
|
@ -1423,6 +1429,22 @@ G_._VERSION = _VERSION
|
|||
|
||||
G_._G = G_
|
||||
|
||||
-- Chain together two functions taking 3 input args.
|
||||
local function chain_func3(func1, func2)
|
||||
if (func1==nil or func2==nil) then
|
||||
return assert(func1 or func2)
|
||||
end
|
||||
|
||||
-- Return a function that runs <func1> first and then tail-calls <func2>.
|
||||
return function(aci, pli, dist)
|
||||
func1(aci, pli, dist)
|
||||
return func2(aci, pli, dist)
|
||||
end
|
||||
end
|
||||
|
||||
-- Actor functions, saved for actor chaining
|
||||
local actor_funcs = {}
|
||||
|
||||
local gameactor_internal = gameactor_internal -- included in lunatic.c
|
||||
-- gameactor(tilenum [, flags [, strength [, act [, mov [, movflags]]]]], actor_func)
|
||||
local function our_gameactor(tilenum, ...)
|
||||
|
@ -1454,54 +1476,88 @@ local function our_gameactor(tilenum, ...)
|
|||
error("invalid 'flags' argument to gameactor: must be a number", 2)
|
||||
end
|
||||
|
||||
local AF = actor.FLAGS
|
||||
local chainflags = bit.band(flags, AF.replace)
|
||||
flags = bit.band(flags, BNOT_CHAIN_MASK)
|
||||
|
||||
-- Default chaining behavior: don't, replace the old actor instead (like CON).
|
||||
if (chainflags == 0) then
|
||||
chainflags = AF.replace
|
||||
end
|
||||
|
||||
local replacep = (chainflags==AF.replace)
|
||||
if (not replacep and not actor_funcs[tilenum]) then
|
||||
error("attempt to chain code to nonexistent actor tile "..tilenum, 2)
|
||||
end
|
||||
|
||||
local flags_rbits = bit.band(flags, BNOT_SFLAG_USER_MASK)
|
||||
if (flags_rbits ~= 0) then
|
||||
error("invalid 'flags' argument to gameactor: must not set reserved bits (0x"
|
||||
..(bit.tohex(flags_rbits))..")", 2)
|
||||
end
|
||||
|
||||
local strength = (numargs > 2) and args[2] or 0
|
||||
if (type(strength) ~= "number") then
|
||||
error("invalid 'strength' argument to gameactor: must be a number", 2)
|
||||
local strength = (numargs > 2) and args[2] or (replacep and 0 or nil)
|
||||
if (replacep or strength~=nil) then
|
||||
if (type(strength) ~= "number") then
|
||||
error("invalid 'strength' argument to gameactor: must be a number", 2)
|
||||
end
|
||||
end
|
||||
|
||||
-- TODO: literal number action other than 0?
|
||||
local act = (numargs > 3) and args[3] or "NO"
|
||||
if (type(act)=="string") then
|
||||
act = AC[act]
|
||||
end
|
||||
if (not ffi.istype(con_action_ct, act)) then
|
||||
error("invalid 'act' argument to gameactor: must be a string or action", 2)
|
||||
local act = (numargs > 3) and args[3] or (replacep and "NO" or nil)
|
||||
if (replacep or act ~= nil) then
|
||||
if (type(act)=="string") then
|
||||
act = AC[act]
|
||||
end
|
||||
if (not ffi.istype(con_action_ct, act)) then
|
||||
error("invalid 'act' argument to gameactor: must be a string or action", 2)
|
||||
end
|
||||
end
|
||||
|
||||
-- TODO: literal number move other than 0?
|
||||
local mov = (numargs > 4) and args[4] or "NO"
|
||||
if (type(mov)=="string") then
|
||||
mov = MV[mov]
|
||||
end
|
||||
if (not ffi.istype(con_move_ct, mov)) then
|
||||
error("invalid 'mov' argument to gameactor: must be a string or move", 2)
|
||||
local mov = (numargs > 4) and args[4] or (replacep and "NO" or nil)
|
||||
if (replacep or mov ~= nil) then
|
||||
if (type(mov)=="string") then
|
||||
mov = MV[mov]
|
||||
end
|
||||
if (not ffi.istype(con_move_ct, mov)) then
|
||||
error("invalid 'mov' argument to gameactor: must be a string or move", 2)
|
||||
end
|
||||
end
|
||||
|
||||
local movflags = (numargs > 5) and args[5] or 0
|
||||
if (type(movflags) ~= "number") then
|
||||
error("invalid 'movflags' argument to gameactor: must be a number", 2)
|
||||
local movflags = (numargs > 5) and args[5] or (replacep and 0 or nil)
|
||||
if (replacep or movflags ~= nil) then
|
||||
if (type(movflags) ~= "number") then
|
||||
error("invalid 'movflags' argument to gameactor: must be a number", 2)
|
||||
end
|
||||
end
|
||||
|
||||
-- All good, set the tile bits and register the actor!
|
||||
|
||||
local tile = ffiC.g_tile[tilenum]
|
||||
tile.flags = bit.bor(tile.flags, flags)
|
||||
local func = args[numargs]
|
||||
|
||||
gameactor_internal(tilenum, strength, act, mov, movflags, args[numargs])
|
||||
-- NOTE: when chaining, this allows passing different flags which are
|
||||
-- silently ORed. This may or may not be what the user intends, but it
|
||||
-- allows e.g. adding a stayput bit to an already defined enemy.
|
||||
-- Modifying existing behavior is the whole point of chaining after all.
|
||||
tile.flags = replacep and flags or bit.bor(tile.flags, flags)
|
||||
|
||||
local newfunc = replacep and func
|
||||
or (chainflags==AF.chain_beg) and chain_func3(func, actor_funcs[tilenum])
|
||||
or (chainflags==AF.chain_end) and chain_func3(actor_funcs[tilenum], func)
|
||||
or assert(false)
|
||||
|
||||
gameactor_internal(tilenum, strength, act, mov, movflags, newfunc)
|
||||
actor_funcs[tilenum] = newfunc
|
||||
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)
|
||||
-- gameevent(<event idx or string> [, flags], <event function>)
|
||||
local function our_gameevent(event, flags, func)
|
||||
if (ffiC.g_elCallDepth > 0) then
|
||||
error("Invalid use of gameevent: must be called from top level", 2)
|
||||
end
|
||||
|
@ -1516,26 +1572,39 @@ local function our_gameevent(event, func)
|
|||
event = eventidx
|
||||
end
|
||||
if (type(event) ~= "number") then
|
||||
error("invalid argument #1 to gameevent: must be a number", 2)
|
||||
error("invalid argument #1 to gameevent: must be a number or event label", 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 AF = actor.FLAGS
|
||||
|
||||
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)
|
||||
return oldfunc(aci, pli, dist)
|
||||
-- Event chaining: in Lunatic, chaining at the *end* is the default.
|
||||
if (func==nil) then
|
||||
func = flags
|
||||
flags = AF.chain_end
|
||||
else
|
||||
if (type(flags) ~= "number") then
|
||||
error("invalid 'flags' argument to gameevent: must be a number", 2)
|
||||
end
|
||||
if (bit.band(flags, BNOT_CHAIN_MASK) ~= 0) then
|
||||
error("invalid 'flags' argument to gameevent: must not set reserved bits", 2)
|
||||
end
|
||||
if (flags == 0) then
|
||||
flags = AF.chain_end
|
||||
end
|
||||
end
|
||||
|
||||
if (type(func) ~= "function") then
|
||||
error("invalid last argument to gameevent: must be a function", 2)
|
||||
end
|
||||
|
||||
local newfunc = (flags==AF.replace) and func
|
||||
or (flags==AF.chain_beg) and chain_func3(func, event_funcs[event])
|
||||
or (flags==AF.chain_end) and chain_func3(event_funcs[event], func)
|
||||
or assert(false)
|
||||
|
||||
gameevent_internal(event, newfunc)
|
||||
event_funcs[event] = newfunc
|
||||
end
|
||||
|
|
|
@ -102,7 +102,7 @@ local g_warn = { ["not-redefined"]=true, ["bad-identifier"]=false,
|
|||
|
||||
-- Code generation and output options.
|
||||
local g_cgopt = { ["no"]=false, ["debug-lineinfo"]=false, ["gendir"]=nil,
|
||||
["cache-sap"]=false, }
|
||||
["cache-sap"]=false, ["no-error-nostate"]=false, }
|
||||
local function csapp() return g_cgopt["cache-sap"] end
|
||||
|
||||
-- How many 'if' statements are following immediately each other,
|
||||
|
@ -1772,8 +1772,11 @@ local handle =
|
|||
|
||||
state = function(statename)
|
||||
if (g_funcname[statename]==nil) then
|
||||
errprintf("state `%s' not found.", statename)
|
||||
return "_NULLSTATE()"
|
||||
local warn = g_cgopt["no-error-nostate"]
|
||||
local xprintf = warn and warnprintf or errprintf
|
||||
|
||||
xprintf("state `%s' not found.", statename)
|
||||
return warn and "" or "_NULLSTATE()"
|
||||
end
|
||||
return format("%s(_aci,_pli,_dist)", g_funcname[statename])
|
||||
end,
|
||||
|
@ -3192,7 +3195,7 @@ local function handle_cmdline_arg(str)
|
|||
g_warn[warnstr] = val
|
||||
ok = true
|
||||
end
|
||||
elseif (str:sub(2,4)=="fno") then
|
||||
elseif (str:sub(2)=="fno") then
|
||||
-- Disable printing code.
|
||||
if (#str >= 5 and str:sub(5)=="=onlycheck") then
|
||||
g_cgopt["no"] = "onlycheck"
|
||||
|
@ -3209,6 +3212,9 @@ local function handle_cmdline_arg(str)
|
|||
elseif (str:sub(2)=="fcache-sap") then
|
||||
g_cgopt["cache-sap"] = true
|
||||
ok = true
|
||||
elseif (str:sub(2)=="fno-error-nostate") then
|
||||
g_cgopt["no-error-nostate"] = true
|
||||
ok = true
|
||||
elseif (str:sub(2)=="fdebug-lineinfo") then
|
||||
g_cgopt["debug-lineinfo"] = true
|
||||
ok = true
|
||||
|
|
|
@ -414,10 +414,7 @@ static int32_t SetEvent_CF(lua_State *L)
|
|||
// gameactor(actortile, strength, act, mov, movflags, lua_function)
|
||||
static int32_t SetActor_CF(lua_State *L)
|
||||
{
|
||||
int32_t actortile, strength, movflags;
|
||||
const con_action_t *act;
|
||||
const con_move_t *mov;
|
||||
|
||||
int32_t actortile;
|
||||
el_actor_t *a;
|
||||
|
||||
Bassert(lua_gettop(L) == 6);
|
||||
|
@ -425,22 +422,23 @@ static int32_t SetActor_CF(lua_State *L)
|
|||
actortile = luaL_checkint(L, 1);
|
||||
Bassert((unsigned)actortile < MAXTILES);
|
||||
|
||||
strength = luaL_checkint(L, 2);
|
||||
movflags = luaL_checkint(L, 5);
|
||||
|
||||
act = lua_topointer(L, 3);
|
||||
mov = lua_topointer(L, 4);
|
||||
|
||||
a = &g_elActors[actortile];
|
||||
L_CheckAndRegisterFunction(L, a);
|
||||
|
||||
// Set actor properties. They can only be nil if we're chaining actor code.
|
||||
|
||||
if (!lua_isnil(L, 2))
|
||||
a->strength = luaL_checkint(L, 2);
|
||||
if (!lua_isnil(L, 5))
|
||||
a->movflags = luaL_checkint(L, 5);
|
||||
|
||||
if (!lua_isnil(L, 3))
|
||||
Bmemcpy(&a->act, lua_topointer(L, 3), sizeof(con_action_t));
|
||||
if (!lua_isnil(L, 4))
|
||||
Bmemcpy(&a->mov, lua_topointer(L, 4), sizeof(con_move_t));
|
||||
|
||||
a->haveit = 1;
|
||||
|
||||
a->strength = strength;
|
||||
a->movflags = movflags;
|
||||
|
||||
Bmemcpy(&a->act, act, sizeof(con_action_t));
|
||||
Bmemcpy(&a->mov, mov, sizeof(con_move_t));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -365,7 +365,8 @@ local TROOPSTRENGTH = 30
|
|||
|
||||
local AF = actor.FLAGS
|
||||
|
||||
gameactor(1680, AF.enemy, TROOPSTRENGTH, "TROOPSTAND", -- LIZTROOP
|
||||
-- Also test actor code chaining: strength is doubled.
|
||||
gameactor(1680, AF.chain_end+AF.enemy, 2*TROOPSTRENGTH, "TROOPSTAND", -- LIZTROOP
|
||||
function(i, playeri, dist)
|
||||
spriteext[i]:make_animated()
|
||||
|
||||
|
|
Loading…
Reference in a new issue