From efbc4cec90d32b192a9d296d4b17acd7d2020932 Mon Sep 17 00:00:00 2001 From: helixhorned Date: Sun, 24 Mar 2013 18:53:28 +0000 Subject: [PATCH] Lunatic: actor usertypes from CON, set SFLAGs as 2nd gameactor() arg in Lua. In passing, fix a couple of omissions: gameactor() being passed nil's in the middle, more than one moveflag to CON *actor. git-svn-id: https://svn.eduke32.com/eduke32@3597 1a8010ca-5511-0410-912e-c29ae57300e0 --- polymer/eduke32/source/actors.c | 5 +- polymer/eduke32/source/lunatic/con_lang.lua | 41 ++++-- polymer/eduke32/source/lunatic/control.lua | 7 +- polymer/eduke32/source/lunatic/defs.ilua | 133 ++++++++++++------ polymer/eduke32/source/lunatic/lunacon.lua | 32 ++++- polymer/eduke32/source/lunatic/test.elua | 16 +-- .../source/lunatic/test/rotfixed_actor.con | 7 + 7 files changed, 168 insertions(+), 73 deletions(-) diff --git a/polymer/eduke32/source/actors.c b/polymer/eduke32/source/actors.c index 07e96d4f3..ab744cdea 100644 --- a/polymer/eduke32/source/actors.c +++ b/polymer/eduke32/source/actors.c @@ -8149,10 +8149,7 @@ void A_PlayAlertSound(int32_t i) int32_t A_CheckEnemyTile(int32_t pn) { - if (g_tile[pn].flags & SPRITE_HARDCODED_BADGUY) - return 1; - - return A_CheckSpriteTileFlags(pn, SPRITE_BADGUY); + return ((g_tile[pn].flags & (SPRITE_HARDCODED_BADGUY|SPRITE_BADGUY)) != 0); } int32_t A_CheckSwitchTile(int32_t i) diff --git a/polymer/eduke32/source/lunatic/con_lang.lua b/polymer/eduke32/source/lunatic/con_lang.lua index fea5c7449..65a9fd3b6 100644 --- a/polymer/eduke32/source/lunatic/con_lang.lua +++ b/polymer/eduke32/source/lunatic/con_lang.lua @@ -4,6 +4,7 @@ local lpeg = require("lpeg") local pairs = pairs local print = print +local setmetatable = setmetatable local type = type @@ -197,26 +198,28 @@ EVENT = { EVENT_CHANGEMENU = 94, } -local SFLAG = { +-- NOTE: negated values are not exported to the ffi.C namespace or CON. +-- See TWEAK_SFLAG below. +SFLAG = { SFLAG_SHADOW = 0x00000001, SFLAG_NVG = 0x00000002, SFLAG_NOSHADE = 0x00000004, --- SFLAG_PROJECTILE = 0x00000008, --- SFLAG_DECAL = 0x00000010, + SFLAG_PROJECTILE = -0x00000008, + SFLAG_DECAL = -0x00000010, SFLAG_BADGUY = 0x00000020, SFLAG_NOPAL = 0x00000040, - SFLAG_NOEVENTS = 0x00000080, -- NAME + SFLAG_NOEVENTS = 0x00000080, -- NAME SFLAG_NOLIGHT = 0x00000100, SFLAG_USEACTIVATOR = 0x00000200, --- SFLAG_NULL = 0x00000400, + SFLAG_NULL = -0x00000400, SFLAG_NOCLIP = 0x00000800, --- SFLAG_NOFLOORSHADOW = 0x00001000, + SFLAG_NOFLOORSHADOW = -0x00001000, SFLAG_SMOOTHMOVE = 0x00002000, SFLAG_NOTELEPORT = 0x00004000, --- SFLAG_BADGUYSTAYPUT = 0x00008000, --- SFLAG_CACHE = 0x00010000, --- SFLAG_ROTFIXED = 0x00020000, --- SPRITE_HARDCODED_BADGUY= 0x00040000, + SFLAG_BADGUYSTAYPUT = -0x00008000, + SFLAG_CACHE = -0x00010000, + SFLAG_ROTFIXED = -0x00020000, + SFLAG_HARDCODED_BADGUY = -0x00040000, } STAT = { @@ -297,6 +300,14 @@ local GAMEFUNC = { GAMEFUNC_DPAD_AIMING = 55, } +local function shallow_copy(tab) + local t = {} + for k,v in pairs(tab) do + t[k] = v + end + return t +end + -- KEEPINSYNC with gamedef.c:C_AddDefaultDefinitions() and the respective -- defines. These are exported to the ffi.C namespace and as literal defines -- in lunacon.lua. @@ -305,11 +316,19 @@ labels = STR, PROJ, EVENT, - SFLAG, + setmetatable(shallow_copy(SFLAG), { __metatable="noffiC" }), STAT, GAMEFUNC, } +-- TWEAK_SFLAG +for name, flag in pairs(SFLAG) do + if (flag < 0) then + SFLAG[name] = -flag + labels[4][name] = nil + end +end + -- KEEPINSYNC player.h wdata_members = { diff --git a/polymer/eduke32/source/lunatic/control.lua b/polymer/eduke32/source/lunatic/control.lua index 228181899..d39276669 100644 --- a/polymer/eduke32/source/lunatic/control.lua +++ b/polymer/eduke32/source/lunatic/control.lua @@ -273,11 +273,10 @@ function _shoot(i, tilenum, zvel) return CF.A_ShootWithZvel(i, tilenum, zvel) end +local BADGUY_MASK = bit.bor(con_lang.SFLAG.SFLAG_HARDCODED_BADGUY, con_lang.SFLAG.SFLAG_BADGUY) + function isenemytile(tilenum) - if (bit.band(ffiC.g_tile[tilenum].flags, 0x00040000)~=0) then - return true - end - return (bit.band(ffiC.g_tile[tilenum].flags, ffiC.SFLAG_BADGUY)~=0) + return (bit.band(ffiC.g_tile[tilenum].flags, BADGUY_MASK)~=0) end function rotatesprite(x, y, zoom, ang, tilenum, shade, pal, orientation, diff --git a/polymer/eduke32/source/lunatic/defs.ilua b/polymer/eduke32/source/lunatic/defs.ilua index 8f92917eb..cf77fba80 100644 --- a/polymer/eduke32/source/lunatic/defs.ilua +++ b/polymer/eduke32/source/lunatic/defs.ilua @@ -12,11 +12,13 @@ local math = math local assert = assert local error = error +local getmetatable = getmetatable local ipairs = ipairs local loadstring = loadstring local pairs = pairs local rawget = rawget local rawset = rawset +local select = select local setmetatable = setmetatable local setfenv = setfenv local tonumber = tonumber @@ -683,23 +685,50 @@ player_static_members.INPUT_BITS = defs_c.conststruct player_static_members.INPUT_EXT_BITS = defs_c.conststruct { - INPUT_MOVE_FORWARD = 1, - INPUT_MOVE_BACKWARD = 2, - INPUT_STRAFE_LEFT = 4, - INPUT_STRAFE_RIGHT = 8, - INPUT_TURN_LEFT = 16, - INPUT_TURN_RIGHT = 32, + MOVE_FORWARD = 1, + MOVE_BACKWARD = 2, + STRAFE_LEFT = 4, + STRAFE_RIGHT = 8, + TURN_LEFT = 16, + TURN_RIGHT = 32, } +-- Actor flags +local actor_static_members = {} +do + local our_SFLAG = {} + local ext_SFLAG = con_lang.labels[4] -- external actor flags only + local USER_MASK = 0 + + for name, flag in pairs(ext_SFLAG) do + our_SFLAG[name:sub(7)] = flag -- strip "SFLAG_" + USER_MASK = bit.bor(USER_MASK, flag) + end + + -- Add a couple of convenience defines. + our_SFLAG.enemy = con_lang.SFLAG.SFLAG_BADGUY + our_SFLAG.enemystayput = con_lang.SFLAG.SFLAG_BADGUY + con_lang.SFLAG.SFLAG_BADGUYSTAYPUT + our_SFLAG.rotfixed = con_lang.SFLAG.SFLAG_ROTFIXED + + -- 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) + + actor_static_members.FLAGS = defs_c.conststruct(our_SFLAG) +end + local tile_static_members = {} -tile_static_members.sizx = defs_c.creategtab(ffiC.tilesizx, ffiC.MAXTILES, "tilesizx[]") -tile_static_members.sizy = defs_c.creategtab(ffiC.tilesizy, ffiC.MAXTILES, "tilesizy[]") +do + tile_static_members.sizx = defs_c.creategtab(ffiC.tilesizx, ffiC.MAXTILES, "tilesizx[]") + tile_static_members.sizy = defs_c.creategtab(ffiC.tilesizy, ffiC.MAXTILES, "tilesizy[]") +end -- XXX: error message will say "g_player_ps" player = setmtonce({}, defs_c.GenStructMetatable("g_player_ps", "playerswhenstarted", player_static_members)) -- needed by "control" -actor = defs_c.creategtab(ffiC.actor, ffiC.MAXSPRITES, "actor[]") +actor = setmtonce({}, defs_c.GenStructMetatable("actor", "MAXSPRITES", actor_static_members)) +local BNOT_SFLAG_USER_MASK = bit.bnot(actor.FLAGS.USER_MASK) local projectile = defs_c.creategtab(ffiC.ProjectileData, ffiC.MAXTILES, "projectile[]") local g_tile = setmtonce({}, defs_c.GenStructMetatable("g_tile", "MAXTILES", tile_static_members)) @@ -1172,14 +1201,15 @@ end -- Declare all con_lang.labels constants in the global FFI namespace. for i=1,#con_lang.labels do - local strbuf = {"enum {"} + if (getmetatable(con_lang.labels[i]) ~= "noffiC") then + local strbuf = {"enum {"} + for label, val in pairs(con_lang.labels[i]) do + strbuf[#strbuf+1] = string.format("%s = %d,", label, val) + end + strbuf[#strbuf+1] = "};" - for label, val in pairs(con_lang.labels[i]) do - strbuf[#strbuf+1] = string.format("%s = %d,", label, val) + ffi.cdef(table.concat(strbuf)) end - strbuf[#strbuf+1] = "};" - - ffi.cdef(table.concat(strbuf)) end @@ -1201,16 +1231,20 @@ local allowed_modules = { con = con, } -for modname, themodule in pairs(allowed_modules) do - local mt = { - __index = themodule, - __newindex = function(tab,idx,val) - error("modifying base module table forbidden", 2) - end, - } +-- Protect base modules. +do + local function basemodule_newindex() + error("modifying base module table forbidden", 2) + end - -- Comment out to make base modules not protected: - allowed_modules[modname] = setmtonce({}, mt) + for modname, themodule in pairs(allowed_modules) do + local mt = { + __index = themodule, + __newindex = basemodule_newindex, + } + + allowed_modules[modname] = setmtonce({}, mt) + end end local function check_valid_modname(modname, errlev) @@ -1396,34 +1430,49 @@ G_._VERSION = _VERSION G_._G = G_ local gameactor_internal = gameactor_internal -- included in lunatic.c --- gameactor(tilenum [, strength [, act [, mov [, movflags]]]], actor_func) +-- gameactor(tilenum [, flags [, strength [, act [, mov [, movflags]]]]], actor_func) local function our_gameactor(tilenum, ...) bcheck.top_level("gameactor") - local args = {...} if (type(tilenum) ~= "number") then error("invalid argument #1 to gameactor: must be a number", 2) end if (tilenum >= ffiC.MAXTILES+0ULL) then - error("invalid argument #1 to gameactor: must be a tile number (0 .. MAXTILES-1)", 2) + error("invalid argument #1 to gameactor: must be a tile number [0..gv.MAXTILES-1]", 2) end - if (#args == 0) then + + local args = {...} + -- Number of varargs; args may have nil's in the middle! + local numargs = select('#', ...) + + if (numargs == 0) then error("invalid call to gameactor: must have at least two arguments (tilenum, func)", 2) end - if (#args > 5) then - error("invalid call to gameactor: must have at most six arguments", 2) + if (numargs >= 7) then -- sic, because tilenum isn't counted! + error("invalid call to gameactor: must have at most 7 arguments", 2) end - if (type(args[#args]) ~= "function") then + if (type(args[numargs]) ~= "function") then error("invalid last argument to gameactor: must be a function", 2) end - local strength = (#args >= 2) and args[1] or 0 + local flags = (numargs > 1) and args[1] or 0 + if (type(flags) ~= "number") then + error("invalid 'flags' argument to gameactor: must be a number", 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) end -- TODO: literal number action other than 0? - local act = (#args >= 3) and args[2] or "NO" + local act = (numargs > 3) and args[3] or "NO" if (type(act)=="string") then act = AC[act] end @@ -1432,7 +1481,7 @@ local function our_gameactor(tilenum, ...) end -- TODO: literal number move other than 0? - local mov = (#args >= 4) and args[3] or "NO" + local mov = (numargs > 4) and args[4] or "NO" if (type(mov)=="string") then mov = MV[mov] end @@ -1440,12 +1489,17 @@ local function our_gameactor(tilenum, ...) error("invalid 'mov' argument to gameactor: must be a string or move", 2) end - local movflags = (#args >= 5) and args[4] or 0 + 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) end - gameactor_internal(tilenum, strength, act, mov, movflags, args[#args]) + -- All good, set the tile bits and register the actor! + + local tile = ffiC.g_tile[tilenum] + tile.flags = bit.bor(tile.flags, flags) + + gameactor_internal(tilenum, strength, act, mov, movflags, args[numargs]) end -- Event functions, saved for event chaining @@ -1565,9 +1619,8 @@ end -- error(..., 2) is to blame the caller and get its line numbers -gv = gv_ local tmpmt = { - __index = function(gv, key) + __index = function(_, key) if (gv_access[key] == nil) then return ffiC[key] end @@ -1578,7 +1631,7 @@ local tmpmt = { error("access forbidden", 2) end, - __newindex = function(gv, key, val) + __newindex = function(_, key, val) if (gv_access[key] == nil) then -- Read-only vars handled by LuaJIT. ffiC[key] = val @@ -1587,7 +1640,7 @@ local tmpmt = { end end, } -setmtonce(gv, tmpmt) +gv = setmtonce(gv_, tmpmt) -- This will create 'sprite', 'wall', etc. HERE, i.e. in the environment of this chunk defs_c.create_globals(_G) diff --git a/polymer/eduke32/source/lunatic/lunacon.lua b/polymer/eduke32/source/lunatic/lunacon.lua index bc2d8b87b..2d859a929 100644 --- a/polymer/eduke32/source/lunatic/lunacon.lua +++ b/polymer/eduke32/source/lunatic/lunacon.lua @@ -341,10 +341,32 @@ local function warnprintf() end -- fwd-decl local on = {} +-- Map from CON actor usertype to SFLAGs. +local MAP_ACTOR_FLAGS = { + [0] = 0, + [1] = conl.SFLAG.SFLAG_BADGUY, + [2] = conl.SFLAG.SFLAG_BADGUY + conl.SFLAG.SFLAG_BADGUYSTAYPUT, + [3] = conl.SFLAG.SFLAG_BADGUY + conl.SFLAG.SFLAG_BADGUYSTAYPUT, +} +for i=4,7 do + MAP_ACTOR_FLAGS[i] = MAP_ACTOR_FLAGS[i-4] + conl.SFLAG.SFLAG_ROTFIXED +end + + function on.actor_end(usertype, tsamm, codetab) local tilenum = tsamm[1] + local flags = 0 - local str = "" + if (usertype ~= nil) then -- useractor + if (not (bit.band(usertype, bit.bnot(7)) == 0)) then + -- XXX: position will be that of last command in actor code + errprintf("invalid usertype: must be bitwise OR of 1, 2 and/or 4") + else + flags = MAP_ACTOR_FLAGS[usertype] + end + end + + local str = flags.."," for i=2,math.min(#tsamm,4) do if ((i==3 or i==4) and tsamm[i]=="0") then -- HACK, gameactor() currently doesn't support literals for actions @@ -353,12 +375,11 @@ function on.actor_end(usertype, tsamm, codetab) end str = str .. tostring(tsamm[i]).."," end - if (#tsamm==5) then - local flags = bit.bor(unpack(tsamm, 5)) - str = str .. flags.."," + if (#tsamm >= 5) then + local movflags = bit.bor(unpack(tsamm, 5)) + str = str .. movflags.."," end - -- TODO: usertype (is non-nil only for 'useractor') addcodef("gameactor(%d,%sfunction(_aci, _pli, _dist)", tilenum, str) addcode(get_cache_sap_code()) add_code_and_end(codetab, "end)") @@ -2355,7 +2376,6 @@ local Cif = { / format("_con._angdiffabs(%s,%s)<=%%1", PLS".ang", SPS".ang"), ifsound = cmd(D) / "_con._soundplaying(_aci,%1)", - -- vvv TODO: this is not correct for GET_ACCESS or GET_SHIELD. ifpinventory = cmd(D,D) / format("_con._checkpinventory(%s,%%1,%%2,_aci)", PLS""), diff --git a/polymer/eduke32/source/lunatic/test.elua b/polymer/eduke32/source/lunatic/test.elua index 87650c2fb..40f1b1210 100644 --- a/polymer/eduke32/source/lunatic/test.elua +++ b/polymer/eduke32/source/lunatic/test.elua @@ -110,9 +110,6 @@ local unsafe = pcall(function() string.UNSAFE=true; end) -- direct gv array access forbidden checkfail('gv.sprite[0].yrepeat = 100', "access forbidden") --- indexing struct array with non-numeric type -checkfail('local i = sprite["qwe"]') -- this will produce an error inside the sprite metatable - checkfail('print(sprite[100000].ceilingpal)', "out-of-bounds sprite[] read access") checkfail('print(gv.sprite[0])', "access forbidden") @@ -129,7 +126,7 @@ checkfail('sector[-1].ceilingpal = 4', "out-of-bounds sector[] read access") checkfail('sector[0].wallnum = 0', "attempt to write to constant location") -- this comes from LJ/FFI -- gv.numsectors is read-only -checkfail('gv.numsectors = 4', "write access forbidden") +checkfail('gv.numsectors = 4', "attempt to write to constant location") -- cannot create new fields in 'gv' checkfail('gv.QWE = 4', "write access forbidden") @@ -153,7 +150,7 @@ checkfail('wall[4].QWE = 123', "has no member named 'QWE'") checkfail("new_global = 345", "attempt to write to undeclared variable 'new_global'") -- can't redefine constants in 'gv' -checkfail('gv.CEILING = 3', "write access forbidden") +checkfail('gv.CEILING = 3', "attempt to write to constant location") -- string.dump is unavailable checkfail('local s=require[[string]]; local tmp=s.dump(gameevent)', @@ -174,7 +171,7 @@ checkfail('gv.luaJIT_setmode(nil, 0, 0)', "missing declaration for symbol 'luaJI checkfail('gv.luaJIT_BC_con_lang', "attempt to call a nil value") checkfail('gv.yax_getbunch(0,0)', "access forbidden") -checkfail('gv.gethitickms = nil', "write access forbidden") +checkfail('gv.gethitickms = nil', "attempt to write to constant location") -- actor[].t_data[] is not accessible for now checkfail('local i = actor[0].t_data[15]', "has no member named 't_data'") @@ -191,6 +188,7 @@ checkfail("do local ud=gv.ud.camerasprite; end", "access forbidden") -- test fo checkfail("sprite[0]:set_picnum(-10)", "invalid tile number") checkfail("gv.g_sizes_of=nil; print(gv.g_sizes_of[0])", "write access forbidden") checkfail("gv.cam.sect=-1", "invalid sector number") +checkfail("local flag=gv.SFLAG_NULL", "missing declaration") printf('ceilingbunch of sector 0: %d', getbunch(0, gv.CEILING)) @@ -339,7 +337,7 @@ gameevent("LOADACTOR", function(i) end end) -gameactor(930, 1, function(i) -- "police line" ribbon +gameactor(930, nil, 1, function(i) -- "police line" ribbon local spr = sprite[i] local r = math.random local d = 20 @@ -365,7 +363,9 @@ con.ai("AITEMP", "TROOPFLINTCH", "SHRUNKVELS", 0) local TROOPSTRENGTH = 30 -gameactor(1680, TROOPSTRENGTH, "TROOPSTAND", -- LIZTROOP +local AF = actor.FLAGS + +gameactor(1680, AF.enemy, TROOPSTRENGTH, "TROOPSTAND", -- LIZTROOP function(i, playeri, dist) spriteext[i]:make_animated() diff --git a/polymer/eduke32/source/lunatic/test/rotfixed_actor.con b/polymer/eduke32/source/lunatic/test/rotfixed_actor.con index 6b97bac73..9328fe166 100644 --- a/polymer/eduke32/source/lunatic/test/rotfixed_actor.con +++ b/polymer/eduke32/source/lunatic/test/rotfixed_actor.con @@ -20,3 +20,10 @@ useractor 4 58 1 NO NO 0 state killme enda + +// Test useractor type "enemy" +define CYCLOIDHEAD 490 +// Will have a flat-sprite-on-floor shadow and be an autoaim target. +useractor 1 CYCLOIDHEAD 10 + state killme +enda