-- test script for ELua/Lunatic Interpreter --do return end -- error=nil -- must not affect "require" 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, ...) print(string.format(fmt, ...)) end local function checkfail(funcstr, expectedmsg) local status, errmsg = pcall(DBG_.loadstring(funcstr)) if (status) then print('^21ERROR:^O '..funcstr.." DIDN'T fail") else if (expectedmsg==nil or string.find(errmsg, expectedmsg, 1, true)) then print("^11SUCCESS:^O "..funcstr.." failed: "..errmsg) else -- XXX: beginning with "^10" is counted as error in OSD_Printf() print("^10ERROR*:^O "..funcstr.." failed: "..errmsg.. ", but expected error message was: "..expectedmsg) end end end ---- check serialization ---- gamevar("ourvar") gamevar("ourvar2") -- test nans, infs, precision, subnorms, booleans ourvar2 = { "asd"; 0/0, 1/0, -1/0, 0.12345678901234567, 1e-314, true } ourvar = { ourvar2; 1, 2, 3, "qwe"; [true]=0, [false]=1 } ourvar[#ourvar+1] = ourvar; local gvstr = DBG_.serializeGamevars() ourvar = -1 print("========== attempting to load string: ==========") print(gvstr) print("---------- (end string to load) ----------") -- XXX: need to think about fully restoring state DBG_.loadGamevarsString(gvstr) print("ourvar[4]="..ourvar[4]) local i print('tweaking sector pals') print('numsectors: ' .. gv.numsectors .. ' of ' .. gv.MAXSECTORS) ---[[ for i = 0, gv.numsectors/2 do sector[i].floorpal = 1; sector[i].ceilingpal = 2; end local vol, lev vol, lev = TEMP_getvollev() print('volume='..vol..', level='..lev) if (vol==1 and lev==1) then -- E1L1 print('tweaking some sprites 2') i = 562 spriteext[i].alpha = 0.5; sprite[i].cstat = bit.bor(sprite[i].cstat, 2+512); spriteext[i].pitch = 128; spriteext[i].roll = 256; for spr in spritesofsect(307) do -- some fence sprites in E1L1 print('spr', spr) sprite[spr].pal = 6 end for spr in spritesofsect(236) do print('#spr', spr) end --this is a problem --actor = {} actor[562].flags = bit.bor(actor[562].flags, 2); -- pal 6 with goggles on front SEENINE end --[[ -- TODO: better API for all TROR things? if (vol==1 and lev==8) then print('tweaking bunch 1'); -- trueror1.map for i in sectorsofbunch(1, gv.CEILING) do sector[i].ceilingz = sector[i].ceilingz - 3*1024; end for i in sectorsofbunch(1, gv.FLOOR) do sector[i].floorz = sector[i].floorz - 3*1024; end end --]] local unsafe = pcall(function() string.UNSAFE=true; end) --]] --tostring = nil -- REMEMBER --DBG_.printkv('_G in test.elua', _G) -- direct gv array access forbidden checkfail('gv.sprite[0].yrepeat = 100', "dummy variable: read 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[] struct read access") -- NOTE: gv.sprite doesn't fail, but we can't use it checkfail('print(gv.sprite[0])', "dummy variable: read access forbidden") -- set metatable forbidden checkfail('setmetatable(sprite, {})', "attempt to read undeclared variable 'setmetatable'") -- oob write access checkfail('sector[-1].ceilingpal = 4', "out-of-bounds sector[] read access") -- note the strange err msg -- wallnum member is read-only 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', "cannot create new or write into existing fields of 'gv'") -- cannot create new fields in 'gv' checkfail('gv.QWE = 4', "cannot create new or write into existing fields of 'gv'") -- direct sector write access forbidden checkfail('sector[4] = sector[6]', "cannot write directly to sector[] struct") -- that would be horrible... checkfail('nextspritesect[4] = -666', "cannot write directly to nextspritesect[]") -- we're indexing a plain array! checkfail('print(nextspritesect[4].whatfield)', "attempt to index a number value") -- creating new keys forbidden... handled by LuaJit checkfail('wall[4].QWE = 123', "has no member named 'QWE'") -- our 'require' has only safe stuff --checkfail("require('os')") -- we must declare globals with 'gamevar' checkfail("new_global = 345", "attempt to write to undeclared variable 'new_global'") -- can't redefine constants in 'gv' checkfail('gv.CEILING = 3', "cannot create new or write into existing fields of 'gv'") -- string.dump is unavailable checkfail('local s=require[[string]]; local tmp=s.dump(gameevent)', "attempt to call field 'dump' (a nil value)") if (not unsafe) then -- changing base module tables is disallowed checkfail('local s=require[[string]]; s.format=nil', "modifying base module table forbidden") else print('WARNING: RUNNING WITH UNPROTECTED BASE MODULES') end print('') -- This is problematic, even though pretty much every access will yield a -- "missing declaration" error. -- See http://luajit.org/ext_ffi_api.html#ffi_C about what stuff ffi.C contains. checkfail('gv.luaJIT_setmode(nil, 0, 0)', "missing declaration for symbol 'luaJIT_setmode'") checkfail('gv.luaJIT_BC_con_lang', "attempt to call a nil value") checkfail('gv.yax_getbunch(0,0)', "attempt to call field 'yax_getbunch' (a table value)") checkfail('gv.gethitickms = nil', "cannot create new or write into existing fields of 'gv'") -- we don't have arrays in Lua-accessible structs now checkfail('local i = actor[0].t_data[15]', "has no member named 't_data'") -- no pointer arithmetic! checkfail('local spr = sprite[0]; local x=spr+1', "attempt to perform arithmetic on") checkfail('gameactor(1680, 0)', "invalid last argument to gameactor: must be a function") checkfail("do local bt=require'bittest'; bt.QWE=1; end", "modifying module table forbidden") -- 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 picnum") printf('ceilingbunch of sector 0: %d', getbunch(0, gv.CEILING)) gameevent(gv.EVENT_JUMP, function(actori, playeri, dist) printf("jump i=%d p=%d d=%d", actori, playeri, dist) error("greetings from EVENT_JUMP") end ) -- test event chaining gameevent("JUMP", function(actori, playeri, dist) print("I'm first!") -- DBG_.oom() player[playeri]:weapon(gv.PISTOL_WEAPON).shoots = 2605 -- RPG end ) gameevent(gv.EVENT_ENTERLEVEL, function() -- NOTE: times are for helixhorned (Core2Duo 3GHz) local i local N = 1e6 local t = gv.gethitickms() for i=3,N do gv.gethitickms() end t = gv.gethitickms()-t -- x86_64: 35ns/call, x86: 280 ns/call -- Windows 32-bit: about 1 us/call? printf("%d gethitickms() calls took %.03f ms (%.03f us/call)", N, t, (t*1000)/N) local sum=0 t = gv.gethitickms() for i=1,N do sum = sum+gv.ksqrt(i) end t = gv.gethitickms()-t -- x86_64: 14ns/call printf("%d ksqrt() calls took %.03f ms (%.03f us/call) [sum=%f]", N, t, (t*1000)/N, sum) sum=0 t = gv.gethitickms() for i=1,N do sum = sum+math.sqrt(i) end t = gv.gethitickms()-t -- x86_64: 7ns/call printf("%d math.sqrt() calls took %.03f ms (%.03f us/call) [sum=%f]", N, t, (t*1000)/N, sum) 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 ) local stat = require("stat") local hs = stat.new() local con = require("con") local AC, MV = con.AC, con.MV con.action("TROOPSTAND",0,1,5,1,1) con.action("TROOPFLINTCH", 50, 1, 1, 1, 6) con.move("SHRUNKVELS", 32) con.ai("AITEMP", AC.TROOPFLINTCH, MV.SHRUNKVELS, 0) -- TODO: test -- This should work as well. In fact, it's exactly the same, but I prefer the -- above version for clarity. NOTE: we'll need to think whether it's OK to -- redefine composites (moves/actions/ais) during gameplay (probably not). -- Or will we allow only one definition per label ever? con.ai("AITEMP", "TROOPFLINTCH", "SHRUNKVELS", 0) local TROOPSTRENGTH = 30 gameactor(1680, TROOPSTRENGTH, "TROOPSTAND", -- LIZTROOP function(i, playeri, dist) sprite[i].pal = math.random(32) -- sprite[i].ang = bit.band(sprite[i].ang-20, 2047) local spr = sprite[i] local t = gv.gethitickms() local hit = hitscan(spr, spr.sectnum, 10, 10, 0, gv.CLIPMASK0) hs:add(1000*(gv.gethitickms()-t)) if (hs.n == 300) then printf("hitscan: %s", hs:getstatstr()) hs:reset() error("greetings from LIZTROOP actor") end if (dist < 4096) then -- Duke Vader / Anakin Nukewalker? actor[i]:set_action("TROOPFLINTCH") actor[i]:set_move("SHRUNKVELS") if (dist < 1024) then con.killit() end end end ) printf("EVENT_INIT = %d", gv.EVENT_INIT) -- tests default defines local bittest = require "bittest" bittest.sieve() require("test/test_geom") require("test/test_rotspr") print('---=== END TEST SCRIPT ===---') function check_sector_idx() error("bla") end spritesofsect(0) --DBG_.oom() -- This will complain about wrong usage of 'error'. In particular, -- the nil must not propagate to C! error(nil)